-- ############################################################################ -- # Project : VHDL-Modellbibliothek # -- # # -- # Filename : array_divider_multiplier.vhd # -- # # -- # Schaltung : Modul zur Multiplikation/Division zweier Binaer- # -- # zahlen in 2'er Komplementdarstellung # -- # # -- # Modell : array_divider_multiplier # -- # # -- # Designer : Wolfgang Sehr; ueberarbeitet von Stefan Schmechtig # -- # Abteilung : Lehrstul fuer rechnergestuetzten Schaltungsentwurf # -- # Datum : 23.01.1995 # -- ############################################################################ -- ############################################################################ -- # IEEE PACKAGES # -- ############################################################################ Library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; -- ############################################################################ ENTITY array_divider_multiplier IS GENERIC(X :INTEGER := @BITBR); -- X := Operandenbreite -- symmetrisches Array X * X PORT(mode : IN STD_LOGIC; op_1 : IN UNSIGNED ((X-1) DOWNTO 0); op_2 : IN UNSIGNED ((X-1) DOWNTO 0); erg_1 : OUT UNSIGNED ((X-1) DOWNTO 0); erg_2 : OUT UNSIGNED ((X-1) DOWNTO 0)); -- mode : Moduswahl, in dem sich das Modul befindet: -- o mode = 1 -> Division -- o mode = 0 -> Multiplikation -- -- op_1 : Eingangsport fuer 1. Operanden -- o bei der Division: Dividend -- o bei der Multiplikation: Multiplikant -- -- op_2 : Eingangsport fuer 2. Operanden -- o bei der Division: Divisor -- o bei der Multiplikation Multiplikator -- -- -- erg_1 : Ausgangsport fuer 1. Teil des Ergebnisses -- o bei der Division: Quotient -- o bei der Muliplikation: hoeherwertiger Teil -- des Produktes -- -- erg_2 : Ausgangsport fuer 2. Teil des Ergebnisses -- o bei der Division: Rest -- o bei der Muliplikation: niederwertiger Teil -- des Produktes -- -- -> Darstellung im 2'er Komplement END array_divider_multiplier; ARCHITECTURE verhalten OF array_divider_multiplier IS SIGNAL op_1_sgn : SIGNED((X-1) DOWNTO 0); SIGNAL op_2_sgn : SIGNED((X-1) DOWNTO 0); BEGIN op_1_sgn <= CONV_SIGNED(op_1, op_1_sgn'LENGTH); op_2_sgn <= CONV_SIGNED(op_2, op_2_sgn'LENGTH); PROCESS(op_1_sgn, op_2_sgn, mode) CONSTANT eins : STD_LOGIC := '1'; VARIABLE ztld : SIGNED ((2*X-2) DOWNTO 0); VARIABLE tlr : SIGNED ((X-1) DOWNTO 0); VARIABLE k_ztld : UNSIGNED ((ztld'LENGTH-1) DOWNTO 0); VARIABLE k_tlr : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE vz : UNSIGNED ( 1 DOWNTO 0); VARIABLE a : UNSIGNED ((ztld'LENGTH-1) DOWNTO 0); VARIABLE a_ein : UNSIGNED ((ztld'LENGTH-1) DOWNTO 0); VARIABLE b : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE k_b : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE q : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE k_q : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE r : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE k_r : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE sum : UNSIGNED ( tlr'LENGTH DOWNTO 0); VARIABLE n_divisable : UNSIGNED ((tlr'LENGTH-1) DOWNTO 0); VARIABLE n_div_detect : STD_LOGIC; VARIABLE b_add : UNSIGNED ((tlr'LENGTH) DOWNTO 0); VARIABLE zwischenerg_2 : UNSIGNED ((X*X-1) DOWNTO 0); VARIABLE p : UNSIGNED (2*X-1 DOWNTO 0); VARIABLE k_p : UNSIGNED ((ztld'LENGTH) DOWNTO 0); VARIABLE a_add : UNSIGNED (X DOWNTO 0); VARIABLE mknt : UNSIGNED ((X-1) DOWNTO 0); VARIABLE mktr : UNSIGNED ((X-1) DOWNTO 0); -- ztld : enthaelt den Dividenden, aufbereitet -- : fuer den Divisionsalgorithmus -- -- tlr : enthaelt den Divisor, aufbereitet -- : fuer den Divisionsalgorithmus -- -- k_ztld : komplementierter Dividend aufbereitet fuer den -- : Divisionsalgorithmus -- -- k_tlr : komplementierter Divisor -- -- vz : 0 -> positives Vorzeichen -- : 1 -> negatives Vorzeichen -- : vz(1) Vorzeichen des Dividenden -- : vz(0) Vorzeichen des Divisors -- -- a : Variable fuer den aktuellen Dividenden -- : waehrend der Ausfuehrumg des -- : Divisionsalgorithmus -- -- a_ein : Variable fuer den Dividenden, der anfangs in -- : Divisionsalgorithmus uebernommen wird -- -- b : Variable fuer den Divisor (immer positiv) -- -- k_b : komplmentierter Divisor (immer negativ) -- -- q : Variable fuer den Quotienten -- -- k_q : komplementierter Quotient -- -- r : ganzzahliger Rest der Division -- -- k_r : komplementierter ganzzahliger Rest der -- Division -- -- sum : Ergebnis der Addition/Subtraktion in de -- einzelnen Stufen -- -- n_divisable : ist in der Stufe i Null, ab der der Dividend -- nicht mehr weiter durch den Divisor teilbar -- ist -- -- n_div_detect : ist 1, wenn der Dividend vor der letzten Zeile -- nicht mehr durch den Divisor teilbar ist -- -- b_add : Zwischenspeichervariable fuer Addition -- -- zwischenerg_2 : Stellt den aktuellen Zwischenerg_2 dar, der -- : sich aus dem Ergebnis der Addition/Subtraktion -- : und den noch nicht behandelten Stellen des -- : Dividenden zusammensetzt. -- -- p : erhaelt den Wert des Produktes im Falle -- : einer Multiplikation -- -- k_p : 2'er Komplement des Produktes -- -- a_add : ein Summand fuer den Addierer -- -- mknt : Multiplikant -- -- mktr : Multiplikator -- BEGIN -- #################################################################### -- Eingangssignale bzw. komplementierte Eingangssignale werden den -- internen Variablen des PROCESS zugewiesen -- #################################################################### ztld := CONV_SIGNED(op_1_sgn, ztld'LENGTH); tlr := CONV_SIGNED(op_2_sgn, tlr'LENGTH); FOR i IN 0 TO (ztld'LENGTH-1) LOOP k_ztld(i) := NOT(ztld(i)); END LOOP; k_ztld := k_ztld + eins; FOR i IN 0 TO (tlr'LENGTH-1) LOOP k_tlr(i) := NOT(tlr(i)); END LOOP; k_tlr := k_tlr + eins; IF (op_1_sgn(op_1_sgn'LENGTH-1) = '1') THEN vz(1) := '1'; ELSE vz(1) := '0'; END IF; IF (op_2_sgn(op_2_sgn'LENGTH-1) = '1') THEN vz(0) := '1'; ELSE vz(0) := '0'; END IF; CASE vz IS WHEN "00" => a := CONV_UNSIGNED(ztld,a'LENGTH); a_ein := CONV_UNSIGNED(ztld,a'LENGTH); b := CONV_UNSIGNED(tlr, b'LENGTH); mknt := CONV_UNSIGNED(op_1_sgn, mknt'LENGTH); mktr := CONV_UNSIGNED(op_2_sgn, mktr'LENGTH); WHEN "01" => a := CONV_UNSIGNED(ztld, a'LENGTH); a_ein := CONV_UNSIGNED(ztld, a'LENGTH); b := CONV_UNSIGNED(k_tlr, b'LENGTH); mknt := CONV_UNSIGNED(op_1_sgn, mknt'LENGTH); mktr := CONV_UNSIGNED(k_tlr, mktr'LENGTH); WHEN "10" => a := CONV_UNSIGNED(k_ztld,a'LENGTH); a_ein := CONV_UNSIGNED(k_ztld,a'LENGTH); b := CONV_UNSIGNED(tlr, b'LENGTH); mknt := CONV_UNSIGNED(k_ztld((X-1) DOWNTO 0), mknt'LENGTH); mktr := CONV_UNSIGNED(op_2_sgn, mktr'LENGTH); WHEN "11" => a := CONV_UNSIGNED(k_ztld,a'LENGTH); a_ein := CONV_UNSIGNED(k_ztld,a'LENGTH); b := CONV_UNSIGNED(k_tlr, b'LENGTH); mknt := CONV_UNSIGNED(k_ztld((X-1) DOWNTO 0), mknt'LENGTH); mktr := CONV_UNSIGNED(k_tlr, mktr'LENGTH); WHEN OTHERS => a := CONV_UNSIGNED(0, a'LENGTH); a_ein := CONV_UNSIGNED(0, a'LENGTH); b := CONV_UNSIGNED(0, b'LENGTH); mknt := CONV_UNSIGNED(0, mknt'LENGTH); mktr := CONV_UNSIGNED(0, mktr'LENGTH); END CASE; -- #################################################################### -- #################################################################### -- Divisionsalgorithmus/Multiplikationsalgorithmus -- #################################################################### IF (mode = '1') THEN sum(tlr'LENGTH) := '1'; ELSE sum := CONV_UNSIGNED(0, X+1); p := CONV_UNSIGNED(0, p'LENGTH); END IF; zwischenerg_2 := CONV_UNSIGNED(0, zwischenerg_2'LENGTH); FOR n IN 0 TO (tlr'LENGTH-1) LOOP k_b(n) := NOT(b(n)); END LOOP; k_b := k_b + eins; FOR i IN 0 TO (tlr'LENGTH-1) LOOP -------------------------------------------------------------------- -- Addition oder Subtraktion des Divisors in Abhaengigkeit des -- Uebertrags der zuvor erfolgten Rechenoperation -------------------------------------------------------------------- b_add := CONV_UNSIGNED(0, b_add'LENGTH); -- Vermeidung von Latches IF (mode = '1') THEN -- Division IF sum(tlr'LENGTH) = '1' THEN b_add := CONV_UNSIGNED(k_b, tlr'LENGTH+1); ELSIF sum(tlr'LENGTH) ='0' THEN b_add := CONV_UNSIGNED(b, tlr'LENGTH+1); END IF; a_add := CONV_UNSIGNED(a(ztld'LENGTH-1-i DOWNTO ztld'LENGTH-tlr'LENGTH-i), tlr'LENGTH+1); ELSE -- Multiplikation b_add := CONV_UNSIGNED(0, b_add'LENGTH); FOR k IN 0 TO (X-1) LOOP b_add(k) := mknt(k) AND mktr(i); END LOOP; a_add := CONV_UNSIGNED(sum(X DOWNTO 1), a_add'LENGTH); END IF; sum := a_add + b_add; ------------------------------------------------------------------- ------------------------------------------------------------------- -- sichern des Zwischenergebnisses mit angehaengtem Dividendenerg_2 ------------------------------------------------------------------- FOR k IN 0 TO (X-1-1-i) LOOP zwischenerg_2(i*X+k) := a_ein(k); END LOOP; FOR l IN 0 TO i LOOP zwischenerg_2(i*X+(X-1-i+l)) := sum(l); END LOOP; ------------------------------------------------------------------- ------------------------------------------------------------------- -- Umlagern der Zwischenergebnisse und Ablagern der endgueltigen -- Ergebnisse ------------------------------------------------------------------- -- fuer Divisionsalgorithmus FOR m IN 1 TO (tlr'LENGTH-1) LOOP a(ztld'LENGTH-m-1-i) := sum(tlr'LENGTH-m-1); END LOOP; q(tlr'LENGTH-1-i) := sum(tlr'LENGTH); -- Uebertrag bei der Addition stellt -- Quotientenstelle dar -- fuer Multiplikationsalgorithmus p(i) := sum(0); ------------------------------------------------------------------- END LOOP; FOR i IN X TO (2*X-1) LOOP p(i) := sum(i-X+1); END LOOP; -- #################################################################### -- Restkorrektur -- #################################################################### r := CONV_UNSIGNED('0', tlr'LENGTH); n_div_detect := '0'; -- -------------------------------------------------------------------- -- Ueberpruefung der Teilbarkeit -- -------------------------------------------------------------------- FOR i IN 0 TO (tlr'LENGTH-1) LOOP IF (i < tlr'LENGTH-1) THEN IF (q(tlr'LENGTH-1-i) = '1') THEN n_divisable(i) := '0'; FOR l IN i+1 TO (tlr'LENGTH-1) LOOP n_divisable(i) := n_divisable(i) OR (q(tlr'LENGTH-1-l)); END LOOP; ELSE n_divisable(i) := '1'; END IF; END IF; END LOOP; -- -------------------------------------------------------------------- -- Zuweisung des entsprechenden Restes -- -------------------------------------------------------------------- IF (q = CONV_UNSIGNED(0, tlr'LENGTH)) THEN r := CONV_UNSIGNED(a_ein((tlr'LENGTH-1) DOWNTO 0), tlr'LENGTH); ELSE FOR i IN 1 TO (tlr'LENGTH-1) LOOP IF (i < tlr'LENGTH-1) THEN IF (n_divisable(i) = '0') THEN r := CONV_UNSIGNED(zwischenerg_2(i*X+X-1 DOWNTO i*X), tlr'LENGTH); n_div_detect := '1'; END IF; ELSE IF (n_div_detect = '0') THEN r := CONV_UNSIGNED(zwischenerg_2(i*X+X-1 DOWNTO i*X), tlr'LENGTH); END IF; END IF; END LOOP; END IF; -- #################################################################### -- #################################################################### -- interne Variablen werden Ausgangssignalen zugewiesen -- #################################################################### FOR i IN 0 TO (q'LENGTH-1) LOOP k_q(i) := NOT(q(i)); END LOOP; k_q := k_q + CONV_UNSIGNED(1, q'LENGTH); FOR i IN 0 TO (r'LENGTH-1) LOOP k_r(i) := NOT(r(i)); END LOOP; k_r := k_r + eins; FOR i IN 0 TO (p'LENGTH-1) LOOP k_p(i) := NOT(p(i)); END LOOP; k_p := k_p + eins; IF (mode = '1') THEN CASE vz IS WHEN "00" => erg_1 <= q; erg_2 <= r; WHEN "01" => erg_1 <= k_q; erg_2 <= r; WHEN "10" => erg_1 <= k_q; erg_2 <= k_r; WHEN "11" => erg_1 <= q; erg_2 <= k_r; WHEN OTHERS => erg_1 <= CONV_UNSIGNED(0, erg_1'LENGTH); erg_2 <= CONV_UNSIGNED(0, erg_2'LENGTH); END CASE; ELSE CASE vz IS WHEN "00" => erg_2 <= CONV_UNSIGNED(p(erg_1'LENGTH-1 DOWNTO 0), erg_1'LENGTH); erg_1 <= CONV_UNSIGNED(p(2*X-1 DOWNTO X), erg_2'LENGTH); WHEN "01" => erg_2 <= CONV_UNSIGNED(k_p(erg_1'LENGTH-1 DOWNTO 0), erg_1'LENGTH); erg_1 <= CONV_UNSIGNED(k_p(2*X-1 DOWNTO X), erg_2'LENGTH); WHEN "10" => erg_2 <= CONV_UNSIGNED(k_p(erg_1'LENGTH-1 DOWNTO 0), erg_1'LENGTH); erg_1 <= CONV_UNSIGNED(k_p(2*X-1 DOWNTO X), erg_2'LENGTH); WHEN "11" => erg_2 <= CONV_UNSIGNED(p(erg_1'LENGTH-1 DOWNTO 0), erg_1'LENGTH); erg_1 <= CONV_UNSIGNED(p(2*X-1 DOWNTO X), erg_2'LENGTH); WHEN OTHERS => erg_2 <= CONV_UNSIGNED(0, erg_1'LENGTH); erg_1 <= CONV_UNSIGNED(0, erg_2'LENGTH); END CASE; END IF; -- #################################################################### END PROCESS; END verhalten; CONFIGURATION CFG_array_divider_multiplier OF array_divider_multiplier IS FOR verhalten END FOR; END CFG_array_divider_multiplier;