Skip to content

Commit

Permalink
Add hardware division
Browse files Browse the repository at this point in the history
  • Loading branch information
miklz committed Mar 16, 2021
1 parent 81a1e3c commit 4f5857e
Show file tree
Hide file tree
Showing 32 changed files with 2,129 additions and 163,713 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

# Quartus files
**/db
**/incremental_db
**/output_files
**/simulation

# Machine Objects
*.o
*.elf
*.hex
*.map
*.tmp

# Personal user files
*.qws
*.qdf
80 changes: 69 additions & 11 deletions alu/m/M.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,93 @@ use work.M_types.all;

entity M is
port(
M_data : in M_data_t;
dataOut : out std_logic_vector(31 downto 0)
clk : in std_logic;
rst : in std_logic;
M_data : in M_data_t;
dataOut : out std_logic_vector(31 downto 0)
);
end entity;

architecture RTL of M is
-------------------------------------------------------------------
-------------------------------------------------------------------


signal mul_signed: Signed(63 downto 0);
signal mulu_unsigned: Unsigned(63 downto 0);

signal div_signed: Signed(31 downto 0);
signal divu_unsigned: Unsigned(31 downto 0);

signal rem_signed: Signed(31 downto 0);
signal remu_unsigned: Unsigned(31 downto 0);

signal remainder_sig : Signed(31 downto 0);
signal quotient_sig : Signed(31 downto 0);
signal remainder_unsig : Unsigned(31 downto 0);
signal quotient_unsig : Unsigned(31 downto 0);
signal divid_signed : Unsigned(31 downto 0);
signal divis_signed : Unsigned(31 downto 0);

begin
--===============================================================--

mul_signed <= M_data.a*M_data.b;
mulu_unsigned <= Unsigned(M_data.a)*Unsigned(M_data.b);

div_signed <= M_data.a/M_data.b;
divu_unsigned <= Unsigned(M_data.a)/Unsigned(M_data.b);

rem_signed <= M_data.a mod M_data.b;
remu_unsigned <= Unsigned(M_data.a) mod Unsigned(M_data.b);
quick_div_signed : entity work.quick_naive
port map (
clk => clk, rst => rst,
dividend => divid_signed, divisor => divis_signed, ready => open,
Signed(remainder) => remainder_sig, Signed(quotient) => quotient_sig
);

quick_div_unsigned : entity work.quick_naive
port map (
clk => clk, rst => rst,
dividend => Unsigned(M_data.a), divisor => Unsigned(M_data.b), ready => open,
remainder => remainder_unsig, quotient => quotient_unsig
);

process(M_data)
begin
divid_signed <= Unsigned(M_data.a);
divis_signed <= Unsigned(M_data.b);
if (M_data.b = x"00000000") then
div_signed <= (others => '1');
divu_unsigned <= (others => '1');
rem_signed <= M_data.a;
remu_unsigned <= Unsigned(M_data.a);
elsif ((M_data.a = x"80000000") and (M_data.b = x"FFFFFFFF")) then
div_signed <= M_data.a;
divu_unsigned <= quotient_unsig;
rem_signed <= (others => '0');
remu_unsigned <= remainder_unsig;
else
divu_unsigned <= quotient_unsig;
remu_unsigned <= remainder_unsig;
if ((M_data.a(M_data.a'left) = '1') and (M_data.b(M_data.b'left) = '1')) then
div_signed <= quotient_sig;
rem_signed <= (not remainder_sig) + 1;
divid_signed <= Unsigned((not M_data.a) + 1);
divis_signed <= Unsigned((not M_data.b) + 1);
elsif ((M_data.a(M_data.a'left) = '1') and (M_data.b(M_data.b'left) = '0')) then
div_signed <= (not quotient_sig) + 1;
rem_signed <= (not remainder_sig) + 1;
divid_signed <= Unsigned((not M_data.a) + 1);
divis_signed <= Unsigned(M_data.b);
elsif ((M_data.a(M_data.a'left) = '0') and (M_data.b(M_data.b'left) = '1')) then
div_signed <= (not quotient_sig) + 1;
rem_signed <= remainder_sig;
divid_signed <= Unsigned(M_data.a);
divis_signed <= Unsigned((not M_data.b) + 1);
else
div_signed <= quotient_sig;
rem_signed <= remainder_sig;
divid_signed <= Unsigned(M_data.a);
divis_signed <= Unsigned(M_data.b);
end if;
end if;
end process;

ula_op : with M_data.code select
dataOut <= Std_logic_vector(mul_signed(31 downto 0)) when M_MUL,
Expand All @@ -51,4 +109,4 @@ begin

(others => '0') when others;

end architecture;
end architecture;
91 changes: 91 additions & 0 deletions alu/m/division_functions.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;

package division_functions is
function clz (bits : in std_logic_vector) return integer;
function msb (bits : in std_logic_vector) return integer;
end package division_functions;

package body division_functions is

function clz (bits : in std_logic_vector) return integer is

variable sub_vector : std_logic_vector(7 downto 0);
type sub_2d is array (0 to 7) of std_logic_vector(1 downto 0);
variable vector_2d : sub_2d;
variable mux_2d : std_logic_vector(7 downto 0);
variable clz, expo : std_logic_vector(0 to 4);
begin

for index in 7 downto 0 loop
sub_vector(7-index) := not(bits(4*index+3) or bits(4*index+2) or bits(4*index+1) or bits(4*index));
vector_2d(7-index)(1) := not (bits(4*index+3) or bits(4*index+2));
vector_2d(7-index)(0) := (not (bits(4*index+3)) and bits(4*index+2)) or (not(bits(4*index+3) or bits(4*index+1)));
end loop;

if sub_vector(0) = '1' then
mux_2d(1 downto 0) := vector_2d(1);
else
mux_2d(1 downto 0) := vector_2d(0);
end if;

if sub_vector(2) = '1' then
mux_2d(3 downto 2) := vector_2d(3);
else
mux_2d(3 downto 2) := vector_2d(2);
end if;

if sub_vector(4) = '1' then
mux_2d(5 downto 4) := vector_2d(5);
else
mux_2d(5 downto 4) := vector_2d(4);
end if;

if sub_vector(6) = '1' then
mux_2d(7 downto 6) := vector_2d(7);
else
mux_2d(7 downto 6) := vector_2d(6);
end if;

expo(0) := sub_vector(0) and sub_vector(1);
expo(1) := expo(0) and sub_vector(2) and sub_vector(3);
expo(2) := expo(1) and sub_vector(4) and sub_vector(5);

case expo(0 to 2) is
when "000" => expo(3 to 4) := mux_2d(1 downto 0);
when "100" => expo(3 to 4) := mux_2d(3 downto 2);
when "110" => expo(3 to 4) := mux_2d(5 downto 4);
when others => expo(3 to 4) := mux_2d(7 downto 6);
end case;

clz(0) := expo(1);
clz(1) := (expo(0) and not expo(1)) or expo(2);
clz(2) := (sub_vector(0) and not(expo(0))) or
(expo(0) and sub_vector(2) and not(expo(1))) or
(expo(1) and sub_vector(4) and not(expo(2))) or
(expo(2) and sub_vector(6));
clz(3) := expo(3);
clz(4) := expo(4);

return to_integer(unsigned(clz));

end clz;

function msb (bits : in std_logic_vector) return integer is

variable mlb : integer := 0;

begin

for i in bits'low to bits'high loop
if bits(i) = '1' then
mlb := i;
end if;
end loop;

return mlb;

end msb;

end package body division_functions;
89 changes: 89 additions & 0 deletions alu/m/quick_naive.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;

use work.division_functions.all;

entity quick_naive is
generic (
N : natural := 32
);
port (
clk : in std_logic;
rst : in std_logic;
dividend : in unsigned(N-1 downto 0);
divisor : in unsigned(N-1 downto 0);
ready : out std_logic;
quotient : out unsigned(N-1 downto 0);
remainder: out unsigned(N-1 downto 0)
);
end entity;

architecture RTL of quick_naive is

signal start : std_logic;
signal new_dividend, new_divisor : unsigned(N-1 downto 0);

begin

quick_naive_load : process(clk, dividend, divisor)
begin

if rising_edge(clk) then
if (divisor /= new_divisor) or (dividend /= new_dividend) then
start <= '1';
new_divisor <= divisor;
new_dividend <= dividend;
else
start <= '0';
end if;
end if;

end process quick_naive_load;

quick_naive_process : process(clk, rst, start)

variable msb_d : integer range 0 to 31;
variable div_est, div_safe : unsigned(N-1 downto 0);
variable sub_result : unsigned(N-1 downto 0);
variable sub_overflow : unsigned(N downto 0);
variable t_remainder, t_quotient : unsigned(N-1 downto 0);

begin

if rst = '1' then
ready <= '0';
quotient <= (others => '0');
remainder <= (others => '0');
t_quotient := (others => '0');
t_remainder := (others => '0');
elsif rising_edge(clk) then
if start = '1' then
ready <= '0';
t_remainder := dividend;
t_quotient := (others => '0');
else
if divisor <= t_remainder then
msb_d := msb(std_logic_vector(t_remainder)) - msb(std_logic_vector(divisor));
div_est := shift_left(divisor, msb_d);
div_safe := shift_left(divisor, msb_d-1);
sub_overflow := (b"0" & t_remainder) - (b"0" & div_est);
sub_result := t_remainder - div_safe;
if(sub_overflow(N) = '1') then
t_remainder := sub_result;
t_quotient(msb_d-1) := '1';
else
t_remainder := sub_overflow(N-1 downto 0);
t_quotient(msb_d) := '1';
end if;
else
ready <= '1';
quotient <= t_quotient;
remainder <= t_remainder;
end if;
end if;
end if;

end process quick_naive_process;

end architecture;
Loading

0 comments on commit 4f5857e

Please sign in to comment.