1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 scfx_ieee.h - 23 24 Original Author: Martin Janssen, Synopsys, Inc. 25 26 *****************************************************************************/ 27 28/***************************************************************************** 29 30 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 31 changes you are making here. 32 33 Name, Affiliation, Date: 34 Description of Modification: 35 36 *****************************************************************************/ 37 38// $Log: scfx_ieee.h,v $ 39// Revision 1.3 2011/08/24 22:05:43 acg 40// Torsten Maehne: initialization changes to remove warnings. 41// 42// Revision 1.2 2011/08/07 18:55:24 acg 43// Philipp A. Hartmann: added guard for __clang__ to get the clang platform 44// working. 45// 46// Revision 1.1.1.1 2006/12/15 20:20:04 acg 47// SystemC 2.3 48// 49// Revision 1.3 2006/01/13 18:53:58 acg 50// Andy Goodrich: added $Log command so that CVS comments are reproduced in 51// the source. 52// 53 54#ifndef __SYSTEMC_EXT_DT_FX_SCFX_IEEE_HH__ 55#define __SYSTEMC_EXT_DT_FX_SCFX_IEEE_HH__ 56 57#include "../../utils/endian.hh" 58#include "sc_fxdefs.hh" 59 60namespace sc_dt 61{ 62 63// classes defined in this module 64union ieee_double; 65class scfx_ieee_double; 66union ieee_float; 67class scfx_ieee_float; 68 69#define SCFX_MASK_(Size) ((1u << (Size))-1u) 70 71// ---------------------------------------------------------------------------- 72// UNION : ieee_double 73// 74// IEEE 754 double-precision format. 75// ---------------------------------------------------------------------------- 76 77union ieee_double 78{ 79 double d; 80 81 struct 82 { 83#if defined(SC_BOOST_BIG_ENDIAN) 84 unsigned negative:1; 85 unsigned exponent:11; 86 unsigned mantissa0:20; 87 unsigned mantissa1:32; 88#elif defined(SC_BOOST_LITTLE_ENDIAN) 89 unsigned mantissa1:32; 90 unsigned mantissa0:20; 91 unsigned exponent:11; 92 unsigned negative:1; 93#endif 94 } s; 95}; 96 97 98const unsigned int SCFX_IEEE_DOUBLE_BIAS = 1023U; 99 100const int SCFX_IEEE_DOUBLE_E_MAX = 1023; 101const int SCFX_IEEE_DOUBLE_E_MIN = -1022; 102 103const unsigned int SCFX_IEEE_DOUBLE_M_SIZE = 52; 104const unsigned int SCFX_IEEE_DOUBLE_M0_SIZE = 20; 105const unsigned int SCFX_IEEE_DOUBLE_M1_SIZE = 32; 106const unsigned int SCFX_IEEE_DOUBLE_E_SIZE = 11; 107 108 109// ---------------------------------------------------------------------------- 110// CLASS : scfx_ieee_double 111// 112// Convenient interface to union ieee_double. 113// ---------------------------------------------------------------------------- 114 115class scfx_ieee_double 116{ 117 ieee_double m_id; 118 public: 119 scfx_ieee_double(); 120 scfx_ieee_double(double); 121 scfx_ieee_double(const scfx_ieee_double &); 122 123 scfx_ieee_double &operator = (double); 124 scfx_ieee_double &operator = (const scfx_ieee_double &); 125 126 operator double() const; 127 128 unsigned int negative() const; 129 void negative(unsigned int); 130 int exponent() const; 131 void exponent(int); 132 unsigned int mantissa0() const; 133 void mantissa0(unsigned int); 134 unsigned int mantissa1() const; 135 void mantissa1(unsigned int); 136 137 bool is_zero() const; 138 bool is_subnormal() const; 139 bool is_normal() const; 140 bool is_inf() const; 141 bool is_nan() const; 142 143 void set_inf(); 144 void set_nan(); 145 146 int msb() const; // most significant non-zero bit 147 int lsb() const; // least significant non-zero bit 148 149 static const scfx_ieee_double nan(); 150 static const scfx_ieee_double inf(int); 151}; 152 153 154// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 155 156inline scfx_ieee_double::scfx_ieee_double() : m_id() 157{ 158 m_id.d = 0.0; 159} 160 161inline scfx_ieee_double::scfx_ieee_double(double d) : m_id() 162{ 163 m_id.d = d; 164} 165 166inline scfx_ieee_double::scfx_ieee_double(const scfx_ieee_double &a) : 167 m_id(a.m_id) 168{ 169 // m_id.d = a.m_id.d; 170} 171 172inline scfx_ieee_double & 173scfx_ieee_double::operator = (double d) 174{ 175 m_id.d = d; 176 return *this; 177} 178 179inline scfx_ieee_double & 180scfx_ieee_double::operator = (const scfx_ieee_double &a) 181{ 182 m_id.d = a.m_id.d; 183 return *this; 184} 185 186inline scfx_ieee_double::operator double() const 187{ 188 return m_id.d; 189} 190 191inline unsigned int 192scfx_ieee_double::negative() const 193{ 194 return m_id.s.negative; 195} 196 197inline void 198scfx_ieee_double::negative(unsigned int a) 199{ 200 m_id.s.negative = a & SCFX_MASK_(1); 201} 202 203inline int 204scfx_ieee_double::exponent() const 205{ 206 return m_id.s.exponent - SCFX_IEEE_DOUBLE_BIAS; 207} 208 209inline void 210scfx_ieee_double::exponent(int a) 211{ 212 m_id.s.exponent = (SCFX_IEEE_DOUBLE_BIAS + a) 213 & SCFX_MASK_(SCFX_IEEE_DOUBLE_E_SIZE); 214} 215 216inline unsigned int 217scfx_ieee_double::mantissa0() const 218{ 219 return m_id.s.mantissa0; 220} 221 222inline void 223scfx_ieee_double::mantissa0(unsigned int a) 224{ 225 m_id.s.mantissa0 = a & SCFX_MASK_(SCFX_IEEE_DOUBLE_M0_SIZE); 226} 227 228inline unsigned int 229scfx_ieee_double::mantissa1() const 230{ 231 return m_id.s.mantissa1; 232} 233 234inline void 235scfx_ieee_double::mantissa1(unsigned int a) 236{ 237 m_id.s.mantissa1 = a; // & SCFX_MASK_(SCFX_IEEE_DOUBLE_M1_SIZE); 238} 239 240inline bool 241scfx_ieee_double::is_zero() const 242{ 243 return (exponent() == SCFX_IEEE_DOUBLE_E_MIN - 1 && 244 mantissa0() == 0U && mantissa1() == 0U); 245} 246 247inline bool 248scfx_ieee_double::is_subnormal() const 249{ 250 return (exponent() == SCFX_IEEE_DOUBLE_E_MIN - 1 && 251 (mantissa0() != 0U || mantissa1() != 0U)); 252} 253 254inline bool 255scfx_ieee_double::is_normal() const 256{ 257 return (exponent() >= SCFX_IEEE_DOUBLE_E_MIN && 258 exponent() <= SCFX_IEEE_DOUBLE_E_MAX); 259} 260 261inline bool 262scfx_ieee_double::is_inf() const 263{ 264 return (exponent() == SCFX_IEEE_DOUBLE_E_MAX + 1 && 265 mantissa0() == 0U && mantissa1() == 0U); 266} 267 268inline bool 269scfx_ieee_double::is_nan() const 270{ 271 return (exponent() == SCFX_IEEE_DOUBLE_E_MAX + 1 && 272 (mantissa0() != 0U || mantissa1() != 0U)); 273} 274 275inline void 276scfx_ieee_double::set_inf() 277{ 278 exponent(SCFX_IEEE_DOUBLE_E_MAX + 1); 279 mantissa0(0U); 280 mantissa1(0U); 281} 282 283inline void 284scfx_ieee_double::set_nan() 285{ 286 exponent(SCFX_IEEE_DOUBLE_E_MAX + 1); 287 mantissa0((unsigned int)-1); 288 mantissa1((unsigned int)-1); 289} 290 291#define MSB_STATEMENT(x,n) if ( x >> n ) { x >>= n; i += n; } 292 293inline int 294scfx_ieee_double::msb() const 295{ 296 unsigned int m0 = mantissa0(); 297 unsigned int m1 = mantissa1(); 298 if (m0 != 0) { 299 int i = 0; 300 MSB_STATEMENT(m0, 16); 301 MSB_STATEMENT(m0, 8); 302 MSB_STATEMENT(m0, 4); 303 MSB_STATEMENT(m0, 2); 304 MSB_STATEMENT(m0, 1); 305 return (i - 20); 306 } else if (m1 != 0) { 307 int i = 0; 308 MSB_STATEMENT(m1, 16); 309 MSB_STATEMENT(m1, 8); 310 MSB_STATEMENT(m1, 4); 311 MSB_STATEMENT(m1, 2); 312 MSB_STATEMENT(m1, 1); 313 return (i - 52); 314 } else { 315 return 0; 316 } 317} 318 319#undef MSB_STATEMENT 320 321#define LSB_STATEMENT(x,n) if ( x << n ) { x <<= n; i -= n; } 322 323inline int 324scfx_ieee_double::lsb() const 325{ 326 unsigned int m0 = mantissa0(); 327 unsigned int m1 = mantissa1(); 328 if (m1 != 0) { 329 int i = 31; 330 LSB_STATEMENT(m1, 16); 331 LSB_STATEMENT(m1, 8); 332 LSB_STATEMENT(m1, 4); 333 LSB_STATEMENT(m1, 2); 334 LSB_STATEMENT(m1, 1); 335 return (i - 52); 336 } else if (m0 != 0) { 337 int i = 31; 338 LSB_STATEMENT(m0, 16); 339 LSB_STATEMENT(m0, 8); 340 LSB_STATEMENT(m0, 4); 341 LSB_STATEMENT(m0, 2); 342 LSB_STATEMENT(m0, 1); 343 return (i - 20); 344 } else { 345 return 0; 346 } 347} 348 349#undef LSB_STATEMENT 350 351inline const scfx_ieee_double 352scfx_ieee_double::nan() 353{ 354 scfx_ieee_double id; 355 id.set_nan(); 356 return id; 357} 358 359inline const scfx_ieee_double 360scfx_ieee_double::inf(int sign) 361{ 362 scfx_ieee_double id(sign); 363 id.set_inf(); 364 return id; 365} 366 367 368// ---------------------------------------------------------------------------- 369// UNION : ieee_float 370// 371// IEEE 754 single-precision format. 372// ---------------------------------------------------------------------------- 373 374union ieee_float 375{ 376 float f; 377 struct 378 { 379#if defined(SC_BOOST_BIG_ENDIAN) 380 unsigned negative:1; 381 unsigned exponent:8; 382 unsigned mantissa:23; 383#elif defined(SC_BOOST_LITTLE_ENDIAN) 384 unsigned mantissa:23; 385 unsigned exponent:8; 386 unsigned negative:1; 387#endif 388 } s; 389}; 390 391 392const unsigned int SCFX_IEEE_FLOAT_BIAS = 127U; 393 394const int SCFX_IEEE_FLOAT_E_MAX = 127; 395const int SCFX_IEEE_FLOAT_E_MIN = -126; 396 397const unsigned int SCFX_IEEE_FLOAT_M_SIZE = 23; 398const unsigned int SCFX_IEEE_FLOAT_E_SIZE = 8; 399 400 401// ---------------------------------------------------------------------------- 402// CLASS : scfx_ieee_float 403// 404// Convenient wrapper to union ieee_float. 405// ---------------------------------------------------------------------------- 406 407class scfx_ieee_float 408{ 409 ieee_float m_if; 410 411 public: 412 scfx_ieee_float(); 413 scfx_ieee_float(float); 414 scfx_ieee_float(const scfx_ieee_float &); 415 416 scfx_ieee_float &operator = (float); 417 scfx_ieee_float &operator = (const scfx_ieee_float &); 418 419 operator float() const; 420 421 unsigned int negative() const; 422 void negative(unsigned int); 423 int exponent() const; 424 void exponent(int); 425 unsigned int mantissa() const; 426 void mantissa(unsigned int); 427 428 bool is_zero() const; 429 bool is_subnormal() const; 430 bool is_normal() const; 431 bool is_inf() const; 432 bool is_nan() const; 433 434 void set_inf(); 435 void set_nan(); 436}; 437 438 439// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 440 441inline scfx_ieee_float::scfx_ieee_float() : m_if() 442{ 443 m_if.f = 0.0; 444} 445 446inline scfx_ieee_float::scfx_ieee_float(float f) : m_if() 447{ 448 m_if.f = f; 449} 450 451inline scfx_ieee_float::scfx_ieee_float(const scfx_ieee_float &a) : 452 m_if(a.m_if) 453{ 454 // m_if.f = a.m_if.f; 455} 456 457 458inline scfx_ieee_float & 459scfx_ieee_float::operator = (float f) 460{ 461 m_if.f = f; 462 return *this; 463} 464 465inline scfx_ieee_float & 466scfx_ieee_float::operator = (const scfx_ieee_float &a) 467{ 468 m_if.f = a.m_if.f; 469 return *this; 470} 471 472inline scfx_ieee_float::operator float() const 473{ 474 return m_if.f; 475} 476 477inline unsigned int 478scfx_ieee_float::negative() const 479{ 480 return m_if.s.negative; 481} 482 483inline void 484scfx_ieee_float::negative(unsigned int a) 485{ 486 m_if.s.negative = a & SCFX_MASK_(1); 487} 488 489inline int 490scfx_ieee_float::exponent() const 491{ 492 return m_if.s.exponent - SCFX_IEEE_FLOAT_BIAS; 493} 494 495inline void 496scfx_ieee_float::exponent(int a) 497{ 498 m_if.s.exponent = (SCFX_IEEE_FLOAT_BIAS + a) & 499 SCFX_MASK_(SCFX_IEEE_FLOAT_E_SIZE); 500} 501 502inline unsigned int 503scfx_ieee_float::mantissa() const 504{ 505 return m_if.s.mantissa; 506} 507 508inline void 509scfx_ieee_float::mantissa(unsigned int a) 510{ 511 m_if.s.mantissa = a & SCFX_MASK_(SCFX_IEEE_FLOAT_M_SIZE); 512} 513 514 515inline bool 516scfx_ieee_float::is_zero() const 517{ 518 return (exponent() == SCFX_IEEE_FLOAT_E_MIN - 1 && mantissa() == 0U); 519} 520 521inline bool 522scfx_ieee_float::is_subnormal() const 523{ 524 return (exponent() == SCFX_IEEE_FLOAT_E_MIN - 1 && mantissa() != 0U); 525} 526 527inline bool 528scfx_ieee_float::is_normal() const 529{ 530 return (exponent() >= SCFX_IEEE_FLOAT_E_MIN && 531 exponent() <= SCFX_IEEE_FLOAT_E_MAX); 532} 533 534inline bool 535scfx_ieee_float::is_inf() const 536{ 537 return (exponent() == SCFX_IEEE_FLOAT_E_MAX + 1 && mantissa() == 0U); 538} 539 540inline bool 541scfx_ieee_float::is_nan() const 542{ 543 return (exponent() == SCFX_IEEE_FLOAT_E_MAX + 1 && mantissa() != 0U); 544} 545 546inline void 547scfx_ieee_float::set_inf() 548{ 549 exponent(SCFX_IEEE_FLOAT_E_MAX + 1); 550 mantissa(0U); 551} 552 553inline void 554scfx_ieee_float::set_nan() 555{ 556 exponent(SCFX_IEEE_FLOAT_E_MAX + 1); 557 mantissa((unsigned int)-1); 558} 559 560 561// ---------------------------------------------------------------------------- 562// FUNCTION : scfx_pow2 563// 564// Computes 2.0**exp in double-precision. 565// ---------------------------------------------------------------------------- 566 567inline double 568scfx_pow2(int exp) 569{ 570 scfx_ieee_double r; 571 if (exp < SCFX_IEEE_DOUBLE_E_MIN) { 572 r = 0.0; 573 // handle subnormal case 574 exp -= SCFX_IEEE_DOUBLE_E_MIN; 575 if ((exp += 20) >= 0) { 576 r.mantissa0(1U << exp); 577 } else if ((exp += 32) >= 0) { 578 r.mantissa1(1U << exp); 579 } 580 } else if (exp > SCFX_IEEE_DOUBLE_E_MAX) { 581 r.set_inf(); 582 } else { 583 r = 1.0; 584 r.exponent(exp); 585 } 586 return r; 587} 588 589 590// ---------------------------------------------------------------------------- 591// FUNCTION : uint64_to_double 592// 593// Platform independent conversion from double uint64 to double. 594// Needed because VC++6 doesn't support this conversion. 595// ---------------------------------------------------------------------------- 596 597inline double 598uint64_to_double(uint64 a) 599{ 600#if defined(__clang__) 601 // conversion from uint64 to double not implemented; use int64 602 double tmp = static_cast<double>(static_cast<int64>(a)); 603 return (tmp >= 0) ? tmp : tmp + sc_dt::scfx_pow2(64); 604#else 605 return static_cast<double>(a); 606#endif 607} 608 609} // namespace sc_dt 610 611#undef SCFX_MASK_ 612 613#endif // __SYSTEMC_EXT_DT_FX_SCFX_IEEE_HH__ 614