nestopia/source/core/NstCore.hpp
rdanbrook a85f7744d3 Fix compiling in C++14 mode
* Left shifting a negative signed is undefined behaviour
* Fix incorrect printf() specifiers found with -Wformat
* GTK Wayland needs to be handled conditionally
2016-12-31 18:21:18 +02:00

764 lines
17 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////////////
#ifndef NST_CORE_H
#define NST_CORE_H
#include <cstddef>
#ifndef NST_BASE_H
#include "NstBase.hpp"
#endif
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
#if defined(_WIN32) || defined(WIN32) || defined(__WIN32__)
#define NST_WIN32
#endif
#if NST_MSVC
#pragma warning( disable : 4018 4100 4127 4244 4245 4308 4309 4310 4512 4800 4996 )
#if NST_MSVC >= 800
#ifdef NST_WIN32
#define NST_FASTCALL __fastcall
#define NST_REGCALL NST_FASTCALL
#endif
#if NST_MSVC >= 1200
#ifndef NST_FASTDELEGATE
#define NST_FASTDELEGATE
#endif
#ifndef _DEBUG
#define NST_MSVC_OPTIMIZE
#define NST_FORCE_INLINE __forceinline
#pragma inline_depth( 255 )
#pragma inline_recursion( on )
#endif
#define NST_SINGLE_CALL __forceinline
#if NST_MSVC >= 1300
#ifndef NST_NO_INLINE
#define NST_NO_INLINE __declspec(noinline)
#endif
#ifndef NST_ASSUME
#define NST_ASSUME(x_) __assume(x_)
#endif
#ifndef NST_DEBUG
#define NST_UNREACHABLE() __assume(0)
#endif
#if !defined(NST_MM_INTRINSICS) && defined(NST_WIN32) && defined(_M_IX86)
#define NST_MM_INTRINSICS
#endif
#define NST_NO_VTABLE __declspec(novtable)
#if NST_MSVC >= 1400
#ifndef NST_RESTRICT
#define NST_RESTRICT __restrict
#endif
#pragma warning( default : 4191 4263 4287 4289 4296 4350 4545 4546 4547 4549 4555 4557 4686 4836 4905 4906 4928 4946 )
#if 0
#pragma warning( default : 4820 ) // byte padding on structs
#pragma warning( default : 4710 ) // function not inlined
#pragma warning( default : 4711 ) // function auto inlined
#pragma warning( default : 4100 ) // unreferenced parameter
#endif
#endif
#endif
#endif
#endif
#elif NST_GCC
#if NST_GCC >= 291
#ifndef NST_RESTRICT
#define NST_RESTRICT __restrict__
#endif
#if NST_GCC >= 301
#ifndef NST_NO_INLINE
#define NST_NO_INLINE __attribute__((noinline))
#endif
// Commenting this fixes a lot of warnings on newer versions of GCC
// #define NST_SINGLE_CALL __attribute__((always_inline))
#if (NST_GCC >= 304) && defined(__i386__)
#define NST_REGCALL __attribute__((regparm(2)))
#endif
#endif
#endif
#endif
#if NST_ICC
#pragma warning( disable : 11 69 304 373 383 444 810 869 981 1418 1572 1599 1786 )
#if !defined(NST_RESTRICT) && NST_ICC >= 810
#define NST_RESTRICT restrict
#endif
#endif
#define NST_NOP() ((void)0)
#ifndef NST_FORCE_INLINE
#define NST_FORCE_INLINE inline
#endif
#ifndef NST_SINGLE_CALL
#define NST_SINGLE_CALL NST_FORCE_INLINE
#endif
#ifndef NST_NO_INLINE
#define NST_NO_INLINE
#endif
#ifndef NST_ASSUME
#define NST_ASSUME(x_) NST_NOP()
#endif
#ifndef NST_NO_VTABLE
#define NST_NO_VTABLE
#endif
#ifndef NST_RESTRICT
#define NST_RESTRICT
#endif
#ifndef NST_UNREACHABLE
#define NST_UNREACHABLE() NST_ASSERT(0)
#endif
#ifndef NST_FASTCALL
#define NST_FASTCALL
#endif
#ifndef NST_REGCALL
#define NST_REGCALL
#endif
#define NST_MIN(x_,y_) ((x_) < (y_) ? (x_) : (y_))
#define NST_MAX(x_,y_) ((x_) < (y_) ? (y_) : (x_))
#define NST_COMMA ,
#define NST_CAT_NEXT(x_,y_) x_##y_
#define NST_CAT(x_,y_) NST_CAT_NEXT(x_,y_)
#define NST_COMPILE_ASSERT(expr_) typedef char NST_CAT(Nestopia_assertion_at_line_,__LINE__)[(expr_) ? 1 : -1]
namespace Nes
{
namespace Core
{
typedef const char* cstring;
typedef const wchar_t* wcstring;
typedef uint ibool;
typedef uint Data;
typedef uint Address;
typedef dword Cycle;
template<typename T,dword N>
char(& array(T(&)[N]))[N];
namespace Helper
{
template<ulong W> struct CountBits
{
enum { VALUE = 1 + CountBits<W / 2>::VALUE };
};
template<> struct CountBits<1UL>
{
enum { VALUE = 1 };
};
template<> struct CountBits<0UL>
{
enum { VALUE = 0 };
};
template<typename T,bool>
struct ShiftSigned
{
static long Left(T v,uint c)
{
return v << c;
}
static long Right(T v,uint c)
{
return v >> c;
}
};
template<typename T>
struct ShiftSigned<T,false>
{
static long Left(T v,uint c)
{
return (v >= 0) ? +long(ulong(v) << c) : -long(ulong(-v) << c);
}
static long Right(T v,uint c)
{
return (v >= 0) ? +long(ulong(v) >> c) : -long(ulong(-v) >> c);
}
};
template<typename T,bool>
struct SignExtend8
{
static T Convert(T v)
{
return schar(v);
}
};
template<typename T>
struct SignExtend8<T,false>
{
static T Convert(T v)
{
return (v & 1U << 7) ? (v | ~0UL << 7) : v;
}
};
}
template<ulong V> struct ValueBits
{
enum { VALUE = Helper::CountBits<V>::VALUE };
};
template<typename T>
inline long signed_shl(T v,uint c)
{
enum {NATIVE = -(T(7) << 1) == -14};
return Helper::ShiftSigned<T,NATIVE>::Left( v, c );
}
template<typename T>
inline long signed_shr(T v,uint c)
{
enum {NATIVE = -(T(7) >> 1) == -4 || -(T(7) >> 1) == -3};
return Helper::ShiftSigned<T,NATIVE>::Right( v, c );
}
template<typename T>
inline T sign_extend_8(T v)
{
enum {NATIVE = CHAR_BIT == 8 && UCHAR_MAX == 0xFF && SCHAR_MIN == -128 && SCHAR_MAX == 127 && T(-2) == T(~1UL)};
return Helper::SignExtend8<T,NATIVE>::Convert( v );
}
template<idword Min,idword Max>
inline idword Clamp(idword value)
{
return (value <= Max) ? (value >= Min) ? value : Min : Max;
}
enum
{
SIZE_1K = 0x400,
SIZE_2K = 0x800,
SIZE_4K = 0x1000,
SIZE_5K = 0x1400,
SIZE_6K = 0x1800,
SIZE_8K = 0x2000,
SIZE_16K = 0x4000,
SIZE_32K = 0x8000,
SIZE_40K = 0xA000,
SIZE_64K = 0x10000,
SIZE_128K = 0x20000,
SIZE_256K = 0x40000,
SIZE_512K = 0x80000,
SIZE_1024K = 0x100000,
SIZE_2048K = 0x200000,
SIZE_3072K = 0x300000,
SIZE_4096K = 0x400000,
SIZE_8192K = 0x800000,
SIZE_16384K = 0x1000000
};
template<char T>
struct Ascii
{
enum
{
V = ( T >= 'a' && T <= 'z') ? T - 'a' + 0x61 :
( T >= 'A' && T <= 'Z') ? T - 'A' + 0x41 :
( T >= '0' && T <= '9') ? T - '0' + 0x30 :
( T == '\0' ) ? 0x00 :
( T == ' ' ) ? 0x20 :
( T == '!' ) ? 0x21 :
( T == '#' ) ? 0x23 :
( T == '%' ) ? 0x25 :
( T == '^' ) ? 0x5E :
( T == '&' ) ? 0x26 :
( T == '*' ) ? 0x2A :
( T == '(' ) ? 0x28 :
( T == ')' ) ? 0x29 :
( T == '-' ) ? 0x2D :
( T == '_' ) ? 0x5F :
( T == '+' ) ? 0x2B :
( T == '=' ) ? 0x3D :
( T == '~' ) ? 0x7E :
( T == '[' ) ? 0x5B :
( T == ']' ) ? 0x5D :
( T == '\\' ) ? 0x5C :
( T == '|' ) ? 0x7C :
( T == ';' ) ? 0x3B :
( T == ':' ) ? 0x3A :
( T == '\'' ) ? 0x27 :
( T == '\"' ) ? 0x22 :
( T == '{' ) ? 0x7B :
( T == '}' ) ? 0x7D :
( T == ',' ) ? 0x2C :
( T == '.' ) ? 0x2E :
( T == '<' ) ? 0x3C :
( T == '>' ) ? 0x3E :
( T == '/' ) ? 0x2F :
( T == '?' ) ? 0x3F :
( T == '\a' ) ? 0x07 :
( T == '\b' ) ? 0x08 :
( T == '\t' ) ? 0x09 :
( T == '\v' ) ? 0x0B :
( T == '\n' ) ? 0x0A :
( T == '\r' ) ? 0x0D :
( T == '\f' ) ? 0x0C : 0xFF
};
NST_COMPILE_ASSERT( V != 0xFF );
};
template<char A,char B,char C=0,char D=0>
struct AsciiId
{
enum
{
V =
(
dword( Ascii<A>::V ) << 0 |
dword( Ascii<B>::V ) << 8 |
dword( Ascii<C>::V ) << 16 |
dword( Ascii<D>::V ) << 24
)
};
static dword R(byte a,byte b=0,byte c=0,byte d=0)
{
return
(
dword( Ascii<A>::V + a ) << 0 |
dword( Ascii<B>::V + b ) << 8 |
dword( Ascii<C>::V + c ) << 16 |
dword( Ascii<D>::V + d ) << 24
);
}
};
template<typename T,typename U>
int StringCompare(const T* a,const U* b)
{
do
{
const wchar_t v[] =
{
(*a < L'a' || *a > L'z') ? *a : (L'A' + (*a - L'a')),
(*b < L'a' || *b > L'z') ? *b : (L'A' + (*b - L'a'))
};
if (v[0] < v[1])
return -1;
if (v[0] > v[1])
return +1;
}
while (++b, *a++);
return 0;
}
template<typename T,typename U>
int StringCompare(const T* a,const U* b,uint l)
{
for (; l--; ++a, ++b)
{
const wchar_t v[] =
{
(*a < L'a' || *a > L'z') ? *a : (L'A' + (*a - L'a')),
(*b < L'a' || *b > L'z') ? *b : (L'A' + (*b - L'a'))
};
if (v[0] < v[1])
return -1;
if (v[0] > v[1])
return +1;
if (!v[0])
return 0;
}
return 0;
}
}
#ifdef NST_U64
typedef NST_U64 qaword;
#define NST_NATIVE_QWORD
#elif (ULONG_MAX > 0xFFFFFFFF) && (ULONG_MAX / 0xFFFFFFFF - 1 > 0xFFFFFFFF)
typedef unsigned long qaword;
#define NST_NATIVE_QWORD
#elif (defined(ULLONG_MAX) && (ULLONG_MAX > 0xFFFFFFFF) && (ULLONG_MAX / 0xFFFFFFFF - 1 > 0xFFFFFFFF)) || (NST_GCC >= 300)
#if NST_GCC
__extension__ typedef unsigned long long qaword;
#else
typedef unsigned long long qaword;
#endif
#define NST_NATIVE_QWORD
#elif defined(_UI64_MAX) && (NST_MSVC >= 900 || NST_BCB >= 0x530)
typedef unsigned __int64 qaword;
#define NST_NATIVE_QWORD
#else
class qaword
{
void Multiply(qaword);
static void Divide(qaword&,const qaword,bool);
void Shl(uint);
void Shr(uint);
enum
{
LO_MASK = 0xFFFFFFFF,
LO_MSB = 0x80000000
};
dword lo;
dword hi;
public:
qaword() {}
qaword(dword v)
: lo(v), hi(0) {}
qaword(dword msdw,dword lsdw)
: lo(lsdw), hi(msdw) {}
qaword(const qaword& v)
: lo(v.lo), hi(v.hi) {}
template<typename V>
qaword& operator = (const V& v)
{
lo = v;
hi = 0;
return *this;
}
qaword& operator = (const qaword& v)
{
lo = v.lo;
hi = v.hi;
return *this;
}
template<typename V>
qaword& operator += (const V& v)
{
dword t = lo;
lo = (lo + v) & LO_MASK;
hi = (hi + (t > lo)) & LO_MASK;
return *this;
}
template<typename V>
qaword& operator -= (const V& v)
{
dword t = lo;
lo = (lo - v) & LO_MASK;
hi = (hi - (t < lo)) & LO_MASK;
return *this;
}
qaword operator ++ (int)
{
qaword t;
t.lo = lo;
lo = (lo + 1) & LO_MASK;
t.hi = hi;
hi = (hi + (t.lo > lo)) & LO_MASK;
return t;
}
qaword& operator ++ ()
{
dword t = lo;
lo = (lo + 1) & LO_MASK;
hi = (hi + (t > lo)) & LO_MASK;
return *this;
}
qaword operator -- (int)
{
qaword t;
t.lo = lo;
lo = (lo - 1) & LO_MASK;
t.hi = hi;
hi = (hi - (t.lo < lo)) & LO_MASK;
return t;
}
qaword& operator -- ()
{
dword t = lo;
lo = (lo - 1) & LO_MASK;
hi = (hi - (t < lo)) & LO_MASK;
return *this;
}
template<typename V>
qaword& operator *= (const V& v)
{
if (!(((lo | v) & 0xFFFF0000) | hi))
lo = (lo * v) & LO_MASK;
else
Multiply( qaword(v) );
return *this;
}
template<typename V>
qaword& operator /= (const V& v)
{
if (!hi)
lo /= v;
else
Divide( *this, qaword(v), false );
return *this;
}
template<typename V>
qaword& operator %= (const V& v)
{
if (!hi)
lo %= v;
else
Divide( *this, qaword(v), true );
return *this;
}
template<typename V> qaword operator + (const V& v) const { return qaword(*this) += v; }
template<typename V> qaword operator - (const V& v) const { return qaword(*this) -= v; }
template<typename V> qaword operator * (const V& v) const { return qaword(*this) *= v; }
template<typename V> qaword operator / (const V& v) const { return qaword(*this) /= v; }
template<typename V> qaword operator % (const V& v) const { return qaword(*this) %= v; }
template<typename V> qaword& operator |= (const V& v) { lo |= v; return *this; }
template<typename V> qaword& operator &= (const V& v) { lo &= v; hi = 0; return *this; }
template<typename V> qaword& operator ^= (const V& v) { lo ^= v; return *this; }
template<typename V> qaword operator | (const V& v) const { return qaword( hi, lo | v ); }
template<typename V> qaword operator & (const V& v) const { return qaword( lo & v ); }
template<typename V> qaword operator ^ (const V& v) const { return qaword( hi, lo ^ v ); }
template<typename V> qaword& operator >>= (const V& v) { Shr(v); return *this; }
template<typename V> qaword& operator <<= (const V& v) { Shl(v); return *this; }
template<typename V> qaword operator >> (const V& v) const { return qaword(*this) >>= v; }
template<typename V> qaword operator << (const V& v) const { return qaword(*this) <<= v; }
qaword operator ~() const
{
return qaword( hi ^ LO_MASK, lo ^ LO_MASK );
}
template<typename V>
bool operator == (const V& v) const
{
return !((lo - v) | hi);
}
template<typename V>
bool operator < (const V& v) const
{
return (lo < v && !hi);
}
template<typename V>
bool operator <= (const V& v) const
{
return (lo <= v && !hi);
}
template<typename V>
bool operator != (const V& v) const
{
return !(*this == v);
}
template<typename V>
bool operator > (const V& v) const
{
return !(*this <= v);
}
template<typename V>
bool operator >= (const V& v) const
{
return !(*this < v);
}
bool operator !() const
{
return !(lo|hi);
}
operator bool() const
{
return (lo|hi);
}
operator int () const { return lo; }
operator uint () const { return lo; }
operator char () const { return lo; }
operator schar () const { return lo; }
operator uchar () const { return lo; }
operator short () const { return lo; }
operator ushort () const { return lo; }
operator long () const { return lo; }
operator ulong () const { return lo; }
};
template<>
inline qaword& qaword::operator += (const qaword& v)
{
dword t = lo;
lo = (lo + v.lo) & LO_MASK;
hi = (hi + (t > lo) + v.hi) & LO_MASK;
return *this;
}
template<>
inline qaword& qaword::operator -= (const qaword& v)
{
dword t = lo;
lo = (lo - v.lo) & LO_MASK;
hi = (hi - ((t < lo) + v.hi)) & LO_MASK;
return *this;
}
template<>
inline qaword& qaword::operator *= (const qaword& v)
{
Multiply( v );
return *this;
}
template<>
inline qaword& qaword::operator /= (const qaword& v)
{
if (hi | v.hi)
Divide( *this, v, false );
else
lo /= v.lo;
return *this;
}
template<>
inline qaword& qaword::operator %= (const qaword& v)
{
Divide( *this, v, true );
return *this;
}
template<> inline qaword& qaword::operator |= (const qaword& v) { lo |= v.lo; hi |= v.hi; return *this; }
template<> inline qaword& qaword::operator &= (const qaword& v) { lo &= v.lo; hi &= v.hi; return *this; }
template<> inline qaword& qaword::operator ^= (const qaword& v) { lo ^= v.lo; hi ^= v.hi; return *this; }
template<> inline qaword qaword::operator | (const qaword& v) const { return qaword( hi | v.hi, lo | v.lo ); }
template<> inline qaword qaword::operator & (const qaword& v) const { return qaword( hi & v.hi, lo & v.lo ); }
template<> inline qaword qaword::operator ^ (const qaword& v) const { return qaword( hi ^ v.hi, lo ^ v.lo ); }
template<>
inline bool qaword::operator == (const qaword& v) const
{
return !((lo - v.lo) | (hi - v.hi));
}
template<>
inline bool qaword::operator < (const qaword& v) const
{
return (hi < v.hi) || (lo < v.lo && hi == v.hi);
}
template<>
inline bool qaword::operator <= (const qaword& v) const
{
return (hi < v.hi) || (hi == v.hi ? (lo <= v.lo) : false);
}
#endif
}
#endif