1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #ifndef NST_CORE_H 26 #define NST_CORE_H 27 28 #include <cstddef> 29 30 #ifndef NST_BASE_H 31 #include "NstBase.hpp" 32 #endif 33 34 #ifdef NST_PRAGMA_ONCE 35 #pragma once 36 #endif 37 38 #if defined(_WIN32) || defined(WIN32) || defined(__WIN32__) 39 #define NST_WIN32 40 #endif 41 42 #if NST_MSVC 43 44 #pragma warning( disable : 4018 4100 4127 4244 4245 4308 4309 4310 4512 4800 4996 ) 45 46 #if NST_MSVC >= 800 47 48 #ifdef NST_WIN32 49 #define NST_FASTCALL __fastcall 50 #define NST_REGCALL NST_FASTCALL 51 #endif 52 53 #if NST_MSVC >= 1200 54 55 #ifndef NST_FASTDELEGATE 56 #define NST_FASTDELEGATE 57 #endif 58 59 #ifndef _DEBUG 60 #define NST_MSVC_OPTIMIZE 61 #define NST_FORCE_INLINE __forceinline 62 #pragma inline_depth( 255 ) 63 #pragma inline_recursion( on ) 64 #endif 65 66 #define NST_SINGLE_CALL __forceinline 67 68 #if NST_MSVC >= 1300 69 70 #ifndef NST_NO_INLINE 71 #define NST_NO_INLINE __declspec(noinline) 72 #endif 73 74 #ifndef NST_ASSUME 75 #define NST_ASSUME(x_) __assume(x_) 76 #endif 77 78 #ifndef NST_DEBUG 79 #define NST_UNREACHABLE() __assume(0) 80 #endif 81 82 #if !defined(NST_MM_INTRINSICS) && defined(NST_WIN32) && defined(_M_IX86) 83 #define NST_MM_INTRINSICS 84 #endif 85 86 #define NST_NO_VTABLE __declspec(novtable) 87 88 #if NST_MSVC >= 1400 89 90 #ifndef NST_RESTRICT 91 #define NST_RESTRICT __restrict 92 #endif 93 94 #pragma warning( default : 4191 4263 4287 4289 4296 4350 4545 4546 4547 4549 4555 4557 4686 4836 4905 4906 4928 4946 ) 95 96 #if 0 97 #pragma warning( default : 4820 ) // byte padding on structs 98 #pragma warning( default : 4710 ) // function not inlined 99 #pragma warning( default : 4711 ) // function auto inlined 100 #pragma warning( default : 4100 ) // unreferenced parameter 101 #endif 102 103 #endif 104 105 #endif 106 107 #endif 108 109 #endif 110 111 #elif NST_GCC 112 113 #if NST_GCC >= 291 114 115 #ifndef NST_RESTRICT 116 #define NST_RESTRICT __restrict__ 117 #endif 118 119 #if NST_GCC >= 301 120 121 #ifndef NST_NO_INLINE 122 #define NST_NO_INLINE __attribute__((noinline)) 123 #endif 124 125 // Commenting this fixes a lot of warnings on newer versions of GCC 126 // #define NST_SINGLE_CALL __attribute__((always_inline)) 127 128 #if (NST_GCC >= 304) && defined(__i386__) 129 #define NST_REGCALL __attribute__((regparm(2))) 130 #endif 131 132 #endif 133 134 #endif 135 136 #endif 137 138 #if NST_ICC 139 140 #pragma warning( disable : 11 69 304 373 383 444 810 869 981 1418 1572 1599 1786 ) 141 142 #if !defined(NST_RESTRICT) && NST_ICC >= 810 143 #define NST_RESTRICT restrict 144 #endif 145 146 #endif 147 148 #define NST_NOP() ((void)0) 149 150 #ifndef NST_FORCE_INLINE 151 #define NST_FORCE_INLINE inline 152 #endif 153 154 #ifndef NST_SINGLE_CALL 155 #define NST_SINGLE_CALL NST_FORCE_INLINE 156 #endif 157 158 #ifndef NST_NO_INLINE 159 #define NST_NO_INLINE 160 #endif 161 162 #ifndef NST_ASSUME 163 #define NST_ASSUME(x_) NST_NOP() 164 #endif 165 166 #ifndef NST_NO_VTABLE 167 #define NST_NO_VTABLE 168 #endif 169 170 #ifndef NST_RESTRICT 171 #define NST_RESTRICT 172 #endif 173 174 #ifndef NST_UNREACHABLE 175 #define NST_UNREACHABLE() NST_ASSERT(0) 176 #endif 177 178 #ifndef NST_FASTCALL 179 #define NST_FASTCALL 180 #endif 181 182 #ifndef NST_REGCALL 183 #define NST_REGCALL 184 #endif 185 186 #define NST_MIN(x_,y_) ((x_) < (y_) ? (x_) : (y_)) 187 #define NST_MAX(x_,y_) ((x_) < (y_) ? (y_) : (x_)) 188 189 #define NST_COMMA , 190 191 #define NST_CAT_NEXT(x_,y_) x_##y_ 192 #define NST_CAT(x_,y_) NST_CAT_NEXT(x_,y_) 193 194 #define NST_COMPILE_ASSERT(expr_) typedef char NST_CAT(Nestopia_assertion_at_line_,__LINE__)[(expr_) ? 1 : -1] 195 196 namespace Nes 197 { 198 namespace Core 199 { 200 typedef const char* cstring; 201 typedef const wchar_t* wcstring; 202 typedef uint ibool; 203 typedef uint Data; 204 typedef uint Address; 205 typedef dword Cycle; 206 207 template<typename T,dword N> 208 char(& array(T(&)[N]))[N]; 209 210 namespace Helper 211 { 212 template<ulong W> struct CountBits 213 { 214 enum { VALUE = 1 + CountBits<W / 2>::VALUE }; 215 }; 216 217 template<> struct CountBits<1UL> 218 { 219 enum { VALUE = 1 }; 220 }; 221 222 template<> struct CountBits<0UL> 223 { 224 enum { VALUE = 0 }; 225 }; 226 227 template<typename T,bool> 228 struct ShiftSigned 229 { LeftNes::Core::Helper::ShiftSigned230 static long Left(T v,uint c) 231 { 232 return v << c; 233 } 234 RightNes::Core::Helper::ShiftSigned235 static long Right(T v,uint c) 236 { 237 return v >> c; 238 } 239 }; 240 241 template<typename T> 242 struct ShiftSigned<T,false> 243 { LeftNes::Core::Helper::ShiftSigned244 static long Left(T v,uint c) 245 { 246 return (v >= 0) ? +long(ulong(v) << c) : -long(ulong(-v) << c); 247 } 248 RightNes::Core::Helper::ShiftSigned249 static long Right(T v,uint c) 250 { 251 return (v >= 0) ? +long(ulong(v) >> c) : -long(ulong(-v) >> c); 252 } 253 }; 254 255 template<typename T,bool> 256 struct SignExtend8 257 { ConvertNes::Core::Helper::SignExtend8258 static T Convert(T v) 259 { 260 return schar(v); 261 } 262 }; 263 264 template<typename T> 265 struct SignExtend8<T,false> 266 { ConvertNes::Core::Helper::SignExtend8267 static T Convert(T v) 268 { 269 return (v & 1U << 7) ? (v | ~0UL << 7) : v; 270 } 271 }; 272 } 273 274 template<ulong V> struct ValueBits 275 { 276 enum { VALUE = Helper::CountBits<V>::VALUE }; 277 }; 278 279 template<typename T> signed_shl(T v,uint c)280 inline long signed_shl(T v,uint c) 281 { 282 enum {NATIVE = -(T(7) << 1) == -14}; 283 return Helper::ShiftSigned<T,NATIVE>::Left( v, c ); 284 } 285 286 template<typename T> signed_shr(T v,uint c)287 inline long signed_shr(T v,uint c) 288 { 289 enum {NATIVE = -(T(7) >> 1) == -4 || -(T(7) >> 1) == -3}; 290 return Helper::ShiftSigned<T,NATIVE>::Right( v, c ); 291 } 292 293 template<typename T> sign_extend_8(T v)294 inline T sign_extend_8(T v) 295 { 296 enum {NATIVE = CHAR_BIT == 8 && UCHAR_MAX == 0xFF && SCHAR_MIN == -128 && SCHAR_MAX == 127 && T(-2) == T(~1UL)}; 297 return Helper::SignExtend8<T,NATIVE>::Convert( v ); 298 } 299 300 template<idword Min,idword Max> Clamp(idword value)301 inline idword Clamp(idword value) 302 { 303 return (value <= Max) ? (value >= Min) ? value : Min : Max; 304 } 305 306 enum 307 { 308 SIZE_1K = 0x400, 309 SIZE_2K = 0x800, 310 SIZE_4K = 0x1000, 311 SIZE_5K = 0x1400, 312 SIZE_6K = 0x1800, 313 SIZE_8K = 0x2000, 314 SIZE_16K = 0x4000, 315 SIZE_32K = 0x8000, 316 SIZE_40K = 0xA000, 317 SIZE_64K = 0x10000, 318 SIZE_128K = 0x20000, 319 SIZE_256K = 0x40000, 320 SIZE_512K = 0x80000, 321 SIZE_1024K = 0x100000, 322 SIZE_2048K = 0x200000, 323 SIZE_3072K = 0x300000, 324 SIZE_4096K = 0x400000, 325 SIZE_8192K = 0x800000, 326 SIZE_16384K = 0x1000000 327 }; 328 329 template<char T> 330 struct Ascii 331 { 332 enum 333 { 334 V = ( T >= 'a' && T <= 'z') ? T - 'a' + 0x61 : 335 ( T >= 'A' && T <= 'Z') ? T - 'A' + 0x41 : 336 ( T >= '0' && T <= '9') ? T - '0' + 0x30 : 337 ( T == '\0' ) ? 0x00 : 338 ( T == ' ' ) ? 0x20 : 339 ( T == '!' ) ? 0x21 : 340 ( T == '#' ) ? 0x23 : 341 ( T == '%' ) ? 0x25 : 342 ( T == '^' ) ? 0x5E : 343 ( T == '&' ) ? 0x26 : 344 ( T == '*' ) ? 0x2A : 345 ( T == '(' ) ? 0x28 : 346 ( T == ')' ) ? 0x29 : 347 ( T == '-' ) ? 0x2D : 348 ( T == '_' ) ? 0x5F : 349 ( T == '+' ) ? 0x2B : 350 ( T == '=' ) ? 0x3D : 351 ( T == '~' ) ? 0x7E : 352 ( T == '[' ) ? 0x5B : 353 ( T == ']' ) ? 0x5D : 354 ( T == '\\' ) ? 0x5C : 355 ( T == '|' ) ? 0x7C : 356 ( T == ';' ) ? 0x3B : 357 ( T == ':' ) ? 0x3A : 358 ( T == '\'' ) ? 0x27 : 359 ( T == '\"' ) ? 0x22 : 360 ( T == '{' ) ? 0x7B : 361 ( T == '}' ) ? 0x7D : 362 ( T == ',' ) ? 0x2C : 363 ( T == '.' ) ? 0x2E : 364 ( T == '<' ) ? 0x3C : 365 ( T == '>' ) ? 0x3E : 366 ( T == '/' ) ? 0x2F : 367 ( T == '?' ) ? 0x3F : 368 ( T == '\a' ) ? 0x07 : 369 ( T == '\b' ) ? 0x08 : 370 ( T == '\t' ) ? 0x09 : 371 ( T == '\v' ) ? 0x0B : 372 ( T == '\n' ) ? 0x0A : 373 ( T == '\r' ) ? 0x0D : 374 ( T == '\f' ) ? 0x0C : 0xFF 375 }; 376 377 NST_COMPILE_ASSERT( V != 0xFF ); 378 }; 379 380 template<char A,char B,char C=0,char D=0> 381 struct AsciiId 382 { 383 enum 384 { 385 V = 386 ( 387 dword( Ascii<A>::V ) << 0 | 388 dword( Ascii<B>::V ) << 8 | 389 dword( Ascii<C>::V ) << 16 | 390 dword( Ascii<D>::V ) << 24 391 ) 392 }; 393 RNes::Core::AsciiId394 static dword R(byte a,byte b=0,byte c=0,byte d=0) 395 { 396 return 397 ( 398 dword( Ascii<A>::V + a ) << 0 | 399 dword( Ascii<B>::V + b ) << 8 | 400 dword( Ascii<C>::V + c ) << 16 | 401 dword( Ascii<D>::V + d ) << 24 402 ); 403 } 404 }; 405 406 template<typename T,typename U> StringCompare(const T * a,const U * b)407 int StringCompare(const T* a,const U* b) 408 { 409 do 410 { 411 const wchar_t v[] = 412 { 413 (*a < L'a' || *a > L'z') ? *a : (L'A' + (*a - L'a')), 414 (*b < L'a' || *b > L'z') ? *b : (L'A' + (*b - L'a')) 415 }; 416 417 if (v[0] < v[1]) 418 return -1; 419 420 if (v[0] > v[1]) 421 return +1; 422 } 423 while (++b, *a++); 424 425 return 0; 426 } 427 428 template<typename T,typename U> StringCompare(const T * a,const U * b,uint l)429 int StringCompare(const T* a,const U* b,uint l) 430 { 431 for (; l--; ++a, ++b) 432 { 433 const wchar_t v[] = 434 { 435 (*a < L'a' || *a > L'z') ? *a : (L'A' + (*a - L'a')), 436 (*b < L'a' || *b > L'z') ? *b : (L'A' + (*b - L'a')) 437 }; 438 439 if (v[0] < v[1]) 440 return -1; 441 442 if (v[0] > v[1]) 443 return +1; 444 445 if (!v[0]) 446 return 0; 447 } 448 449 return 0; 450 } 451 } 452 453 #ifdef NST_U64 454 455 typedef NST_U64 qaword; 456 #define NST_NATIVE_QWORD 457 458 #elif (ULONG_MAX > 0xFFFFFFFF) && (ULONG_MAX / 0xFFFFFFFF - 1 > 0xFFFFFFFF) 459 460 typedef unsigned long qaword; 461 #define NST_NATIVE_QWORD 462 463 #elif (defined(ULLONG_MAX) && (ULLONG_MAX > 0xFFFFFFFF) && (ULLONG_MAX / 0xFFFFFFFF - 1 > 0xFFFFFFFF)) || (NST_GCC >= 300) 464 465 #if NST_GCC 466 __extension__ typedef unsigned long long qaword; 467 #else 468 typedef unsigned long long qaword; 469 #endif 470 #define NST_NATIVE_QWORD 471 472 #elif defined(_UI64_MAX) && (NST_MSVC >= 900 || NST_BCB >= 0x530) 473 474 typedef unsigned __int64 qaword; 475 #define NST_NATIVE_QWORD 476 477 #else 478 479 class qaword 480 { 481 void Multiply(qaword); 482 static void Divide(qaword&,const qaword,bool); 483 void Shl(uint); 484 void Shr(uint); 485 486 enum 487 { 488 LO_MASK = 0xFFFFFFFF, 489 LO_MSB = 0x80000000 490 }; 491 492 dword lo; 493 dword hi; 494 495 public: 496 qaword()497 qaword() {} 498 qaword(dword v)499 qaword(dword v) 500 : lo(v), hi(0) {} 501 qaword(dword msdw,dword lsdw)502 qaword(dword msdw,dword lsdw) 503 : lo(lsdw), hi(msdw) {} 504 qaword(const qaword & v)505 qaword(const qaword& v) 506 : lo(v.lo), hi(v.hi) {} 507 508 template<typename V> operator =(const V & v)509 qaword& operator = (const V& v) 510 { 511 lo = v; 512 hi = 0; 513 return *this; 514 } 515 operator =(const qaword & v)516 qaword& operator = (const qaword& v) 517 { 518 lo = v.lo; 519 hi = v.hi; 520 return *this; 521 } 522 523 template<typename V> operator +=(const V & v)524 qaword& operator += (const V& v) 525 { 526 dword t = lo; 527 lo = (lo + v) & LO_MASK; 528 hi = (hi + (t > lo)) & LO_MASK; 529 return *this; 530 } 531 532 template<typename V> operator -=(const V & v)533 qaword& operator -= (const V& v) 534 { 535 dword t = lo; 536 lo = (lo - v) & LO_MASK; 537 hi = (hi - (t < lo)) & LO_MASK; 538 return *this; 539 } 540 operator ++(int)541 qaword operator ++ (int) 542 { 543 qaword t; 544 t.lo = lo; 545 lo = (lo + 1) & LO_MASK; 546 t.hi = hi; 547 hi = (hi + (t.lo > lo)) & LO_MASK; 548 return t; 549 } 550 operator ++()551 qaword& operator ++ () 552 { 553 dword t = lo; 554 lo = (lo + 1) & LO_MASK; 555 hi = (hi + (t > lo)) & LO_MASK; 556 return *this; 557 } 558 operator --(int)559 qaword operator -- (int) 560 { 561 qaword t; 562 t.lo = lo; 563 lo = (lo - 1) & LO_MASK; 564 t.hi = hi; 565 hi = (hi - (t.lo < lo)) & LO_MASK; 566 return t; 567 } 568 operator --()569 qaword& operator -- () 570 { 571 dword t = lo; 572 lo = (lo - 1) & LO_MASK; 573 hi = (hi - (t < lo)) & LO_MASK; 574 return *this; 575 } 576 577 template<typename V> operator *=(const V & v)578 qaword& operator *= (const V& v) 579 { 580 if (!(((lo | v) & 0xFFFF0000) | hi)) 581 lo = (lo * v) & LO_MASK; 582 else 583 Multiply( qaword(v) ); 584 585 return *this; 586 } 587 588 template<typename V> operator /=(const V & v)589 qaword& operator /= (const V& v) 590 { 591 if (!hi) 592 lo /= v; 593 else 594 Divide( *this, qaword(v), false ); 595 596 return *this; 597 } 598 599 template<typename V> operator %=(const V & v)600 qaword& operator %= (const V& v) 601 { 602 if (!hi) 603 lo %= v; 604 else 605 Divide( *this, qaword(v), true ); 606 607 return *this; 608 } 609 operator +(const V & v) const610 template<typename V> qaword operator + (const V& v) const { return qaword(*this) += v; } operator -(const V & v) const611 template<typename V> qaword operator - (const V& v) const { return qaword(*this) -= v; } operator *(const V & v) const612 template<typename V> qaword operator * (const V& v) const { return qaword(*this) *= v; } operator /(const V & v) const613 template<typename V> qaword operator / (const V& v) const { return qaword(*this) /= v; } operator %(const V & v) const614 template<typename V> qaword operator % (const V& v) const { return qaword(*this) %= v; } 615 operator |=(const V & v)616 template<typename V> qaword& operator |= (const V& v) { lo |= v; return *this; } operator &=(const V & v)617 template<typename V> qaword& operator &= (const V& v) { lo &= v; hi = 0; return *this; } operator ^=(const V & v)618 template<typename V> qaword& operator ^= (const V& v) { lo ^= v; return *this; } 619 operator |(const V & v) const620 template<typename V> qaword operator | (const V& v) const { return qaword( hi, lo | v ); } operator &(const V & v) const621 template<typename V> qaword operator & (const V& v) const { return qaword( lo & v ); } operator ^(const V & v) const622 template<typename V> qaword operator ^ (const V& v) const { return qaword( hi, lo ^ v ); } 623 operator >>=(const V & v)624 template<typename V> qaword& operator >>= (const V& v) { Shr(v); return *this; } operator <<=(const V & v)625 template<typename V> qaword& operator <<= (const V& v) { Shl(v); return *this; } 626 operator >>(const V & v) const627 template<typename V> qaword operator >> (const V& v) const { return qaword(*this) >>= v; } operator <<(const V & v) const628 template<typename V> qaword operator << (const V& v) const { return qaword(*this) <<= v; } 629 operator ~() const630 qaword operator ~() const 631 { 632 return qaword( hi ^ LO_MASK, lo ^ LO_MASK ); 633 } 634 635 template<typename V> operator ==(const V & v) const636 bool operator == (const V& v) const 637 { 638 return !((lo - v) | hi); 639 } 640 641 template<typename V> operator <(const V & v) const642 bool operator < (const V& v) const 643 { 644 return (lo < v && !hi); 645 } 646 647 template<typename V> operator <=(const V & v) const648 bool operator <= (const V& v) const 649 { 650 return (lo <= v && !hi); 651 } 652 653 template<typename V> operator !=(const V & v) const654 bool operator != (const V& v) const 655 { 656 return !(*this == v); 657 } 658 659 template<typename V> operator >(const V & v) const660 bool operator > (const V& v) const 661 { 662 return !(*this <= v); 663 } 664 665 template<typename V> operator >=(const V & v) const666 bool operator >= (const V& v) const 667 { 668 return !(*this < v); 669 } 670 operator !() const671 bool operator !() const 672 { 673 return !(lo|hi); 674 } 675 operator bool() const676 operator bool() const 677 { 678 return (lo|hi); 679 } 680 operator int() const681 operator int () const { return lo; } operator uint() const682 operator uint () const { return lo; } operator char() const683 operator char () const { return lo; } operator schar() const684 operator schar () const { return lo; } operator uchar() const685 operator uchar () const { return lo; } operator short() const686 operator short () const { return lo; } operator ushort() const687 operator ushort () const { return lo; } operator long() const688 operator long () const { return lo; } operator ulong() const689 operator ulong () const { return lo; } 690 }; 691 692 template<> operator +=(const qaword & v)693 inline qaword& qaword::operator += (const qaword& v) 694 { 695 dword t = lo; 696 lo = (lo + v.lo) & LO_MASK; 697 hi = (hi + (t > lo) + v.hi) & LO_MASK; 698 return *this; 699 } 700 701 template<> operator -=(const qaword & v)702 inline qaword& qaword::operator -= (const qaword& v) 703 { 704 dword t = lo; 705 lo = (lo - v.lo) & LO_MASK; 706 hi = (hi - ((t < lo) + v.hi)) & LO_MASK; 707 return *this; 708 } 709 710 template<> operator *=(const qaword & v)711 inline qaword& qaword::operator *= (const qaword& v) 712 { 713 Multiply( v ); 714 return *this; 715 } 716 717 template<> operator /=(const qaword & v)718 inline qaword& qaword::operator /= (const qaword& v) 719 { 720 if (hi | v.hi) 721 Divide( *this, v, false ); 722 else 723 lo /= v.lo; 724 725 return *this; 726 } 727 728 template<> operator %=(const qaword & v)729 inline qaword& qaword::operator %= (const qaword& v) 730 { 731 Divide( *this, v, true ); 732 return *this; 733 } 734 operator |=(const qaword & v)735 template<> inline qaword& qaword::operator |= (const qaword& v) { lo |= v.lo; hi |= v.hi; return *this; } operator &=(const qaword & v)736 template<> inline qaword& qaword::operator &= (const qaword& v) { lo &= v.lo; hi &= v.hi; return *this; } operator ^=(const qaword & v)737 template<> inline qaword& qaword::operator ^= (const qaword& v) { lo ^= v.lo; hi ^= v.hi; return *this; } 738 operator |(const qaword & v) const739 template<> inline qaword qaword::operator | (const qaword& v) const { return qaword( hi | v.hi, lo | v.lo ); } operator &(const qaword & v) const740 template<> inline qaword qaword::operator & (const qaword& v) const { return qaword( hi & v.hi, lo & v.lo ); } operator ^(const qaword & v) const741 template<> inline qaword qaword::operator ^ (const qaword& v) const { return qaword( hi ^ v.hi, lo ^ v.lo ); } 742 743 template<> operator ==(const qaword & v) const744 inline bool qaword::operator == (const qaword& v) const 745 { 746 return !((lo - v.lo) | (hi - v.hi)); 747 } 748 749 template<> operator <(const qaword & v) const750 inline bool qaword::operator < (const qaword& v) const 751 { 752 return (hi < v.hi) || (lo < v.lo && hi == v.hi); 753 } 754 755 template<> operator <=(const qaword & v) const756 inline bool qaword::operator <= (const qaword& v) const 757 { 758 return (hi < v.hi) || (hi == v.hi ? (lo <= v.lo) : false); 759 } 760 761 #endif 762 } 763 764 #endif 765