---------------------------------------------------------------------------- -- Plus minus algorithm for modular divison (plus_minus.vhd) -- ---------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; package plus_minus_Parameters is -- constant K: natural := 256; -- constant P: std_logic_vector(K downto 0) := (256 => '0', 223 downto 193 => '0',191 downto 96 => '0',others =>'1'); -- constant K: natural := 192; -- constant P: std_logic_vector(K downto 0) := '0' & x"fffffffffffffffffffffffffffffffeffffffffffffffff"; -- constant LOGK: natural := 9; constant K: natural := 8; constant P: std_logic_vector(K downto 0) := conv_std_logic_vector(239, K+1); -----LOGK+1 bits for representing integers between -k and k constant LOGK: natural := 4; constant MINUS_P: std_logic_vector(K+1 downto 0) := ('1' & not P) + '1'; constant TWO_P: std_logic_vector(K+1 downto 0) := P & '0'; constant ZERO: std_logic_vector(K downto 0) := (others => '0'); constant SHORT_ZERO: std_logic_vector(LOGK-1 downto 0) := (others => '0'); constant MINUS_ONE: std_logic_vector(LOGK downto 0) := conv_std_logic_vector(-1, LOGK+1); constant MINUS_TWO: std_logic_vector(LOGK downto 0) := conv_std_logic_vector(-2, LOGK+1); --if p mod 4 = 3: constant pp1: std_logic_vector (K+1 downto 0) := p(k)&p; constant pp3: std_logic_vector (K+1 downto 0) := MINUS_P; --if p mod 4 = 1: --constant pp1: std_logic_vector (K+1 downto 0) := MINUS_P; --constant pp3: std_logic_vector (K+1 downto 0) := p(k)&p; end plus_minus_Parameters; ---------------------------------------------------------------------------- -- plus_minus ---------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.plus_minus_Parameters.all; entity plus_minus is port( x, y: in std_logic_vector(K-1 downto 0); clk, reset, start: in std_logic; z: out std_logic_vector(K-1 downto 0); done: out std_logic ); end plus_minus; architecture rtl of plus_minus is signal a, b, c, d, next_a, next_b, next_c, next_d, half_a, half_b, sum_ab, half_sum_ab, aa, cc, dd: std_logic_vector(K downto 0); signal sum_cd, pp: std_logic_vector(K+1 downto 0); signal corrected_sum: std_logic_vector(K+2 downto 0); signal oper, sel_bd, sel_correction, sel_dif, sel_min, s: std_logic_vector(1 downto 0); signal sel_ac, lastb, firstb, oper_dif, ce_ac, ce_bd, b_4, b_2, b_plus_a, dif_neg, dif_zero, dif_neg_zero, dif_one, cond, min_zero, min_zero_neg: std_logic; signal dif, min, next_dif, next_min, d1, d2, m1, m2: std_logic_vector(LOGK downto 0); type states is range 0 to 4; signal current_state: states; begin half_b <= b(K)& b(K downto 1); half_a <= a(K)& a(K downto 1); gates1: for i in 0 to K generate aa(i) <= (oper(1) and (oper(0) xor half_a(i))); end generate; sum_ab <= half_b + aa + oper(1); half_sum_ab <= sum_ab(K)& sum_ab(K downto 1); with sel_bd select next_b <= '0' & y when "00", sum_ab when "01", half_sum_ab when others; gates2: for i in 0 to k generate dd(i) <= lastb and d(i); cc(i) <= (oper(1) and (oper(0) xor c(i))); end generate; sum_cd <= (dd(k)&dd) + (cc(k)&cc) + oper(0); with sel_correction select pp <= '0' & ZERO when "00", pp1 when "01", TWO_P when "10", pp3 when others; corrected_sum <= (sum_cd(K+1) & sum_cd) + (pp(K+1) & pp); z <= corrected_sum(K-1 downto 0); with sel_bd select next_d <= '0'&x when "00", corrected_sum(K+1 downto 1) when "01", corrected_sum(K+2 downto 2) when others; with sel_ac select next_a <= p when '0', b when others; with sel_ac select next_c <= ZERO when '0', d when others; with sel_dif select d1 <= '0' & SHORT_ZERO when "00", MINUS_ONE when "01", MINUS_TWO when others; gates3: for i in 0 to LOGK generate d2(i) <= firstb and dif(i); end generate; with oper_dif select next_dif <= d1 + d2 when '0', d1 - d2 when others; with sel_min select m1 <= '0' & SHORT_ZERO when "00", MINUS_ONE when "01", MINUS_TWO when others; m2 <= m1 + min; with firstb select next_min <= conv_std_logic_vector(K, LOGK+1) when '0', m2 when others; registers_ac: process(clk) begin if clk'event and clk = '1' then if ce_ac = '1' then a <= next_a; c <= next_c; end if; end if; end process registers_ac; registers_bd: process(clk) begin if clk'event and clk = '1' then if ce_bd = '1' then b <= next_b; d <= next_d; end if; end if; end process registers_bd; registers_md: process(clk) begin if clk'event and clk = '1' then min <= next_min; dif <= next_dif; end if; end process registers_md; --flag generation b_4 <= b(1) or b(0); b_2 <= b(0); s <= a(1 downto 0) + b(1 downto 0); b_plus_a <= s(1) or s(0); dif_neg <= dif(LOGK); cond <= '1' when dif(LOGK downto 1) = SHORT_ZERO else '0'; dif_zero <= cond and not(dif(0)); dif_one <= cond and dif(0); dif_neg_zero <= dif_neg or dif_zero; min_zero <= '1' when min = '0' & SHORT_ZERO else '0'; min_zero_neg <= min_zero or min(LOGK); control_unit: process(clk, reset, current_state, a, b, c, d, min, dif, oper, lastb, sum_cd) begin case current_state is when 0 to 1 => oper <= '1'&a(k); sel_bd <= "00"; sel_correction <= '0'&(a(k) xor c(k)); sel_dif <= "00"; sel_min <= "00"; sel_ac <= '0'; lastb <= '0'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '0'; done <= '1'; when 2 => oper <= "00"; sel_bd <= "00"; sel_correction <= "00"; sel_dif <= "00"; sel_min <= "00"; sel_ac <= '0'; lastb <= '1'; firstb <= '0'; oper_dif <= '0'; ce_ac <= '1'; ce_bd <= '1'; done <= '0'; when 3 => if (min_zero_neg ='1') then oper <= '1'&a(k); sel_bd <= "00"; sel_correction <= '0'&(a(k) xor c(k)); sel_dif <= "00"; sel_min <= "00"; sel_ac <= '0'; lastb <= '0'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '0'; done <= '0'; elsif (b_4 = '0') then if (dif_neg_zero = '1') then oper <= "00"; sel_bd <= "10"; sel_correction <= d(1 downto 0); sel_dif <= "10"; sel_min <= "10"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; elsif (dif_one = '1') then oper <= "00"; sel_bd <= "10"; sel_correction <= d(1 downto 0); sel_dif <= "10"; sel_min <= "01"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; else oper <= "00"; sel_bd <= "10"; sel_correction <= d(1 downto 0); sel_dif <= "10"; sel_min <= "00"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; end if; elsif (b_2 = '0') then if (dif_neg_zero = '1') then oper <= "00"; sel_bd <= "01"; sel_correction <= '0'&d(0); sel_dif <= "01"; sel_min <= "01"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; else oper <= "00"; sel_bd <= "01"; sel_correction <= '0'&d(0); sel_dif <= "01"; sel_min <= "00"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; end if; elsif (b_plus_a = '0') then if (dif_neg = '1') then oper <= "10"; sel_bd <= "10"; sel_correction <= sum_cd(1 downto 0); sel_dif <= "01"; sel_min <= "00"; sel_ac <= '1'; lastb <= '1'; firstb <= '1'; oper_dif <= '1'; ce_ac <= '1'; ce_bd <= '1'; done <= '0'; elsif (dif_zero = '1') then oper <= "10"; sel_bd <= "10"; sel_correction <= sum_cd(1 downto 0); sel_dif <= "01"; sel_min <= "01"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; else oper <= "10"; sel_bd <= "10"; sel_correction <= sum_cd(1 downto 0); sel_dif <= "01"; sel_min <= "00"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; end if; else if (dif_neg = '1') then oper <= "11"; sel_bd <= "10"; sel_correction <= sum_cd(1 downto 0); sel_dif <= "01"; sel_min <= "00"; sel_ac <= '1'; lastb <= '1'; firstb <= '1'; oper_dif <= '1'; ce_ac <= '1'; ce_bd <= '1'; done <= '0'; elsif (dif_zero = '1') then oper <= "11"; sel_bd <= "10"; sel_correction <= sum_cd(1 downto 0); sel_dif <= "01"; sel_min <= "01"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; else oper <= "11"; sel_bd <= "10"; sel_correction <= sum_cd(1 downto 0); sel_dif <= "01"; sel_min <= "00"; sel_ac <= '0'; lastb <= '1'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '1'; done <= '0'; end if; end if; when 4 => oper <= '1'&a(k); sel_bd <= "00"; sel_correction <= '0'&(a(k) xor c(k)); sel_dif <= "00"; sel_min <= "00"; sel_ac <= '0'; lastb <= '0'; firstb <= '1'; oper_dif <= '0'; ce_ac <= '0'; ce_bd <= '0'; done <= '0'; end case; if reset = '1' then current_state <= 0; elsif clk'event and clk = '1' then case current_state is when 0 => if start = '0' then current_state <= 1; end if; when 1 => if start = '1' then current_state <= 2; end if; when 2 => current_state <= 3; when 3 => if (min_zero_neg) ='1'then current_state <= 4; end if; when 4 => current_state <= 0; end case; end if; end process; end rtl;