forked from antonblanchard/microwatt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
divider.vhdl
137 lines (131 loc) · 4.7 KB
/
divider.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.common.all;
use work.decode_types.all;
entity divider is
port (
clk : in std_logic;
rst : in std_logic;
d_in : in Execute1ToDividerType;
d_out : out DividerToExecute1Type
);
end entity divider;
architecture behaviour of divider is
signal dend : std_ulogic_vector(128 downto 0);
signal div : unsigned(63 downto 0);
signal quot : std_ulogic_vector(63 downto 0);
signal result : std_ulogic_vector(63 downto 0);
signal sresult : std_ulogic_vector(64 downto 0);
signal oresult : std_ulogic_vector(63 downto 0);
signal running : std_ulogic;
signal count : unsigned(6 downto 0);
signal neg_result : std_ulogic;
signal is_modulus : std_ulogic;
signal is_32bit : std_ulogic;
signal extended : std_ulogic;
signal is_signed : std_ulogic;
signal overflow : std_ulogic;
signal ovf32 : std_ulogic;
signal did_ovf : std_ulogic;
begin
divider_0: process(clk)
begin
if rising_edge(clk) then
if rst = '1' or d_in.flush = '1' then
dend <= (others => '0');
div <= (others => '0');
quot <= (others => '0');
running <= '0';
count <= "0000000";
is_32bit <= '0';
overflow <= '0';
elsif d_in.valid = '1' then
if d_in.is_extended = '1' then
dend <= '0' & d_in.dividend & x"0000000000000000";
else
dend <= '0' & x"0000000000000000" & d_in.dividend;
end if;
div <= unsigned(d_in.divisor);
quot <= (others => '0');
neg_result <= d_in.neg_result;
is_modulus <= d_in.is_modulus;
extended <= d_in.is_extended;
is_32bit <= d_in.is_32bit;
is_signed <= d_in.is_signed;
count <= "1111111";
running <= '1';
overflow <= '0';
ovf32 <= '0';
elsif running = '1' then
if count = "0111111" then
running <= '0';
end if;
overflow <= quot(63);
if dend(128) = '1' or unsigned(dend(127 downto 64)) >= div then
ovf32 <= ovf32 or quot(31);
dend <= std_ulogic_vector(unsigned(dend(127 downto 64)) - div) &
dend(63 downto 0) & '0';
quot <= quot(62 downto 0) & '1';
count <= count + 1;
elsif dend(128 downto 57) = x"000000000000000000" and count(6 downto 3) /= "0111" then
-- consume 8 bits of zeroes in one cycle
ovf32 <= or (ovf32 & quot(31 downto 24));
dend <= dend(120 downto 0) & x"00";
quot <= quot(55 downto 0) & x"00";
count <= count + 8;
else
ovf32 <= ovf32 or quot(31);
dend <= dend(127 downto 0) & '0';
quot <= quot(62 downto 0) & '0';
count <= count + 1;
end if;
else
count <= "0000000";
end if;
end if;
end process;
divider_1: process(all)
begin
if is_modulus = '1' then
result <= dend(128 downto 65);
else
result <= quot;
end if;
if neg_result = '1' then
sresult <= std_ulogic_vector(- signed('0' & result));
else
sresult <= '0' & result;
end if;
did_ovf <= '0';
if is_32bit = '0' then
did_ovf <= overflow or (is_signed and (sresult(64) xor sresult(63)));
elsif is_signed = '1' then
if ovf32 = '1' or sresult(32) /= sresult(31) then
did_ovf <= '1';
end if;
else
did_ovf <= ovf32;
end if;
if did_ovf = '1' then
oresult <= (others => '0');
elsif (is_32bit = '1') and (is_modulus = '0') then
-- 32-bit divisions set the top 32 bits of the result to 0
oresult <= x"00000000" & sresult(31 downto 0);
else
oresult <= sresult(63 downto 0);
end if;
end process;
divider_out: process(clk)
begin
if rising_edge(clk) then
d_out.valid <= '0';
d_out.write_reg_data <= oresult;
d_out.overflow <= did_ovf;
if count = "1000000" then
d_out.valid <= '1';
end if;
end if;
end process;
end architecture behaviour;