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

Subversion Repositories plasma_fpu

[/] [plasma_fpu/] [trunk/] [src/] [subunits/] [plasma_mult.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 __alexs__
-- --------------------------------------------------------------------------
2
-- >>>>>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<<<<
3
-- --------------------------------------------------------------------------
4
-- TITLE:       Plasma MULTIPLICATOR
5
-- AUTHOR:      Alex Schoenberger (Alex.Schoenberger@ies.tu-darmstadt.de)
6
-- COMMENT:     This project is based on Plasma CPU core by Steve Rhoads
7
--
8
-- www.ies.tu-darmstadt.de
9
-- TU Darmstadt
10
-- Institute for Integrated Systems
11
-- Merckstr. 25
12
-- 
13
-- 64283 Darmstadt - GERMANY
14
-- --------------------------------------------------------------------------
15
-- PROJECT:       Plasma CPU core with FPU
16
-- FILENAME:      plasma_mult.vhd
17
-- --------------------------------------------------------------------------
18
-- COPYRIGHT: 
19
--  This project is distributed by GPLv2.0
20
--  Software placed into the public domain by the author.
21
--  Software 'as is' without warranty.  Author liable for nothing.
22
-- --------------------------------------------------------------------------
23
-- DESCRIPTION:
24
--    implements multiplication operations depending on instruction code:
25
--    MULT, DIV, MULTU, DIVU, MTLO, MFLO, MTHI, MFHI
26
--
27
--    SYNTHESIZABLE
28
--
29
----------------------------------------------------------------------------
30
-- Revision History
31
-- --------------------------------------------------------------------------
32
-- Revision   Date    Author     CHANGES
33
-- 1.0      4/2014    AS         initial
34
-- --------------------------------------------------------------------------
35
library IEEE;
36
   use IEEE.std_logic_1164.ALL;
37
   use IEEE.numeric_std.ALL;
38
 
39
library PLASMA;
40
  use PLASMA.mips_instruction_set.ALL;
41
  use PLASMA.plasma_pack.ALL;
42
 
43
entity plasma_mult is
44
    port(
45
      control                 : in  t_main_control;
46
      mult_a_in               : in  t_plasma_word;
47
      mult_b_in               : in  t_plasma_word;
48
      mult_func               : in  t_mips_function;
49
      mult_busy               : out std_logic;
50
      mult_out                : out t_plasma_word
51
    );
52
end entity plasma_mult;
53
 
54
-- synthesis translate_off
55
-- ____ _ _  _ _  _ _    ____ ___ _ ____ _  _ 
56
-- [__  | |\/| |  | |    |__|  |  | |  | |\ | 
57
-- ___] | |  | |__| |___ |  |  |  | |__| | \| 
58
architecture sim_mult of plasma_mult is
59
 
60
   signal reg_mult      : t_plasma_dword;
61
   signal i_reg_mult    : t_plasma_dword;
62
 
63
begin
64
 
65
  process( control.clk )
66
 
67
    variable a_in_sig     :   signed(PLASMA_DATA_WIDTH - 1 downto 0);
68
    variable b_in_sig     :   signed(PLASMA_DATA_WIDTH - 1 downto 0);
69
 
70
    variable a_in_uns     : unsigned(PLASMA_DATA_WIDTH - 1 downto 0);
71
    variable b_in_uns     : unsigned(PLASMA_DATA_WIDTH - 1 downto 0);
72
 
73
  begin
74
 
75
    if falling_edge( control.clk ) then                         -- avoid spurious division by zero
76
 
77
    -- default values
78
    i_reg_mult <= reg_mult;
79
    mult_out      <= PLASMA_ZERO_WORD;
80
 
81
    -- operation mux
82
    case mult_func is
83
        when MIPS_FUNC_MFLO       =>
84
              mult_out      <= reg_mult(  PLASMA_DATA_WIDTH  - 1 downto                 0);
85
        when MIPS_FUNC_MFHI       =>
86
              mult_out      <= reg_mult(2*PLASMA_DATA_WIDTH  - 1 downto PLASMA_DATA_WIDTH);
87
        when MIPS_FUNC_MTLO      =>
88
              i_reg_mult <= reg_mult(2*PLASMA_DATA_WIDTH  - 1 downto PLASMA_DATA_WIDTH) & mult_a_in;
89
        when MIPS_FUNC_MTHI      =>
90
              i_reg_mult <= mult_a_in & reg_mult(PLASMA_DATA_WIDTH - 1 downto 0);
91
 
92
        when MIPS_FUNC_MULTU =>
93
 
94
              a_in_uns := unsigned(mult_a_in);
95
              b_in_uns := unsigned(mult_b_in);
96
 
97
              i_reg_mult <= std_logic_vector(a_in_uns * b_in_uns);
98
 
99
        when MIPS_FUNC_MULT   =>
100
              a_in_sig :=   signed(mult_a_in);
101
              b_in_sig :=   signed(mult_b_in);
102
 
103
              i_reg_mult <= std_logic_vector(a_in_sig * b_in_sig);
104
 
105
        when MIPS_FUNC_DIVU  =>
106
 
107
              a_in_uns := unsigned(mult_a_in);
108
              b_in_uns := unsigned(mult_b_in);
109
 
110
              assert ( b_in_uns /= 0) report "ERROR:Division by zero!" severity failure;
111
 
112
              i_reg_mult(  PLASMA_DATA_WIDTH - 1 downto                 0) <= std_logic_vector(a_in_uns  /  b_in_uns);
113
              i_reg_mult(2*PLASMA_DATA_WIDTH - 1 downto PLASMA_DATA_WIDTH) <= std_logic_vector(a_in_uns mod b_in_uns);
114
 
115
        when MIPS_FUNC_DIV    =>
116
 
117
              a_in_sig :=   signed(mult_a_in);
118
              b_in_sig :=   signed(mult_b_in);
119
 
120
              assert ( b_in_sig /= 0) report "ERROR:Division by zero!" severity failure;
121
 
122
              i_reg_mult(  PLASMA_DATA_WIDTH - 1 downto                 0) <= std_logic_vector(a_in_sig  /  b_in_sig);
123
              i_reg_mult(2*PLASMA_DATA_WIDTH - 1 downto PLASMA_DATA_WIDTH) <= std_logic_vector(a_in_sig mod b_in_sig);
124
 
125
        when others                    =>
126
      end case;
127
      end if;
128
   end process;
129
 
130
 
131
   process( control.clk )
132
   begin
133
      if rising_edge( control.clk ) then
134
         if control.rst = '1' then
135
            reg_mult <= (others => '0');
136
         else
137
            reg_mult <= i_reg_mult;
138
         end if;
139
      end if;
140
   end process;
141
 
142
   mult_busy <= '0';
143
 
144
end architecture sim_mult;
145
-- synthesis translate_on
146
 
147
 
148
library MUL;
149
 
150
-- ____ ___  ____ ____ 
151
-- |___ |__] | __ |__| 
152
-- |    |    |__] |  | 
153
architecture FPGA_mult of plasma_mult is
154
 
155
  -- ____ ___  ____ ____ ____ ___ _ ____ _  _    ____ ____ ____ ____ ____ 
156
  -- |  | |__] |___ |__/ |__|  |  | |  | |\ |    |    |  | |__/ |___ [__  
157
  -- |__| |    |___ |  \ |  |  |  | |__| | \|    |___ |__| |  \ |___ ___] 
158
  --
159
  -- multiplication
160
  --
161
  component mul_core is
162
  port(
163
    clk               : in  std_logic;
164
    rst               : in  std_logic;
165
 
166
    start             : in  std_logic;
167
    busy              : out std_logic;
168
    rdy               : out std_logic;
169
 
170
    sign_flag         : in  std_logic;
171
 
172
    a                 : in  std_logic_vector(31 downto 0);
173
    b                 : in  std_logic_vector(31 downto 0);
174
 
175
    c                 : out std_logic_vector(63 downto 0)
176
  );
177
  end component mul_core;
178
 
179
  --
180
  -- division
181
  --
182
  component div_core is
183
  port(
184
    clk               : in  std_logic;
185
    rst               : in  std_logic;
186
 
187
    start             : in  std_logic;
188
    busy              : out std_logic;
189
    rdy               : out std_logic;
190
 
191
    sign_flag         : in  std_logic;
192
 
193
    a                 : in  std_logic_vector(31 downto 0);
194
    b                 : in  std_logic_vector(31 downto 0);
195
 
196
    c                 : out std_logic_vector(31 downto 0);
197
    r                 : out std_logic_vector(31 downto 0)
198
  );
199
  end component div_core;
200
 
201
  --
202
  -- control
203
  --
204
  type t_core_ctrl is
205
    record
206
      -- start             : std_logic;       -- ModelSIM cannot handle different directions in a record
207
      busy              : std_logic;
208
      rdy               : std_logic;
209
    end record;
210
 
211
  signal c_mul          : t_core_ctrl;
212
  signal c_div          : t_core_ctrl;
213
 
214
  signal mul_start      : std_logic;
215
  signal div_start      : std_logic;
216
 
217
  signal sign_flag      : std_logic;
218
 
219
  --
220
  -- calculated data
221
  --
222
  signal mul_data       : t_plasma_dword;
223
  signal div_data       : t_plasma_dword;
224
 
225
  -- ____ ___ ____ ___ ____    _  _ ____ ____ _  _ _ _  _ ____ 
226
  -- [__   |  |__|  |  |___    |\/| |__| |    |__| | |\ | |___ 
227
  -- ___]  |  |  |  |  |___    |  | |  | |___ |  | | | \| |___ 
228
  type t_mult_state is ( s_IDLE, s_BUSY );
229
 
230
  signal i_state, state : t_mult_state;
231
 
232
  signal i_start        : std_logic;
233
  signal flag_div       : std_logic;
234
 
235
 
236
  -- _  _ ____ _ _  _    ____ ____ ____ _ ____ ___ ____ ____ 
237
  -- |\/| |__| | |\ |    |__/ |___ | __ | [__   |  |___ |__/ 
238
  -- |  | |  | | | \|    |  \ |___ |__] | ___]  |  |___ |  \ 
239
  type t_mul_reg_sel is (
240
      MUL_REG_STORE,                            -- stored value
241
      MUL_REG_LO,                               -- LO data from PLASMA
242
      MUL_REG_HI,                               -- HI data from PLASMA
243
      MUL_REG_MUL,                              -- data from multiplier core
244
      MUL_REG_DIV                               -- data from divisor core
245
    );
246
 
247
  signal mul_reg_sel    : t_mul_reg_sel;
248
 
249
  --
250
  -- main register
251
  --
252
  signal reg_en         : std_logic;
253
  signal reg_mult       : t_plasma_dword;
254
  signal i_reg_mult     : t_plasma_dword;
255
 
256
  --
257
  -- function
258
  --
259
  signal i_busy         : std_logic;
260
  signal func_en        : std_logic;
261
  signal i_mult_func    : t_mips_function;
262
  signal reg_mult_func  : t_mips_function;
263
 
264
  -- ____ _  _ ___ ___  _  _ ___ 
265
  -- |  | |  |  |  |__] |  |  |  
266
  -- |__| |__|  |  |    |__|  |  
267
  --
268
  -- output mux
269
  --
270
  type t_mul_out_sel is (
271
      MUL_OUT_HI,                               -- HI word
272
      MUL_OUT_LO,                               -- LO word
273
      MUL_OUT_MUL,                              -- from MUL core
274
      MUL_OUT_DIV                               -- from DIV core
275
    );
276
 
277
  signal mul_out_sel    : t_mul_out_sel;
278
 
279
begin
280
  -- ____ ___  ____ ____ ____ ___ _ ____ _  _    ____ ____ ____ ____ ____ 
281
  -- |  | |__] |___ |__/ |__|  |  | |  | |\ |    |    |  | |__/ |___ [__  
282
  -- |__| |    |___ |  \ |  |  |  | |__| | \|    |___ |__| |  \ |___ ___] 
283
  mult_core_unit: entity MUL.mul_core
284
  PORT MAP(
285
    clk       => control.clk,     rst => control.rst,
286
    start     => mul_start,
287
    busy      => c_mul.busy,      rdy => c_mul.rdy,
288
    sign_flag => sign_flag,
289
 
290
    a         => mult_a_in,       b   => mult_b_in,
291
    c         => mul_data
292
  );
293
 
294
  div_core_unit: entity MUL.div_core
295
  PORT MAP(
296
    clk       => control.clk,     rst => control.rst,
297
    start     => div_start,
298
    busy      => c_div.busy,      rdy => c_div.rdy,
299
    sign_flag => sign_flag,
300
 
301
    a         => mult_a_in,       b   => mult_b_in,
302
    c         => div_data(31 downto 0),
303
    r         => div_data(63 downto 32)
304
  );
305
 
306
  -- ___  ____ ____ ____ ___  ____ ____ 
307
  -- |  \ |___ |    |  | |  \ |___ |__/ 
308
  -- |__/ |___ |___ |__| |__/ |___ |  \ 
309
  --
310
  -- intern busy indicates calculation till ready is set
311
  --
312
  i_busy                <= (c_mul.busy or c_div.busy) and (not c_mul.rdy) and (not c_div.rdy);
313
 
314
  --
315
  -- store function till calculation is finished
316
  --
317
  i_mult_func           <= reg_mult_func when state = s_BUSY else mult_func;
318
 
319
  --
320
  -- signed calculation
321
  --
322
  sign_flag             <= '1' when (i_mult_func = MIPS_FUNC_MULT) or
323
                                    (i_mult_func = MIPS_FUNC_DIV)
324
                                                                      else '0';
325
 
326
  --
327
  -- decode command
328
  --
329
  mult_decode:
330
  process( i_mult_func, c_mul.rdy, c_div.rdy )
331
  begin
332
    -- ############## DEFAULT VALUES
333
    reg_en              <= '0';             -- no register store
334
    mul_reg_sel         <= MUL_REG_STORE;   -- stored value remains
335
 
336
    mul_out_sel         <= MUL_OUT_LO;      -- LO word
337
 
338
    --
339
    -- state machine control
340
    --
341
    i_start             <= '0';             -- no calculation
342
    flag_div            <= '0';             -- multiplication is default
343
 
344
    -- operation mux
345
    case i_mult_func is
346
        when MIPS_FUNC_MFLO   =>
347
 
348
        when MIPS_FUNC_MFHI   =>
349
              mul_out_sel       <= MUL_OUT_HI;
350
 
351
        when MIPS_FUNC_MTLO   =>
352
              mul_reg_sel       <= MUL_REG_LO;
353
              reg_en            <= '1';
354
 
355
        when MIPS_FUNC_MTHI   =>
356
              mul_reg_sel       <= MUL_REG_HI;
357
              reg_en            <= '1';
358
 
359
        when MIPS_FUNC_MULTU |
360
             MIPS_FUNC_MULT   =>
361
              i_start           <= '1';
362
 
363
              reg_en            <= c_mul.rdy;
364
              mul_reg_sel       <= MUL_REG_MUL;
365
 
366
        when MIPS_FUNC_DIVU  |
367
             MIPS_FUNC_DIV    =>
368
              i_start           <= '1';
369
              flag_div          <= '1';
370
 
371
              reg_en            <= c_div.rdy;
372
              mul_reg_sel       <= MUL_REG_DIV;
373
 
374
        when others            =>
375
      end case;
376
   end process;
377
 
378
  -- ____ ___ ____ ___ ____    _  _ ____ ____ _  _ _ _  _ ____ 
379
  -- [__   |  |__|  |  |___    |\/| |__| |    |__| | |\ | |___ 
380
  -- ___]  |  |  |  |  |___    |  | |  | |___ |  | | | \| |___ 
381
  --
382
  -- start calculation units and store function
383
  --
384
  mult_state:
385
  process( state, i_start, flag_div, i_busy )
386
  begin
387
    -- ############ DEFAULT VALUES
388
    --
389
    -- calculations units control
390
    --
391
    mul_start           <= '0';             -- mul core inactive
392
    div_start           <= '0';             -- div core inactive
393
 
394
    --
395
    -- function store
396
    --
397
    func_en             <= '0';             -- no function store
398
 
399
    --
400
    -- next state
401
    --
402
    i_state             <= s_IDLE;          -- remain in IDLE
403
 
404
    -- ############ STATE LOGIC
405
    case state is
406
      when s_IDLE   => if i_start = '1' then
407
 
408
                        mul_start   <= not flag_div;
409
                        div_start   <= flag_div;
410
 
411
                        func_en     <= '1';   -- store function
412
 
413
                        i_state     <= s_BUSY;
414
                       end if;
415
 
416
      when s_BUSY   => if i_busy = '1' then
417
                        i_state     <= s_BUSY;
418
                       end if;
419
      when others   =>
420
    end case;
421
  end process;
422
 
423
  -- _  _ ____ _ _  _    ____ ____ ____ _ ____ ___ ____ ____ 
424
  -- |\/| |__| | |\ |    |__/ |___ | __ | [__   |  |___ |__/ 
425
  -- |  | |  | | | \|    |  \ |___ |__] | ___]  |  |___ |  \ 
426
  --
427
  -- select next input
428
  --
429
  with mul_reg_sel select
430
    i_reg_mult        <= reg_mult(2*PLASMA_DATA_WIDTH  - 1 downto PLASMA_DATA_WIDTH) & mult_a_in  when MUL_REG_LO,
431
                         mult_a_in & reg_mult(PLASMA_DATA_WIDTH - 1 downto 0)                     when MUL_REG_HI,
432
                         mul_data                                                                 when MUL_REG_MUL,
433
                         div_data                                                                 when MUL_REG_DIV,
434
                         reg_mult                                                                 when others;
435
 
436
  mult_register:
437
  process( control.clk )
438
  begin
439
    if rising_edge( control.clk ) then
440
      if control.rst = '1' then
441
        reg_mult          <= (others => '0');
442
 
443
        reg_mult_func     <= MIPS_FUNC_MFLO;
444
 
445
        state             <= s_IDLE;
446
      else
447
        if reg_en = '1' then
448
          reg_mult        <= i_reg_mult;
449
        end if;
450
 
451
        if func_en = '1' then
452
          reg_mult_func   <= mult_func;
453
        end if;
454
 
455
        state             <= i_state;           -- always active
456
      end if;
457
    end if;
458
  end process;
459
 
460
  -- ____ _  _ ___ ___  _  _ ___ 
461
  -- |  | |  |  |  |__] |  |  |  
462
  -- |__| |__|  |  |    |__|  | 
463
  --
464
  -- busy indication
465
  --
466
  -- mult_busy           <= c_mul.busy or c_div.busy;
467
  mult_busy           <= i_busy;      -- 1 clock cycle is necessary for change from ID to EX stage
468
 
469
  --
470
  -- data output
471
  --
472
  with mul_out_sel select
473
    mult_out          <= reg_mult(  PLASMA_DATA_WIDTH - 1 downto                 0) when MUL_OUT_LO,
474
                         reg_mult(2*PLASMA_DATA_WIDTH - 1 downto PLASMA_DATA_WIDTH) when others;
475
 
476
end architecture FPGA_mult;

powered by: WebSVN 2.1.0

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