OpenCores
URL https://opencores.org/ocsvn/mlite/mlite/trunk

Subversion Repositories mlite

[/] [mlite/] [trunk/] [vhdl/] [mult.vhd] - Blame information for rev 117

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 rhoads
---------------------------------------------------------------------
2
-- TITLE: Multiplication and Division Unit
3
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com)
4
-- DATE CREATED: 1/31/01
5
-- FILENAME: mult.vhd
6 43 rhoads
-- PROJECT: Plasma CPU core
7 2 rhoads
-- COPYRIGHT: Software placed into the public domain by the author.
8
--    Software 'as is' without warranty.  Author liable for nothing.
9
-- DESCRIPTION:
10
--    Implements the multiplication and division unit.
11 90 rhoads
--    Division takes 32 clock cycles.
12
--    Multiplication normally takes 16 clock cycles.
13
--    if b <= 0xffff then mult in 8 cycles. 
14
--    if b <= 0xff then mult in 4 cycles. 
15 97 rhoads
--
16
-- For multiplication set reg_b = 0x00000000 & b.  The 64-bit result
17
-- will be in reg_b.  The lower bits of reg_b contain the upper 
18
-- bits of b that have not yet been multiplied.  For 16 clock cycles
19
-- shift reg_b two bits to the right.  Use the lowest two bits of reg_b 
20
-- to multiply by two bits at a time and add the result to the upper
21
-- 32-bits of reg_b (using C syntax):
22
--    reg_b = (reg_b >> 2) + (((reg_b & 3) * reg_a) << 32);
23
--
24
-- For division set reg_b = '0' & b & 30_ZEROS.  The answer will be
25
-- in answer_reg and the remainder in reg_a.  For 32 clock cycles
26
-- (using C syntax):
27
--    answer_reg = (answer_reg << 1);
28
--    if (reg_a >= reg_b) {
29
--       answer_reg += 1;
30
--       reg_a -= reg_b;
31
--    }
32
--    reg_b = reg_b >> 1;
33 2 rhoads
---------------------------------------------------------------------
34
library ieee;
35
use ieee.std_logic_1164.all;
36 90 rhoads
use ieee.std_logic_unsigned.all;
37 39 rhoads
use work.mlite_pack.all;
38 2 rhoads
 
39
entity mult is
40 117 rhoads
   generic(adder_type : string := "GENERIC";
41
           mult_type  : string := "GENERIC");
42 2 rhoads
   port(clk       : in std_logic;
43
        a, b      : in std_logic_vector(31 downto 0);
44
        mult_func : in mult_function_type;
45
        c_mult    : out std_logic_vector(31 downto 0);
46
        pause_out : out std_logic);
47
end; --entity mult
48
 
49
architecture logic of mult is
50
--   type mult_function_type is (
51
--      mult_nothing, mult_read_lo, mult_read_hi, mult_write_lo, 
52
--      mult_write_hi, mult_mult, mult_divide, mult_signed_divide);
53 47 rhoads
   signal do_mult_reg   : std_logic;
54 2 rhoads
   signal do_signed_reg : std_logic;
55
   signal count_reg     : std_logic_vector(5 downto 0);
56
   signal reg_a         : std_logic_vector(31 downto 0);
57
   signal reg_b         : std_logic_vector(63 downto 0);
58
   signal answer_reg    : std_logic_vector(31 downto 0);
59 90 rhoads
   signal aa, bb        : std_logic_vector(33 downto 0);
60
   signal sum           : std_logic_vector(33 downto 0);
61
   signal reg_a_times3  : std_logic_vector(33 downto 0);
62 2 rhoads
begin
63
 
64
--multiplication/division unit
65
mult_proc: process(clk, a, b, mult_func,
66 47 rhoads
                   do_mult_reg, do_signed_reg, count_reg,
67 90 rhoads
                   reg_a, reg_b, answer_reg, sum, reg_a_times3)
68 47 rhoads
   variable do_mult_temp   : std_logic;
69 2 rhoads
   variable do_signed_temp : std_logic;
70
   variable count_temp     : std_logic_vector(5 downto 0);
71
   variable a_temp         : std_logic_vector(31 downto 0);
72
   variable b_temp         : std_logic_vector(63 downto 0);
73
   variable answer_temp    : std_logic_vector(31 downto 0);
74
   variable start          : std_logic;
75
   variable do_write       : std_logic;
76
   variable do_hi          : std_logic;
77 45 rhoads
   variable sign_extend    : std_logic;
78 99 rhoads
   variable a_neg          : std_logic_vector(31 downto 0);
79
   variable b_neg          : std_logic_vector(31 downto 0);
80 2 rhoads
 
81
begin
82 47 rhoads
   do_mult_temp   := do_mult_reg;
83 2 rhoads
   do_signed_temp := do_signed_reg;
84
   count_temp     := count_reg;
85
   a_temp         := reg_a;
86
   b_temp         := reg_b;
87
   answer_temp    := answer_reg;
88 47 rhoads
   sign_extend    := do_signed_reg and do_mult_reg;
89 2 rhoads
   start          := '0';
90
   do_write       := '0';
91
   do_hi          := '0';
92
 
93
   case mult_func is
94
   when mult_read_lo =>
95
   when mult_read_hi =>
96
      do_hi := '1';
97
   when mult_write_lo =>
98
      do_write := '1';
99
   when mult_write_hi =>
100
      do_write := '1';
101
      do_hi := '1';
102
   when mult_mult =>
103
      start := '1';
104 47 rhoads
      do_mult_temp := '1';
105 45 rhoads
      do_signed_temp := '0';
106
   when mult_signed_mult =>
107
      start := '1';
108 47 rhoads
      do_mult_temp := '1';
109 99 rhoads
      do_signed_temp := '1';
110 2 rhoads
   when mult_divide =>
111
      start := '1';
112 47 rhoads
      do_mult_temp := '0';
113 2 rhoads
      do_signed_temp := '0';
114
   when mult_signed_divide =>
115
      start := '1';
116 47 rhoads
      do_mult_temp := '0';
117 23 rhoads
      do_signed_temp := a(31) xor b(31);
118 2 rhoads
   when others =>
119
   end case;
120
 
121
   if start = '1' then
122
      count_temp := "000000";
123
      answer_temp := ZERO;
124 99 rhoads
      a_neg := bv_negate(a);
125
      b_neg := bv_negate(b);
126 47 rhoads
      if do_mult_temp = '0' then
127 18 rhoads
         b_temp(63) := '0';
128 99 rhoads
         if mult_func /= mult_signed_divide or a(31) = '0' then
129
            a_temp := a;
130
         else
131
            a_temp := a_neg;
132
         end if;
133 23 rhoads
         if mult_func /= mult_signed_divide or b(31) = '0' then
134 2 rhoads
            b_temp(62 downto 31) := b;
135
         else
136 99 rhoads
            b_temp(62 downto 31) := b_neg;
137 23 rhoads
         end if;
138 99 rhoads
         b_temp(30 downto 0) := ZERO(30 downto 0);
139
      else --multiply
140
         if do_signed_temp = '0' or b(31) = '0' then
141 23 rhoads
            a_temp := a;
142 99 rhoads
            b_temp(31 downto 0) := b;
143 23 rhoads
         else
144 99 rhoads
            a_temp := a_neg;
145
            b_temp(31 downto 0) := b_neg;
146 2 rhoads
         end if;
147 99 rhoads
         b_temp(63 downto 32) := ZERO;
148 2 rhoads
      end if;
149
   elsif do_write = '1' then
150
      if do_hi = '0' then
151
         b_temp(31 downto 0) := a;
152
      else
153
         b_temp(63 downto 32) := a;
154
      end if;
155
   end if;
156
 
157 90 rhoads
   if do_mult_reg = '0' then  --division
158
      aa <= (reg_a(31) and sign_extend) & (reg_a(31) and sign_extend) & reg_a;
159
      bb <= reg_b(33 downto 0);
160
   else                       --multiplication two-bits at a time
161
      case reg_b(1 downto 0) is
162
      when "00" =>
163
         aa <= "00" & ZERO;
164
      when "01" =>
165
         aa <= (reg_a(31) and sign_extend) & (reg_a(31) and sign_extend) & reg_a;
166
      when "10" =>
167
         aa <= (reg_a(31) and sign_extend) & reg_a & '0';
168
      when others =>
169
         aa <= reg_a_times3;
170
      end case;
171
      bb <= (reg_b(63) and sign_extend) & (reg_b(63) and sign_extend) & reg_b(63 downto 32);
172 2 rhoads
   end if;
173
 
174
   if count_reg(5) = '0' and start = '0' then
175
      count_temp := bv_inc6(count_reg);
176 90 rhoads
      if do_mult_reg = '0' then          --division
177 2 rhoads
         answer_temp(31 downto 1) := answer_reg(30 downto 0);
178 23 rhoads
         if reg_b(63 downto 32) = ZERO and sum(32) = '0' then
179 2 rhoads
            a_temp := sum(31 downto 0);  --aa=aa-bb;
180
            answer_temp(0) := '1';
181
         else
182
            answer_temp(0) := '0';
183
         end if;
184
         if count_reg /= "011111" then
185
            b_temp(62 downto 0) := reg_b(63 downto 1);
186 90 rhoads
         else                            --done with divide
187 2 rhoads
            b_temp(63 downto 32) := a_temp;
188 23 rhoads
            if do_signed_reg = '0' then
189
               b_temp(31 downto 0) := answer_temp;
190
            else
191
               b_temp(31 downto 0) := bv_negate(answer_temp);
192
            end if;
193 2 rhoads
         end if;
194
      else  -- mult_mode
195 90 rhoads
         b_temp(63 downto 30) := sum;
196
         b_temp(29 downto 0) := reg_b(31 downto 2);
197
         if count_reg = "001000" and sign_extend = '0' and   --early stop
198 7 rhoads
               reg_b(15 downto 0) = ZERO(15 downto 0) then
199 2 rhoads
            count_temp := "111111";
200
            b_temp(31 downto 0) := reg_b(47 downto 16);
201
         end if;
202 90 rhoads
         if count_reg = "000100" and sign_extend = '0' and   --early stop
203 7 rhoads
               reg_b(23 downto 0) = ZERO(23 downto 0) then
204
            count_temp := "111111";
205
            b_temp(31 downto 0) := reg_b(55 downto 24);
206
         end if;
207 90 rhoads
         count_temp(5) := count_temp(4);
208 2 rhoads
      end if;
209
   end if;
210
 
211
   if rising_edge(clk) then
212 47 rhoads
      do_mult_reg <= do_mult_temp;
213 2 rhoads
      do_signed_reg <= do_signed_temp;
214
      count_reg <= count_temp;
215
      reg_a <= a_temp;
216
      reg_b <= b_temp;
217
      answer_reg <= answer_temp;
218 90 rhoads
      if start = '1' then
219 99 rhoads
         reg_a_times3 <= ((a_temp(31) and do_signed_temp) & a_temp & '0') +
220
            ((a_temp(31) and do_signed_temp) & (a_temp(31) and do_signed_temp) & a_temp);
221 90 rhoads
      end if;
222 2 rhoads
   end if;
223
 
224
   if count_reg(5) = '0' and mult_func/= mult_nothing and start = '0' then
225
      pause_out <= '1';
226
   else
227
      pause_out <= '0';
228
   end if;
229 47 rhoads
   case mult_func is
230
   when mult_read_lo =>
231 2 rhoads
      c_mult <= reg_b(31 downto 0);
232 47 rhoads
   when mult_read_hi =>
233 2 rhoads
      c_mult <= reg_b(63 downto 32);
234 47 rhoads
   when others =>
235 2 rhoads
      c_mult <= ZERO;
236 47 rhoads
   end case;
237 2 rhoads
 
238
end process;
239
 
240 47 rhoads
 
241
   generic_adder:
242 117 rhoads
   if adder_type = "GENERIC" generate
243 90 rhoads
      sum <= (aa + bb) when do_mult_reg = '1' else
244
             (aa - bb);
245 47 rhoads
   end generate; --generic_adder
246
 
247
   --For Altera
248
   lpm_adder:
249
   if adder_type = "ALTERA" generate
250
      lpm_add_sub_component : lpm_add_sub
251
      GENERIC MAP (
252 90 rhoads
         lpm_width => 34,
253 47 rhoads
         lpm_direction => "UNUSED",
254
         lpm_type => "LPM_ADD_SUB",
255
         lpm_hint => "ONE_INPUT_IS_CONSTANT=NO"
256
      )
257
      PORT MAP (
258
         dataa => aa,
259
         add_sub => do_mult_reg,
260
         datab => bb,
261
         result => sum
262
      );
263
   end generate; --lpm_adder
264
 
265 2 rhoads
end; --architecture logic
266
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.