-- ############################################################################ -- # Project : VHDL-Modellbibliothek # -- # # -- # Filename : array_divider.vhd # -- # # -- # Schaltung : Array-Dividierer # -- # # -- # Modell : array_divider # -- # # -- # Designer : Wolfgang Sehr # -- # Abteilung : Lehrstuhl fuer Rechnergestuetzten Schaltungsentwurf # -- # Datum : 20.01.1995 # -- ############################################################################ -- ############################################################################ -- # IEEE PACKAGES # -- ############################################################################ Library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; -- ############################################################################ ENTITY array_divider IS GENERIC(X :INTEGER := @BITBR); -- X := Operandenbreite -- symmetrisches Array X * X PORT(dvd : IN UNSIGNED ((X-1) DOWNTO 0); dvs : IN UNSIGNED ((X-1) DOWNTO 0); quot : OUT UNSIGNED ((X-1) DOWNTO 0); rest : OUT UNSIGNED ((X-1) DOWNTO 0)); -- dvd : Eingangsport fuer Dividenden -- -- dvs : Eingangsport fuer Divisor -- -- quot : Ausgangsport fuer Quotienten -- -- rest : Ausgangsport fuer Rest -- -- -> Darstellung im 2'er Komplement END array_divider; ARCHITECTURE verhalten OF array_divider IS BEGIN PROCESS(dvd, dvs) CONSTANT eins : STD_LOGIC := '1'; VARIABLE dvd_sgn : SIGNED ((X-1) DOWNTO 0); VARIABLE dvs_sgn : SIGNED ((X-1) DOWNTO 0); 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 zwischenrest : UNSIGNED ((X*X-1) DOWNTO 0); -- 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 Divisions- -- : algorithmus -- -- a_ein : Variable fuer den Dividenden, der anfangs in -- : Divisionsalgorithmus uebernommen wird -- -- b : Variable fuer den Divisor (immer positiv) -- -- k_b : komplemtierter 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 den -- : 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 -- -- zwischenrest : Stellt den aktuellen Zwischenrest dar, der -- : sich aus dem Ergebnis der Addition/Subtraktion -- : und den noch nicht behandelten Stellen des -- : Dividenden zusammensetzt. BEGIN -- #################################################################### -- Eingangssignale bzw. komplementierte Eingangssignale werden den -- internen Variablen des PROCESS zugewiesen -- #################################################################### dvd_sgn := CONV_SIGNED(dvd, dvd_sgn'LENGTH); dvs_sgn := CONV_SIGNED(dvs, dvs_sgn'LENGTH); ztld := CONV_SIGNED(dvd_sgn, ztld'LENGTH); tlr := CONV_SIGNED(dvs_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 (dvd(dvd'LENGTH-1) = '1') THEN vz(1) := '1'; ELSE vz(1) := '0'; END IF; IF (dvs(dvs'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); WHEN "01" => a := CONV_UNSIGNED(ztld, a'LENGTH); a_ein := CONV_UNSIGNED(ztld, a'LENGTH); b := CONV_UNSIGNED(k_tlr, b'LENGTH); WHEN "10" => a := CONV_UNSIGNED(k_ztld,a'LENGTH); a_ein := CONV_UNSIGNED(k_ztld,a'LENGTH); b := CONV_UNSIGNED(tlr, b'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); WHEN OTHERS => a := CONV_UNSIGNED(0, a'LENGTH); a_ein := CONV_UNSIGNED(0, a'LENGTH); b := CONV_UNSIGNED(0, b'LENGTH); END CASE; -- #################################################################### -- #################################################################### -- Divisionsalgorithmus -- #################################################################### sum(tlr'LENGTH) := '1'; zwischenrest := CONV_UNSIGNED(0, zwischenrest'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 -------------------------------------------------------------------- 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; sum := CONV_UNSIGNED(a(ztld'LENGTH-1-i DOWNTO ztld'LENGTH-tlr'LENGTH-i), tlr'LENGTH+1) + b_add; ------------------------------------------------------------------- ------------------------------------------------------------------- -- sichern des Zwischenrestes mit angehaengtem Dividendenrest ------------------------------------------------------------------- FOR k IN 0 TO (X-1-1-i) LOOP zwischenrest(i*X+k) := a_ein(k); END LOOP; FOR l IN 0 TO i LOOP zwischenrest(i*X+(X-1-i+l)) := sum(l); END LOOP; ------------------------------------------------------------------- ------------------------------------------------------------------- -- Umlagern der Ergebnisse ------------------------------------------------------------------- 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); -- XOR b(tlr'LENGTH-1); -- Uebertrag bei der Addition stellt -- Quotientenstelle dar ------------------------------------------------------------------- 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(zwischenrest(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(zwischenrest(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; CASE vz IS WHEN "00" => quot <= q; rest <= r; WHEN "01" => quot <= k_q; rest <= r; WHEN "10" => quot <= k_q; rest <= k_r; WHEN "11" => quot <= q; rest <= k_r; WHEN OTHERS => quot <= CONV_UNSIGNED(0, quot'LENGTH); rest <= CONV_UNSIGNED(0, rest'LENGTH); END CASE; -- #################################################################### END PROCESS; END verhalten; CONFIGURATION CFG_array_divider OF array_divider IS FOR verhalten END FOR; END CFG_array_divider;