gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

patomic.cxx (6417B)


      1 /*
      2  *
      3  *  C++ Portable Types Library (PTypes)
      4  *  Version 2.1.1  Released 27-Jun-2007
      5  *
      6  *  Copyright (C) 2001-2007 Hovik Melikyan
      7  *
      8  *  http://www.melikyan.com/ptypes/
      9  *
     10  */
     11 
     12 #ifdef WIN32
     13 #  include <windows.h>
     14 #endif
     15 
     16 #include "ptypes.h"
     17 #include "pasync.h"     // for pmemlock*
     18 
     19 #include <assert.h>
     20 
     21 namespace ptypes {
     22 
     23 
     24 #ifdef PTYPES_ST
     25 // single-threaded version
     26 
     27 
     28 int __PFASTCALL pexchange(int* target, int value)
     29 {
     30     int r = *target;
     31     *target = value;
     32     return r;
     33 }
     34 
     35 
     36 void* __PFASTCALL pexchange(void** target, void* value)
     37 {
     38     void* r = *target;
     39     *target = value;
     40     return r;
     41 }
     42 
     43 
     44 int __PFASTCALL pincrement(int* target)
     45 {
     46     return ++(*target);
     47 }
     48 
     49 
     50 int __PFASTCALL pdecrement(int* target)
     51 {
     52     return --(*target);
     53 }
     54 
     55 
     56 #else
     57 // multi-threaded version
     58 
     59 #if defined(__GNUC__) && (defined(__i386__) || defined(__I386__))
     60 #  define GCC_i386
     61 #elif defined(__GNUC__) && defined(__ppc__)
     62 #  define GCC_PPC
     63 #elif defined(_MSC_VER) && defined(_M_IX86)
     64 #  define MSC_i386
     65 #elif defined(_MSC_VER) && (defined(_M_IA64) || defined(_WIN64))
     66 #  define MSC_x64
     67 #elif defined(__BORLANDC__) && defined(_M_IX86)
     68 #  define BCC_i386
     69 #elif defined(__GNUC__) && defined(__sparc__) && !defined(__arch64__)
     70 #  define GCC_sparc
     71 #endif
     72 
     73 
     74 #if defined(MSC_i386) || defined(BCC_i386)
     75 
     76 //
     77 // atomic operations for Microsoft C or Borland C on Windows
     78 //
     79 
     80 #if defined(_MSC_VER)
     81 #  pragma warning (disable: 4035)
     82 #elif defined(__BORLANDC__)
     83 #  pragma warn -rvl
     84 #endif
     85 
     86 // !!! NOTE
     87 // the following functions implement atomic exchange/inc/dec on
     88 // windows. they are dangerous in that they rely on the calling
     89 // conventions of MSVC and BCC. the first one passes the first
     90 // two arguments in ECX and EDX, and the second one - in EAX and 
     91 // EDX.
     92 
     93 int __PFASTCALL pincrement(int* v)
     94 {
     95 	return InterlockedIncrement((LONG*)v);
     96 }
     97 
     98 
     99 int __PFASTCALL pdecrement(int* v)
    100 {
    101 	return InterlockedDecrement((LONG*)v);
    102 }
    103 
    104 
    105 int __PFASTCALL pexchange(int* a, int b)
    106 {
    107 	return InterlockedExchange((LONG*)a,b);
    108 }
    109 
    110 
    111 void* __PFASTCALL pexchange(void** a, void* b)
    112 {
    113 #ifdef _WIN64
    114 	return InterlockedExchange64( a,b);
    115 #else
    116 	return (void*)InterlockedExchange((LONG*)a,(LONG)b);
    117 #endif
    118 }
    119 
    120 
    121 #elif defined(GCC_i386)
    122 
    123 //
    124 // GNU C compiler on any i386 platform (actually 486+ for xadd)
    125 //
    126 
    127 int pexchange(int* target, int value)
    128 {
    129     __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target));
    130     return value;
    131 }
    132 
    133 
    134 void* pexchange(void** target, void* value)
    135 {
    136     __asm__ __volatile ("lock ; xchgl (%1),%0" : "+r" (value) : "r" (target));
    137     return value;
    138 }
    139 
    140 
    141 int pincrement(int* target)
    142 {
    143     int temp = 1;
    144     __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target));
    145     return temp + 1;
    146 }
    147 
    148 
    149 int pdecrement(int* target)
    150 {
    151     int temp = -1;
    152     __asm__ __volatile ("lock ; xaddl %0,(%1)" : "+r" (temp) : "r" (target));
    153     return temp - 1;
    154 }
    155 
    156 
    157 #elif defined(GCC_PPC)
    158 
    159 //
    160 // GNU C compiler on any PPC platform
    161 //
    162 
    163 int pexchange(int* target, int value)
    164 {
    165     int temp;
    166     __asm__ __volatile (
    167 "1: lwarx  %0,0,%1\n\
    168 	stwcx. %2,0,%1\n\
    169 	bne-   1b\n\
    170 	isync"
    171 	: "=&r" (temp)
    172 	: "r" (target), "r" (value)
    173 	: "cc", "memory"
    174 	);
    175     return temp;
    176 }
    177 
    178 
    179 void* pexchange(void** target, void* value)
    180 {
    181     void* temp;
    182     __asm__ __volatile (
    183 "1: lwarx  %0,0,%1\n\
    184 	stwcx. %2,0,%1\n\
    185 	bne-   1b\n\
    186 	isync"
    187 	: "=&r" (temp)
    188 	: "r" (target), "r" (value)
    189 	: "cc", "memory"
    190 	);
    191     return temp;
    192 }
    193 
    194 
    195 int pincrement(int* target)
    196 {
    197     int temp;
    198     __asm__ __volatile (
    199 "1: lwarx  %0,0,%1\n\
    200 	addic  %0,%0,1\n\
    201 	stwcx. %0,0,%1\n\
    202 	bne-   1b\n\
    203 	isync"
    204 	: "=&r" (temp)
    205 	: "r" (target)
    206 	: "cc", "memory"
    207 	);
    208     return temp;
    209 }
    210 
    211 
    212 int pdecrement(int* target)
    213 {
    214     int temp;
    215     __asm__ __volatile (
    216 "1: lwarx  %0,0,%1\n\
    217 	addic  %0,%0,-1\n\
    218 	stwcx. %0,0,%1\n\
    219 	bne-   1b\n\
    220 	isync"
    221 	: "=&r" (temp)
    222 	: "r" (target)
    223 	: "cc", "memory"
    224 	);
    225     return temp;
    226 }
    227 
    228 
    229 #elif defined GCC_sparc
    230 
    231 //
    232 // GNU C compiler on SPARC in 32-bit mode (pointers are 32-bit)
    233 //
    234 
    235 // assembly routines defined in patomic.sparc.s
    236 // we currently don't use CAS in the library, but let it be there
    237 extern "C" {
    238     int __patomic_add(volatile int* __mem, int __val);
    239     int __patomic_swap(volatile int* __mem, int __val);
    240     int __patomic_cas(volatile int* __mem, int __expected, int __newval);
    241 }
    242 
    243 #define __patomic_swap_p(mem,val) \
    244     (void*)(__patomic_swap((int*)(mem), (int)(val)))
    245 
    246 
    247 int pexchange(int* target, int value)
    248 {
    249     return __patomic_swap(target, value);
    250 }
    251 
    252 
    253 void* pexchange(void** target, void* value)
    254 {
    255     return __patomic_swap_p(target, value);
    256 }
    257 
    258 
    259 int pincrement(int* target)
    260 {
    261     return __patomic_add(target, 1);
    262 }
    263 
    264 
    265 int pdecrement(int* target)
    266 {
    267     return __patomic_add(target, -1);
    268 }
    269 
    270 #elif defined __EMSCRIPTEN__
    271 #include <emscripten/threading.h>
    272 int pexchange(int* target, int value)
    273 {
    274 	return emscripten_atomic_exchange_u32(target, value);
    275 }
    276 
    277 
    278 void* pexchange(void** target, void* value)
    279 {
    280 	return (void*)emscripten_atomic_exchange_u32(*target, (uint32_t)value);
    281 }
    282 
    283 
    284 int pincrement(int* target)
    285 {
    286 	return emscripten_atomic_add_u32(target, 1);
    287 }
    288 
    289 
    290 int pdecrement(int* target)
    291 {
    292 	return emscripten_atomic_add_u32(target, -1);
    293 }
    294 
    295 #elif defined MSC_x64
    296 
    297 int pexchange(int* target, int value)
    298 {
    299 	assert( sizeof(target) == sizeof(volatile LONG*) );
    300 
    301 	return InterlockedExchange((volatile LONG*)target,value);
    302 }
    303 
    304 
    305 void* pexchange(void** target, void* value)
    306 {
    307 	return InterlockedExchangePointer(target,value);
    308 }
    309 
    310 int pincrement(int* target)
    311 {
    312 	assert( sizeof(target) == sizeof(volatile LONG*) );
    313 	return InterlockedIncrement((volatile LONG*)target);
    314 }
    315 
    316 
    317 int pdecrement(int* target)
    318 {
    319 	assert( sizeof(target) == sizeof(volatile LONG*) );
    320 	return InterlockedDecrement((volatile LONG*)target);
    321 }
    322 
    323 
    324 #else
    325 
    326 //
    327 // other platforms: mutex locking
    328 //
    329 
    330 int pexchange(int* target, int value)
    331 {
    332     pmemlock* m = pgetmemlock(target);
    333     pmementer(m);
    334     int r = *target;
    335     *target = value;
    336     pmemleave(m);
    337     return r;
    338 }
    339 
    340 
    341 void* pexchange(void** target, void* value)
    342 {
    343     pmemlock* m = pgetmemlock(target);
    344     pmementer(m);
    345     void* r = *target;
    346     *target = value;
    347     pmemleave(m);
    348     return r;
    349 }
    350 
    351 int pincrement(int* target)
    352 {
    353 	assert( NULL != _mtxtable );
    354     pmemlock* m = pgetmemlock(target);
    355     pmementer(m);
    356     int r = ++(*target);
    357     pmemleave(m);
    358     return r;
    359 }
    360 
    361 
    362 int pdecrement(int* target)
    363 {
    364     pmemlock* m = pgetmemlock(target);
    365     pmementer(m);
    366     int r = --(*target);
    367     pmemleave(m);
    368     return r;
    369 }
    370 
    371 #endif
    372 
    373 
    374 #endif
    375 
    376 
    377 }