-
Notifications
You must be signed in to change notification settings - Fork 110
/
fpnew_pkg.sv
495 lines (432 loc) · 17.6 KB
/
fpnew_pkg.sv
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
// Copyright 2019 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// SPDX-License-Identifier: SHL-0.51
// Author: Stefan Mach <smach@iis.ee.ethz.ch>
package fpnew_pkg;
// ---------
// FP TYPES
// ---------
// | Enumerator | Format | Width | EXP_BITS | MAN_BITS
// |:----------:|------------------|-------:|:--------:|:--------:
// | FP32 | IEEE binary32 | 32 bit | 8 | 23
// | FP64 | IEEE binary64 | 64 bit | 11 | 52
// | FP16 | IEEE binary16 | 16 bit | 5 | 10
// | FP8 | binary8 | 8 bit | 5 | 2
// | FP16ALT | binary16alt | 16 bit | 8 | 7
// *NOTE:* Add new formats only at the end of the enumeration for backwards compatibilty!
// Encoding for a format
typedef struct packed {
int unsigned exp_bits;
int unsigned man_bits;
} fp_encoding_t;
localparam int unsigned NUM_FP_FORMATS = 5; // change me to add formats
localparam int unsigned FP_FORMAT_BITS = $clog2(NUM_FP_FORMATS);
// FP formats
typedef enum logic [FP_FORMAT_BITS-1:0] {
FP32 = 'd0,
FP64 = 'd1,
FP16 = 'd2,
FP8 = 'd3,
FP16ALT = 'd4
// add new formats here
} fp_format_e;
// Encodings for supported FP formats
localparam fp_encoding_t [0:NUM_FP_FORMATS-1] FP_ENCODINGS = '{
'{8, 23}, // IEEE binary32 (single)
'{11, 52}, // IEEE binary64 (double)
'{5, 10}, // IEEE binary16 (half)
'{5, 2}, // custom binary8
'{8, 7} // custom binary16alt
// add new formats here
};
typedef logic [0:NUM_FP_FORMATS-1] fmt_logic_t; // Logic indexed by FP format (for masks)
typedef logic [0:NUM_FP_FORMATS-1][31:0] fmt_unsigned_t; // Unsigned indexed by FP format
localparam fmt_logic_t CPK_FORMATS = 5'b11000; // FP32 and FP64 can provide CPK only
// ---------
// INT TYPES
// ---------
// | Enumerator | Width |
// |:----------:|-------:|
// | INT8 | 8 bit |
// | INT16 | 16 bit |
// | INT32 | 32 bit |
// | INT64 | 64 bit |
// *NOTE:* Add new formats only at the end of the enumeration for backwards compatibilty!
localparam int unsigned NUM_INT_FORMATS = 4; // change me to add formats
localparam int unsigned INT_FORMAT_BITS = $clog2(NUM_INT_FORMATS);
// Int formats
typedef enum logic [INT_FORMAT_BITS-1:0] {
INT8,
INT16,
INT32,
INT64
// add new formats here
} int_format_e;
// Returns the width of an INT format by index
function automatic int unsigned int_width(int_format_e ifmt);
unique case (ifmt)
INT8: return 8;
INT16: return 16;
INT32: return 32;
INT64: return 64;
default: begin
// pragma translate_off
$fatal(1, "Invalid INT format supplied");
// pragma translate_on
// just return any integer to avoid any latches
// hopefully this error is caught by simulation
return INT8;
end
endcase
endfunction
typedef logic [0:NUM_INT_FORMATS-1] ifmt_logic_t; // Logic indexed by INT format (for masks)
// --------------
// FP OPERATIONS
// --------------
localparam int unsigned NUM_OPGROUPS = 4;
// Each FP operation belongs to an operation group
typedef enum logic [1:0] {
ADDMUL, DIVSQRT, NONCOMP, CONV
} opgroup_e;
localparam int unsigned OP_BITS = 4;
typedef enum logic [OP_BITS-1:0] {
FMADD, FNMSUB, ADD, MUL, // ADDMUL operation group
DIV, SQRT, // DIVSQRT operation group
SGNJ, MINMAX, CMP, CLASSIFY, // NONCOMP operation group
F2F, F2I, I2F, CPKAB, CPKCD // CONV operation group
} operation_e;
// -------------------
// RISC-V FP-SPECIFIC
// -------------------
// Rounding modes
typedef enum logic [2:0] {
RNE = 3'b000,
RTZ = 3'b001,
RDN = 3'b010,
RUP = 3'b011,
RMM = 3'b100,
ROD = 3'b101, // This mode is not defined in RISC-V FP-SPEC
DYN = 3'b111
} roundmode_e;
// Status flags
typedef struct packed {
logic NV; // Invalid
logic DZ; // Divide by zero
logic OF; // Overflow
logic UF; // Underflow
logic NX; // Inexact
} status_t;
// Information about a floating point value
typedef struct packed {
logic is_normal; // is the value normal
logic is_subnormal; // is the value subnormal
logic is_zero; // is the value zero
logic is_inf; // is the value infinity
logic is_nan; // is the value NaN
logic is_signalling; // is the value a signalling NaN
logic is_quiet; // is the value a quiet NaN
logic is_boxed; // is the value properly NaN-boxed (RISC-V specific)
} fp_info_t;
// Classification mask
typedef enum logic [9:0] {
NEGINF = 10'b00_0000_0001,
NEGNORM = 10'b00_0000_0010,
NEGSUBNORM = 10'b00_0000_0100,
NEGZERO = 10'b00_0000_1000,
POSZERO = 10'b00_0001_0000,
POSSUBNORM = 10'b00_0010_0000,
POSNORM = 10'b00_0100_0000,
POSINF = 10'b00_1000_0000,
SNAN = 10'b01_0000_0000,
QNAN = 10'b10_0000_0000
} classmask_e;
// ------------------
// FPU configuration
// ------------------
// Pipelining registers can be inserted (at elaboration time) into operational units
typedef enum logic [1:0] {
BEFORE, // registers are inserted at the inputs of the unit
AFTER, // registers are inserted at the outputs of the unit
INSIDE, // registers are inserted at predetermined (suboptimal) locations in the unit
DISTRIBUTED // registers are evenly distributed, INSIDE >= AFTER >= BEFORE
} pipe_config_t;
// Arithmetic units can be arranged in parallel (per format), merged (multi-format) or not at all.
typedef enum logic [1:0] {
DISABLED, // arithmetic units are not generated
PARALLEL, // arithmetic units are generated in prallel slices, one for each format
MERGED // arithmetic units are contained within a merged unit holding multiple formats
} unit_type_t;
// Array of unit types indexed by format
typedef unit_type_t [0:NUM_FP_FORMATS-1] fmt_unit_types_t;
// Array of format-specific unit types by opgroup
typedef fmt_unit_types_t [0:NUM_OPGROUPS-1] opgrp_fmt_unit_types_t;
// same with unsigned
typedef fmt_unsigned_t [0:NUM_OPGROUPS-1] opgrp_fmt_unsigned_t;
// FPU configuration: features
typedef struct packed {
int unsigned Width;
logic EnableVectors;
logic EnableNanBox;
fmt_logic_t FpFmtMask;
ifmt_logic_t IntFmtMask;
} fpu_features_t;
localparam fpu_features_t RV64D = '{
Width: 64,
EnableVectors: 1'b0,
EnableNanBox: 1'b1,
FpFmtMask: 5'b11000,
IntFmtMask: 4'b0011
};
localparam fpu_features_t RV32D = '{
Width: 64,
EnableVectors: 1'b1,
EnableNanBox: 1'b1,
FpFmtMask: 5'b11000,
IntFmtMask: 4'b0010
};
localparam fpu_features_t RV32F = '{
Width: 32,
EnableVectors: 1'b0,
EnableNanBox: 1'b1,
FpFmtMask: 5'b10000,
IntFmtMask: 4'b0010
};
localparam fpu_features_t RV64D_Xsflt = '{
Width: 64,
EnableVectors: 1'b1,
EnableNanBox: 1'b1,
FpFmtMask: 5'b11111,
IntFmtMask: 4'b1111
};
localparam fpu_features_t RV32F_Xsflt = '{
Width: 32,
EnableVectors: 1'b1,
EnableNanBox: 1'b1,
FpFmtMask: 5'b10111,
IntFmtMask: 4'b1110
};
localparam fpu_features_t RV32F_Xf16alt_Xfvec = '{
Width: 32,
EnableVectors: 1'b1,
EnableNanBox: 1'b1,
FpFmtMask: 5'b10001,
IntFmtMask: 4'b0110
};
// FPU configuraion: implementation
typedef struct packed {
opgrp_fmt_unsigned_t PipeRegs;
opgrp_fmt_unit_types_t UnitTypes;
pipe_config_t PipeConfig;
} fpu_implementation_t;
localparam fpu_implementation_t DEFAULT_NOREGS = '{
PipeRegs: '{default: 0},
UnitTypes: '{'{default: PARALLEL}, // ADDMUL
'{default: MERGED}, // DIVSQRT
'{default: PARALLEL}, // NONCOMP
'{default: MERGED}}, // CONV
PipeConfig: BEFORE
};
localparam fpu_implementation_t DEFAULT_SNITCH = '{
PipeRegs: '{default: 1},
UnitTypes: '{'{default: PARALLEL}, // ADDMUL
'{default: DISABLED}, // DIVSQRT
'{default: PARALLEL}, // NONCOMP
'{default: MERGED}}, // CONV
PipeConfig: BEFORE
};
// -----------------------
// Synthesis optimization
// -----------------------
localparam logic DONT_CARE = 1'b1; // the value to assign as don't care
// -------------------------
// General helper functions
// -------------------------
function automatic int minimum(int a, int b);
return (a < b) ? a : b;
endfunction
function automatic int maximum(int a, int b);
return (a > b) ? a : b;
endfunction
// -------------------------------------------
// Helper functions for FP formats and values
// -------------------------------------------
// Returns the width of a FP format
function automatic int unsigned fp_width(fp_format_e fmt);
return FP_ENCODINGS[fmt].exp_bits + FP_ENCODINGS[fmt].man_bits + 1;
endfunction
// Returns the widest FP format present
function automatic int unsigned max_fp_width(fmt_logic_t cfg);
automatic int unsigned res = 0;
for (int unsigned i = 0; i < NUM_FP_FORMATS; i++)
if (cfg[i])
res = unsigned'(maximum(res, fp_width(fp_format_e'(i))));
return res;
endfunction
// Returns the narrowest FP format present
function automatic int unsigned min_fp_width(fmt_logic_t cfg);
automatic int unsigned res = max_fp_width(cfg);
for (int unsigned i = 0; i < NUM_FP_FORMATS; i++)
if (cfg[i])
res = unsigned'(minimum(res, fp_width(fp_format_e'(i))));
return res;
endfunction
// Returns the number of expoent bits for a format
function automatic int unsigned exp_bits(fp_format_e fmt);
return FP_ENCODINGS[fmt].exp_bits;
endfunction
// Returns the number of mantissa bits for a format
function automatic int unsigned man_bits(fp_format_e fmt);
return FP_ENCODINGS[fmt].man_bits;
endfunction
// Returns the bias value for a given format (as per IEEE 754-2008)
function automatic int unsigned bias(fp_format_e fmt);
return unsigned'(2**(FP_ENCODINGS[fmt].exp_bits-1)-1); // symmetrical bias
endfunction
function automatic fp_encoding_t super_format(fmt_logic_t cfg);
automatic fp_encoding_t res;
res = '0;
for (int unsigned fmt = 0; fmt < NUM_FP_FORMATS; fmt++)
if (cfg[fmt]) begin // only active format
res.exp_bits = unsigned'(maximum(res.exp_bits, exp_bits(fp_format_e'(fmt))));
res.man_bits = unsigned'(maximum(res.man_bits, man_bits(fp_format_e'(fmt))));
end
return res;
endfunction
// -------------------------------------------
// Helper functions for INT formats and values
// -------------------------------------------
// Returns the widest INT format present
function automatic int unsigned max_int_width(ifmt_logic_t cfg);
automatic int unsigned res = 0;
for (int ifmt = 0; ifmt < NUM_INT_FORMATS; ifmt++) begin
if (cfg[ifmt]) res = maximum(res, int_width(int_format_e'(ifmt)));
end
return res;
endfunction
// --------------------------------------------------
// Helper functions for operations and FPU structure
// --------------------------------------------------
// Returns the operation group of the given operation
function automatic opgroup_e get_opgroup(operation_e op);
unique case (op)
FMADD, FNMSUB, ADD, MUL: return ADDMUL;
DIV, SQRT: return DIVSQRT;
SGNJ, MINMAX, CMP, CLASSIFY: return NONCOMP;
F2F, F2I, I2F, CPKAB, CPKCD: return CONV;
default: return NONCOMP;
endcase
endfunction
// Returns the number of operands by operation group
function automatic int unsigned num_operands(opgroup_e grp);
unique case (grp)
ADDMUL: return 3;
DIVSQRT: return 2;
NONCOMP: return 2;
CONV: return 3; // vectorial casts use 3 operands
default: return 0;
endcase
endfunction
// Returns the number of lanes according to width, format and vectors
function automatic int unsigned num_lanes(int unsigned width, fp_format_e fmt, logic vec);
return vec ? width / fp_width(fmt) : 1; // if no vectors, only one lane
endfunction
// Returns the maximum number of lanes in the FPU according to width, format config and vectors
function automatic int unsigned max_num_lanes(int unsigned width, fmt_logic_t cfg, logic vec);
return vec ? width / min_fp_width(cfg) : 1; // if no vectors, only one lane
endfunction
// Returns a mask of active FP formats that are present in lane lane_no of a multiformat slice
function automatic fmt_logic_t get_lane_formats(int unsigned width,
fmt_logic_t cfg,
int unsigned lane_no);
automatic fmt_logic_t res;
for (int unsigned fmt = 0; fmt < NUM_FP_FORMATS; fmt++)
// Mask active formats with the number of lanes for that format
res[fmt] = cfg[fmt] & (width / fp_width(fp_format_e'(fmt)) > lane_no);
return res;
endfunction
// Returns a mask of active INT formats that are present in lane lane_no of a multiformat slice
function automatic ifmt_logic_t get_lane_int_formats(int unsigned width,
fmt_logic_t cfg,
ifmt_logic_t icfg,
int unsigned lane_no);
automatic ifmt_logic_t res;
automatic fmt_logic_t lanefmts;
res = '0;
lanefmts = get_lane_formats(width, cfg, lane_no);
for (int unsigned ifmt = 0; ifmt < NUM_INT_FORMATS; ifmt++)
for (int unsigned fmt = 0; fmt < NUM_FP_FORMATS; fmt++)
// Mask active int formats with the width of the float formats
if ((fp_width(fp_format_e'(fmt)) == int_width(int_format_e'(ifmt))))
res[ifmt] |= icfg[ifmt] && lanefmts[fmt];
return res;
endfunction
// Returns a mask of active FP formats that are present in lane lane_no of a CONV slice
function automatic fmt_logic_t get_conv_lane_formats(int unsigned width,
fmt_logic_t cfg,
int unsigned lane_no);
automatic fmt_logic_t res;
for (int unsigned fmt = 0; fmt < NUM_FP_FORMATS; fmt++)
// Mask active formats with the number of lanes for that format, CPK at least twice
res[fmt] = cfg[fmt] && ((width / fp_width(fp_format_e'(fmt)) > lane_no) ||
(CPK_FORMATS[fmt] && (lane_no < 2)));
return res;
endfunction
// Returns a mask of active INT formats that are present in lane lane_no of a CONV slice
function automatic ifmt_logic_t get_conv_lane_int_formats(int unsigned width,
fmt_logic_t cfg,
ifmt_logic_t icfg,
int unsigned lane_no);
automatic ifmt_logic_t res;
automatic fmt_logic_t lanefmts;
res = '0;
lanefmts = get_conv_lane_formats(width, cfg, lane_no);
for (int unsigned ifmt = 0; ifmt < NUM_INT_FORMATS; ifmt++)
for (int unsigned fmt = 0; fmt < NUM_FP_FORMATS; fmt++)
// Mask active int formats with the width of the float formats
res[ifmt] |= icfg[ifmt] && lanefmts[fmt] &&
(fp_width(fp_format_e'(fmt)) == int_width(int_format_e'(ifmt)));
return res;
endfunction
// Return whether any active format is set as MERGED
function automatic logic any_enabled_multi(fmt_unit_types_t types, fmt_logic_t cfg);
for (int unsigned i = 0; i < NUM_FP_FORMATS; i++)
if (cfg[i] && types[i] == MERGED)
return 1'b1;
return 1'b0;
endfunction
// Return whether the given format is the first active one set as MERGED
function automatic logic is_first_enabled_multi(fp_format_e fmt,
fmt_unit_types_t types,
fmt_logic_t cfg);
for (int unsigned i = 0; i < NUM_FP_FORMATS; i++) begin
if (cfg[i] && types[i] == MERGED) return (fp_format_e'(i) == fmt);
end
return 1'b0;
endfunction
// Returns the first format that is active and is set as MERGED
function automatic fp_format_e get_first_enabled_multi(fmt_unit_types_t types, fmt_logic_t cfg);
for (int unsigned i = 0; i < NUM_FP_FORMATS; i++)
if (cfg[i] && types[i] == MERGED)
return fp_format_e'(i);
return fp_format_e'(0);
endfunction
// Returns the largest number of regs that is active and is set as MERGED
function automatic int unsigned get_num_regs_multi(fmt_unsigned_t regs,
fmt_unit_types_t types,
fmt_logic_t cfg);
automatic int unsigned res = 0;
for (int unsigned i = 0; i < NUM_FP_FORMATS; i++) begin
if (cfg[i] && types[i] == MERGED) res = maximum(res, regs[i]);
end
return res;
endfunction
endpackage