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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [rtl/] [verilog/] [or1200/] [or1200_fpu.v] - Blame information for rev 751

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

Line No. Rev Author Line
1 350 julius
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  OR1200's FPU Wrapper                                        ////
4
////                                                              ////
5
////  This file is part of the OpenRISC 1200 project              ////
6
////  http://opencores.org/project,or1k                           ////
7
////                                                              ////
8
////  Description                                                 ////
9
////  Wrapper for floating point unit.                            ////
10
////  Interface based on MULT/MAC unit.                           ////
11
////                                                              ////
12
////  To Do:                                                      ////
13
////   - lf.rem.s and lf.madd.s instruction support               ////
14
////   - implement FP SPRs as needed                              ////
15
////                                                              ////
16
////  Author(s):                                                  ////
17
////      - Julius Baxter, julius@opencores.org                   ////
18
////                                                              ////
19
//////////////////////////////////////////////////////////////////////
20
////                                                              ////
21
//// Copyright (C) 2009,2010 Authors and OPENCORES.ORG            ////
22
////                                                              ////
23
//// This source file may be used and distributed without         ////
24
//// restriction provided that this copyright statement is not    ////
25
//// removed from the file and that any derivative work contains  ////
26
//// the original copyright notice and the associated disclaimer. ////
27
////                                                              ////
28
//// This source file is free software; you can redistribute it   ////
29
//// and/or modify it under the terms of the GNU Lesser General   ////
30
//// Public License as published by the Free Software Foundation; ////
31
//// either version 2.1 of the License, or (at your option) any   ////
32
//// later version.                                               ////
33
////                                                              ////
34
//// This source is distributed in the hope that it will be       ////
35
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
36
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
37
//// PURPOSE.  See the GNU Lesser General Public License for more ////
38
//// details.                                                     ////
39
////                                                              ////
40
//// You should have received a copy of the GNU Lesser General    ////
41
//// Public License along with this source; if not, download it   ////
42
//// from http://www.opencores.org/lgpl.shtml                     ////
43
////                                                              ////
44
//////////////////////////////////////////////////////////////////////
45
 
46
// synopsys translate_off
47
`include "timescale.v"
48
// synopsys translate_on
49
`include "or1200_defines.v"
50
 
51
module or1200_fpu(
52
                  // Clock and reset
53
                  clk, rst,
54
 
55
                  // FPU interface
56
                  ex_freeze, a, b, fpu_op, result, done,
57
 
58
                  // Flag controls
59
                  flagforw, flag_we,
60
 
61
                  // Exception signal
62
                  sig_fp, except_started,
63
 
64
                  // FPCSR system register
65
                  fpcsr_we, fpcsr,
66
 
67
                  // SPR interface -- currently unused
68
                  spr_cs, spr_write, spr_addr, spr_dat_i, spr_dat_o
69
                  );
70
 
71
   parameter width = `OR1200_OPERAND_WIDTH;
72
 
73
   //
74
   // I/O
75
   //
76
 
77
   //
78
   // Clock and reset
79
   //
80
   input                                clk;
81
   input                                rst;
82
 
83
   //
84
   // FPU interface
85
   //
86
   input                                ex_freeze;
87
   input [width-1:0]                     a;
88
   input [width-1:0]                     b;
89
   input [`OR1200_FPUOP_WIDTH-1:0]       fpu_op;
90
   output [width-1:0]                    result;
91
   output                               done;
92
 
93
   //
94
   // Flag signals
95
   //
96
   output                               flagforw;
97
   output                               flag_we;
98
 
99
   //
100
   // FPCSR interface
101
   //  
102
   input                                fpcsr_we;
103
   output [`OR1200_FPCSR_WIDTH-1:0]      fpcsr;
104
 
105
   //
106
   // Exception signal
107
   //   
108
   output                               sig_fp;
109
   input                                except_started;
110
 
111
 
112
   //
113
   // SPR interface
114
   //
115
   input                                spr_cs;
116
   input                                spr_write;
117
   input [31:0]                  spr_addr;
118
   input [31:0]                  spr_dat_i;
119
   output [31:0]                         spr_dat_o;
120
 
121
 
122
`ifndef OR1200_FPU_IMPLEMENTED
123
 
124
   // No FPU needed
125
   assign result = 0;
126
   assign flagforw  = 0;
127
   assign flag_we = 0;
128
   assign sig_fp = 0;
129
   assign spr_dat_o = 0;
130
   assign fpcsr = 0;
131
   assign done = 1;
132
`else
133
 
134
 
135
   //
136
   // Internals
137
   //
138
   wire                                 fpu_op_is_arith, fpu_op_is_conv,
139
                                        fpu_op_is_comp;
140
   wire                                 fpu_op_r_is_arith, fpu_op_r_is_conv,
141
                                        fpu_op_r_is_comp;
142
   wire                                 fpu_arith_done, fpu_conv_done,
143
                                        fpu_comp_done;
144
   wire [width-1:0]                      result_arith, result_conv;
145
 
146 364 julius
   reg [`OR1200_FPUOP_WIDTH-1:0]         fpu_op_r;
147 350 julius
   reg [`OR1200_FPCSR_WIDTH-1:0]         fpcsr_r;
148
   wire                                 fpu_op_valid;
149
   reg                                  fpu_op_valid_re;
150
   wire                                 fpu_check_op;
151
   wire                                 inf, inv_inf_op_in,snan, snan_in,qnan,
152
                                        ine, overflow, underflow, zero, dbz,
153
                                        dbz_in, mul_z_inf, nan_in;
154
   wire                                 altb, blta, aeqb, inf_cmp, zero_cmp,
155
                                        unordered ;
156
   wire                                 snan_conv, ine_conv, inv_conv,
157
                                        zero_conv, underflow_conv,
158
                                        overflow_conv;
159
   wire                                 inv_comp;
160
   reg                                  flag;
161
 
162
 
163
   assign spr_dat_o = 0;
164
 
165
   assign fpcsr = fpcsr_r;
166
 
167
   assign sig_fp = fpcsr_r[`OR1200_FPCSR_FPEE]
168
            & (|fpcsr_r[`OR1200_FPCSR_WIDTH-1:`OR1200_FPCSR_OVF]);
169
 
170
   // Top bit indicates FPU instruction
171
   assign fpu_op_valid = fpu_op[`OR1200_FPUOP_WIDTH-1];
172
 
173
   assign fpu_check_op = !ex_freeze & fpu_op_valid;
174
 
175
   // Generate signals to latch fpu_op from decode instruction, then latch 
176
   // operands when they appear during execute stage
177
 
178
   assign fpu_op_is_arith = !(|fpu_op[3:2]);
179
   assign fpu_op_is_conv = fpu_op[2] & !fpu_op[3];
180
   assign fpu_op_is_comp = fpu_op[3];
181
 
182
   assign fpu_op_r_is_arith = !(|fpu_op_r[3:2]);
183
   assign fpu_op_r_is_conv = fpu_op_r[2] & !fpu_op_r[3];
184
   assign fpu_op_r_is_comp = fpu_op_r[3];
185
 
186
   assign done = (fpu_op_r_is_arith & fpu_arith_done) |
187
                 (fpu_op_r_is_conv & fpu_conv_done)   |
188
                 (fpu_op_r_is_comp & fpu_comp_done)   ;
189
 
190
   // Register fpu_op (remove FPU op valid bit [7], replace with 0)
191
   always @(posedge clk)
192
     if (fpu_check_op)
193
       fpu_op_r <= {1'b0,fpu_op[`OR1200_FPUOP_WIDTH-2:0]};
194
 
195
   // Indicate new FPU op
196 358 julius
   always @(posedge clk or `OR1200_RST_EVENT rst)
197
     if (rst == `OR1200_RST_VALUE)
198 350 julius
       fpu_op_valid_re <= 0;
199
     else if (fpu_op_valid_re)
200
       fpu_op_valid_re <= 0;
201
     else if (fpu_check_op)
202
       fpu_op_valid_re <= 1;
203
 
204
   //
205
   // FPCSR system group register implementation
206
   //   
207 358 julius
   always @(posedge clk or `OR1200_RST_EVENT rst) begin
208
      if (rst == `OR1200_RST_VALUE)
209 350 julius
        fpcsr_r <= 0;
210
      else
211
        begin
212
           if (fpcsr_we)
213
             fpcsr_r <= b[`OR1200_FPCSR_WIDTH-1:0];
214
           else if (done)
215
             begin
216
                fpcsr_r[`OR1200_FPCSR_OVF] <= (overflow & fpu_op_r_is_arith);
217
                fpcsr_r[`OR1200_FPCSR_UNF] <= (underflow & fpu_op_r_is_arith) |
218
                                          (underflow_conv  & fpu_op_r_is_conv);
219
                fpcsr_r[`OR1200_FPCSR_SNF] <= (snan  & fpu_op_r_is_arith)|
220
                                              (snan_conv & fpu_op_r_is_conv);
221
                fpcsr_r[`OR1200_FPCSR_QNF] <= (qnan  & fpu_op_r_is_arith);
222
                fpcsr_r[`OR1200_FPCSR_ZF]  <= (zero  & fpu_op_r_is_arith) |
223
                                              (zero_cmp & fpu_op_r_is_comp) |
224
                                              (zero_conv & fpu_op_r_is_conv);
225
                fpcsr_r[`OR1200_FPCSR_IXF] <= (ine  & fpu_op_r_is_arith) |
226
                                              (ine_conv & fpu_op_r_is_conv);
227
                fpcsr_r[`OR1200_FPCSR_IVF] <=
228
                                ((snan_in | dbz_in | inv_inf_op_in | mul_z_inf) &
229
                                           fpu_op_r_is_arith) |
230
                                  ((inv_conv | snan_conv) & fpu_op_r_is_conv) |
231
                                              (inv_comp & fpu_op_r_is_comp);
232
                fpcsr_r[`OR1200_FPCSR_INF] <= (inf  & fpu_op_r_is_arith) |
233
                                              (inf_cmp & fpu_op_r_is_comp);
234
                fpcsr_r[`OR1200_FPCSR_DZF] <= (dbz & fpu_op_r_is_arith);
235
             end // if (fpu_arith_done | fpu_conv_done)    
236
           if (except_started)
237
             fpcsr_r[`OR1200_FPCSR_FPEE] <= 0;
238
        end // else: !if(rst)
239 358 julius
   end // always @ (posedge clk or `OR1200_RST_EVENT rst)
240 350 julius
 
241
   //
242
   // Comparison flag generation
243
   //
244
   always @*
245
     begin
246
        // Get rid of top bit - is FPU op valid bit
247
        case({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]})
248
          `OR1200_FPCOP_SFEQ: begin
249
             flag = aeqb;
250
          end
251
          `OR1200_FPCOP_SFNE: begin
252
             flag = !aeqb;
253
               end
254
          `OR1200_FPCOP_SFGT: begin
255
             flag = blta & !aeqb;
256
          end
257
          `OR1200_FPCOP_SFGE: begin
258
             flag = blta | aeqb;
259
          end
260
          `OR1200_FPCOP_SFLT: begin
261
             flag = altb & !aeqb;
262
          end
263
          `OR1200_FPCOP_SFLE: begin
264
             flag = altb | aeqb;
265
          end
266
          default: begin
267
             flag = 0;
268
          end
269
        endcase // case (fpu_op_r)
270
     end // always@ (posedge clk)
271
 
272
   assign flagforw = flag;
273
 
274
   // Determine here where we do the write, ie how much we pipeline the 
275
   // comparison
276
   assign flag_we = fpu_op_r_is_comp & fpu_comp_done;
277
 
278
   // MUX for outputs from arith and conversion modules
279
   assign result = fpu_op_r_is_conv ? result_conv : result_arith;
280
 
281
   //
282
   // Instantiate FPU modules
283
   //
284
 
285
   // FPU 100 VHDL core from OpenCores.org: http://opencores.org/project,fpu100
286
   // Used only for add,sub,mul,div
287
   or1200_fpu_arith fpu_arith
288
     (
289
      .clk_i(clk),
290
      .opa_i(a),
291
      .opb_i(b),
292
      .fpu_op_i({1'b0,fpu_op_r[1:0]}), // Only bottom 2 bits
293
      .rmode_i(fpcsr_r[`OR1200_FPCSR_RM]),
294
      .output_o(result_arith),
295
      .start_i(fpu_op_valid_re & fpu_op_r_is_arith),
296
      .ready_o(fpu_arith_done),
297
      .ine_o(ine),
298
      .overflow_o(overflow),
299
      .underflow_o(underflow),
300
      .div_zero_o(dbz),
301
      .inf_o(inf),
302
      .zero_o(zero),
303
      .qnan_o(qnan),
304
      .snan_o(snan)
305
      );
306
 
307
   // Logic for detection of signaling NaN on input
308
   // signaling NaN: exponent is 8hff, [22] is zero, rest of fract is non-zero
309
   // quiet NaN: exponent is 8hff, [22] is 1
310
   reg a_is_snan, b_is_snan;
311
   reg a_is_qnan, b_is_qnan;
312
 
313
   always @(posedge clk)
314
     begin
315
        a_is_snan <= (a[30:23]==8'hff) & !a[22] & (|a[21:0]);
316
        b_is_snan <= (b[30:23]==8'hff) & !b[22] & (|b[21:0]);
317
        a_is_qnan <= (a[30:23]==8'hff) & a[22];
318
        b_is_qnan <= (b[30:23]==8'hff) & b[22];
319
     end
320
   // Signal to indicate there was a signaling NaN on input
321
   assign snan_in = a_is_snan | b_is_snan;
322
 
323
   // Check for, add with opposite signed infinities, or subtract with 
324
   // same signed infinities.
325
   reg a_is_inf, b_is_inf, a_b_sign_xor;
326
 
327
   always @(posedge clk)
328
     begin
329
        a_is_inf <= (a[30:23]==8'hff) & !(|a[22:0]);
330
        b_is_inf <= (b[30:23]==8'hff) & !(|a[22:0]);
331
        a_b_sign_xor <= a[31] ^ b[31];
332
     end
333
 
334
   assign inv_inf_op_in = (a_is_inf & b_is_inf) &
335
                          ((a_b_sign_xor &
336
                            ({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]} ==
337
                             `OR1200_FPUOP_ADD)) |
338
                           (!a_b_sign_xor &
339
                            ({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]} ==
340
                             `OR1200_FPUOP_SUB))) ;
341
 
342
   // Check if it's 0.0/0.0 to generate invalid signal (ignore sign bit)
343
   reg a_is_zero, b_is_zero;
344
 
345
   always @(posedge clk)
346
     begin
347
        a_is_zero <= !(|a[30:0]);
348
        b_is_zero <= !(|b[30:0]);
349
     end
350
   assign dbz_in = ({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]} ==
351
                    `OR1200_FPUOP_DIV) & (a_is_zero & b_is_zero);
352
 
353
 
354
   assign mul_z_inf = ({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]} ==
355
                       `OR1200_FPUOP_MUL) &
356
                      ((a_is_zero & b_is_inf) | (b_is_zero & a_is_inf));
357
 
358
   assign nan_in = (a_is_snan | b_is_snan | a_is_qnan | b_is_qnan);
359
 
360
   // 32-bit integer <-> single precision floating point conversion unit
361
   or1200_fpu_intfloat_conv fpu_intfloat_conv
362
     (
363
       .clk(clk),
364
       .rmode(fpcsr_r[`OR1200_FPCSR_RM]),
365
       .fpu_op(fpu_op_r[2:0]),
366
       .opa(a),
367
       .out(result_conv),
368
       .snan(snan_conv),
369
       .ine(ine_conv),
370
       .inv(inv_conv),
371
       .overflow(overflow_conv),
372
       .underflow(underflow_conv),
373
       .zero(zero_conv)
374
       );
375
 
376
   // 5-long shift reg for conversion ready counter
377
   reg [6:0] fpu_conv_shr;
378
   always @(posedge clk)
379
     fpu_conv_shr <= {fpu_conv_shr[5:0],fpu_check_op & fpu_op_is_conv};
380
   assign fpu_conv_done = fpu_conv_shr[6];
381
 
382
   // Single precision floating point number comparison module
383
   or1200_fpu_fcmp fpu_fcmp
384
     (
385
      .opa(a),
386
      .opb(b),
387
      .unordered(unordered),
388
      // I am convinced the comparison logic is wrong way around in this 
389
      // module, simplest to swap them on output -- julius       
390
      .altb(blta),
391
      .blta(altb),
392
      .aeqb(aeqb),
393
      .inf(inf_cmp),
394
      .zero(zero_cmp));
395
 
396
   reg       fpu_op_valid_re_r;
397
   always @(posedge clk)
398
     fpu_op_valid_re_r  <= fpu_op_valid_re;
399
 
400
   assign fpu_comp_done = fpu_op_valid_re_r & fpu_op_r_is_comp;
401
 
402
   // Comparison invalid when sNaN in on an equal comparison, or any NaN 
403
   // for any other comparison.
404
   assign inv_comp =  (snan_in & ({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]}
405
                                  == `OR1200_FPCOP_SFEQ)) |
406
                      (nan_in & ({1'b0,fpu_op_r[`OR1200_FPUOP_WIDTH-2:0]}
407
                                 != `OR1200_FPCOP_SFEQ));
408
 
409
`endif // !`ifndef OR1200_FPU_IMPLEMENTED
410
 
411
endmodule // or1200_fpu

powered by: WebSVN 2.1.0

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