---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
-- Divider
|
-- Divider
|
--
|
--
|
-- Part of the LXP32 CPU
|
-- Part of the LXP32 CPU
|
--
|
--
|
-- Copyright (c) 2016 by Alex I. Kuznetsov
|
-- Copyright (c) 2016 by Alex I. Kuznetsov
|
--
|
--
|
-- Based on the NRD (Non Restoring Division) algorithm. Takes
|
-- Based on the NRD (Non Restoring Division) algorithm. Takes
|
-- 36 cycles to calculate quotient (37 for remainder).
|
-- 36 cycles to calculate quotient (37 for remainder).
|
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.numeric_std.all;
|
use ieee.numeric_std.all;
|
|
|
entity lxp32_divider is
|
entity lxp32_divider is
|
port(
|
port(
|
clk_i: in std_logic;
|
clk_i: in std_logic;
|
rst_i: in std_logic;
|
rst_i: in std_logic;
|
ce_i: in std_logic;
|
ce_i: in std_logic;
|
op1_i: in std_logic_vector(31 downto 0);
|
op1_i: in std_logic_vector(31 downto 0);
|
op2_i: in std_logic_vector(31 downto 0);
|
op2_i: in std_logic_vector(31 downto 0);
|
signed_i: in std_logic;
|
signed_i: in std_logic;
|
rem_i: in std_logic;
|
rem_i: in std_logic;
|
ce_o: out std_logic;
|
ce_o: out std_logic;
|
result_o: out std_logic_vector(31 downto 0)
|
result_o: out std_logic_vector(31 downto 0)
|
);
|
);
|
end entity;
|
end entity;
|
|
|
architecture rtl of lxp32_divider is
|
architecture rtl of lxp32_divider is
|
|
|
-- Complementor signals
|
-- Complementor signals
|
|
|
signal compl_inv: std_logic;
|
signal compl_inv: std_logic;
|
signal compl_mux: std_logic_vector(31 downto 0);
|
signal compl_mux: std_logic_vector(31 downto 0);
|
signal compl_out: std_logic_vector(31 downto 0);
|
signal compl_out: std_logic_vector(31 downto 0);
|
|
|
signal inv_res: std_logic;
|
signal inv_res: std_logic;
|
|
|
-- Divider FSM signals
|
-- Divider FSM signals
|
|
|
signal fsm_ce: std_logic:='0';
|
signal fsm_ce: std_logic:='0';
|
|
|
signal dividend: unsigned(31 downto 0);
|
signal dividend: unsigned(31 downto 0);
|
signal divisor: unsigned(32 downto 0);
|
signal divisor: unsigned(32 downto 0);
|
signal want_remainder: std_logic;
|
signal want_remainder: std_logic;
|
|
|
signal partial_remainder: unsigned(32 downto 0);
|
signal partial_remainder: unsigned(32 downto 0);
|
signal addend: unsigned(32 downto 0);
|
signal addend: unsigned(32 downto 0);
|
signal sum: unsigned(32 downto 0);
|
signal sum: unsigned(32 downto 0);
|
signal sum_positive: std_logic;
|
signal sum_positive: std_logic;
|
signal sum_subtract: std_logic;
|
signal sum_subtract: std_logic;
|
|
|
signal cnt: integer range 0 to 34:=0;
|
signal cnt: integer range 0 to 34:=0;
|
|
|
signal ceo: std_logic:='0';
|
signal ceo: std_logic:='0';
|
|
|
-- Output restoration signals
|
-- Output restoration signals
|
|
|
signal remainder_corrector: unsigned(31 downto 0);
|
signal remainder_corrector: unsigned(31 downto 0);
|
signal remainder_corrector_1: std_logic;
|
signal remainder_corrector_1: std_logic;
|
signal remainder_pos: unsigned(31 downto 0);
|
signal remainder_pos: unsigned(31 downto 0);
|
signal result_pos: unsigned(31 downto 0);
|
signal result_pos: unsigned(31 downto 0);
|
|
|
begin
|
begin
|
|
|
compl_inv<=op1_i(31) and signed_i when ce_i='1' else inv_res;
|
compl_inv<=op1_i(31) and signed_i when ce_i='1' else inv_res;
|
compl_mux<=op1_i when ce_i='1' else std_logic_vector(result_pos);
|
compl_mux<=op1_i when ce_i='1' else std_logic_vector(result_pos);
|
|
|
compl_op1_inst: entity work.lxp32_compl(rtl)
|
compl_op1_inst: entity work.lxp32_compl(rtl)
|
port map(
|
port map(
|
clk_i=>clk_i,
|
clk_i=>clk_i,
|
compl_i=>compl_inv,
|
compl_i=>compl_inv,
|
d_i=>compl_mux,
|
d_i=>compl_mux,
|
d_o=>compl_out
|
d_o=>compl_out
|
);
|
);
|
|
|
process (clk_i) is
|
process (clk_i) is
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if rst_i='1' then
|
if rst_i='1' then
|
fsm_ce<='0';
|
fsm_ce<='0';
|
want_remainder<='-';
|
want_remainder<='-';
|
inv_res<='-';
|
inv_res<='-';
|
else
|
else
|
fsm_ce<=ce_i;
|
fsm_ce<=ce_i;
|
if ce_i='1' then
|
if ce_i='1' then
|
want_remainder<=rem_i;
|
want_remainder<=rem_i;
|
if rem_i='1' then
|
if rem_i='1' then
|
inv_res<=op1_i(31) and signed_i;
|
inv_res<=op1_i(31) and signed_i;
|
else
|
else
|
inv_res<=(op1_i(31) xor op2_i(31)) and signed_i;
|
inv_res<=(op1_i(31) xor op2_i(31)) and signed_i;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Main adder/subtractor
|
-- Main adder/subtractor
|
|
|
addend_gen: for i in addend'range generate
|
addend_gen: for i in addend'range generate
|
addend(i)<=divisor(i) xor sum_subtract;
|
addend(i)<=divisor(i) xor sum_subtract;
|
end generate;
|
end generate;
|
|
|
sum<=partial_remainder+addend+(to_unsigned(0,32)&sum_subtract);
|
sum<=partial_remainder+addend+(to_unsigned(0,32)&sum_subtract);
|
sum_positive<=not sum(32);
|
sum_positive<=not sum(32);
|
|
|
-- Divider state machine
|
-- Divider state machine
|
|
|
process (clk_i) is
|
process (clk_i) is
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if rst_i='1' then
|
if rst_i='1' then
|
cnt<=0;
|
cnt<=0;
|
ceo<='0';
|
ceo<='0';
|
divisor<=(others=>'-');
|
divisor<=(others=>'-');
|
dividend<=(others=>'-');
|
dividend<=(others=>'-');
|
partial_remainder<=(others=>'-');
|
partial_remainder<=(others=>'-');
|
sum_subtract<='-';
|
sum_subtract<='-';
|
else
|
else
|
if cnt=1 then
|
if cnt=1 then
|
ceo<='1';
|
ceo<='1';
|
else
|
else
|
ceo<='0';
|
ceo<='0';
|
end if;
|
end if;
|
|
|
if ce_i='1' then
|
if ce_i='1' then
|
divisor(31 downto 0)<=unsigned(op2_i);
|
divisor(31 downto 0)<=unsigned(op2_i);
|
divisor(32)<=op2_i(31) and signed_i;
|
divisor(32)<=op2_i(31) and signed_i;
|
end if;
|
end if;
|
|
|
if fsm_ce='1' then
|
if fsm_ce='1' then
|
dividend<=unsigned(compl_out(30 downto 0)&"0");
|
dividend<=unsigned(compl_out(30 downto 0)&"0");
|
partial_remainder<=to_unsigned(0,32)&compl_out(31);
|
partial_remainder<=to_unsigned(0,32)&compl_out(31);
|
sum_subtract<=not divisor(32);
|
sum_subtract<=not divisor(32);
|
if want_remainder='1' then
|
if want_remainder='1' then
|
cnt<=34;
|
cnt<=34;
|
else
|
else
|
cnt<=33;
|
cnt<=33;
|
end if;
|
end if;
|
else
|
else
|
partial_remainder<=sum(31 downto 0)÷nd(31);
|
partial_remainder<=sum(31 downto 0)÷nd(31);
|
sum_subtract<=sum_positive xor divisor(32);
|
sum_subtract<=sum_positive xor divisor(32);
|
dividend<=dividend(30 downto 0)&sum_positive;
|
dividend<=dividend(30 downto 0)&sum_positive;
|
if cnt>0 then
|
if cnt>0 then
|
cnt<=cnt-1;
|
cnt<=cnt-1;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
-- Output restoration circuit
|
-- Output restoration circuit
|
|
|
process (clk_i) is
|
process (clk_i) is
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
for i in remainder_corrector'range loop
|
for i in remainder_corrector'range loop
|
remainder_corrector(i)<=(divisor(i) xor divisor(32)) and not sum_positive;
|
remainder_corrector(i)<=(divisor(i) xor divisor(32)) and not sum_positive;
|
end loop;
|
end loop;
|
remainder_corrector_1<=divisor(32) and not sum_positive;
|
remainder_corrector_1<=divisor(32) and not sum_positive;
|
remainder_pos<=partial_remainder(32 downto 1)+remainder_corrector+
|
remainder_pos<=partial_remainder(32 downto 1)+remainder_corrector+
|
(to_unsigned(0,31)&remainder_corrector_1);
|
(to_unsigned(0,31)&remainder_corrector_1);
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
result_pos<=remainder_pos when want_remainder='1' else dividend;
|
result_pos<=remainder_pos when want_remainder='1' else dividend;
|
|
|
result_o<=compl_out;
|
result_o<=compl_out;
|
ce_o<=ceo;
|
ce_o<=ceo;
|
|
|
end architecture;
|
end architecture;
|
|
|