1 | // CPU Byte Order Utilities |
2 | |
3 | // snes_spc 0.9.0 |
4 | #ifndef BLARGG_ENDIAN |
5 | #define BLARGG_ENDIAN |
6 | |
7 | #include "blargg_common.h" |
8 | |
9 | // BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) |
10 | #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ |
11 | defined (__x86_64__) || defined (__ia64__) || defined (__i386__) |
12 | #define BLARGG_CPU_X86 1 |
13 | #define BLARGG_CPU_CISC 1 |
14 | #endif |
15 | |
16 | #if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) |
17 | #define BLARGG_CPU_POWERPC 1 |
18 | #define BLARGG_CPU_RISC 1 |
19 | #endif |
20 | |
21 | // BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only |
22 | // one may be #defined to 1. Only needed if something actually depends on byte order. |
23 | #if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) |
24 | #ifdef __GLIBC__ |
25 | // GCC handles this for us |
26 | #include <endian.h> |
27 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
28 | #define BLARGG_LITTLE_ENDIAN 1 |
29 | #elif __BYTE_ORDER == __BIG_ENDIAN |
30 | #define BLARGG_BIG_ENDIAN 1 |
31 | #endif |
32 | #else |
33 | |
34 | #if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ |
35 | (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) |
36 | #define BLARGG_LITTLE_ENDIAN 1 |
37 | #endif |
38 | |
39 | #if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ |
40 | defined (__sparc__) || BLARGG_CPU_POWERPC || \ |
41 | (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) |
42 | #define BLARGG_BIG_ENDIAN 1 |
43 | #elif !defined (__mips__) |
44 | // No endian specified; assume little-endian, since it's most common |
45 | #define BLARGG_LITTLE_ENDIAN 1 |
46 | #endif |
47 | #endif |
48 | #endif |
49 | |
50 | #if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN |
51 | #undef BLARGG_LITTLE_ENDIAN |
52 | #undef BLARGG_BIG_ENDIAN |
53 | #endif |
54 | |
55 | inline void blargg_verify_byte_order() |
56 | { |
57 | #ifndef NDEBUG |
58 | #if BLARGG_BIG_ENDIAN |
59 | volatile int i = 1; |
60 | assert( *(volatile char*) &i == 0 ); |
61 | #elif BLARGG_LITTLE_ENDIAN |
62 | volatile int i = 1; |
63 | assert( *(volatile char*) &i != 0 ); |
64 | #endif |
65 | #endif |
66 | } |
67 | |
68 | inline unsigned get_le16( void const* p ) |
69 | { |
70 | return (unsigned) ((unsigned char const*) p) [1] << 8 | |
71 | (unsigned) ((unsigned char const*) p) [0]; |
72 | } |
73 | |
74 | inline unsigned get_be16( void const* p ) |
75 | { |
76 | return (unsigned) ((unsigned char const*) p) [0] << 8 | |
77 | (unsigned) ((unsigned char const*) p) [1]; |
78 | } |
79 | |
80 | inline blargg_ulong get_le32( void const* p ) |
81 | { |
82 | return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | |
83 | (blargg_ulong) ((unsigned char const*) p) [2] << 16 | |
84 | (blargg_ulong) ((unsigned char const*) p) [1] << 8 | |
85 | (blargg_ulong) ((unsigned char const*) p) [0]; |
86 | } |
87 | |
88 | inline blargg_ulong get_be32( void const* p ) |
89 | { |
90 | return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | |
91 | (blargg_ulong) ((unsigned char const*) p) [1] << 16 | |
92 | (blargg_ulong) ((unsigned char const*) p) [2] << 8 | |
93 | (blargg_ulong) ((unsigned char const*) p) [3]; |
94 | } |
95 | |
96 | inline void set_le16( void* p, unsigned n ) |
97 | { |
98 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); |
99 | ((unsigned char*) p) [0] = (unsigned char) n; |
100 | } |
101 | |
102 | inline void set_be16( void* p, unsigned n ) |
103 | { |
104 | ((unsigned char*) p) [0] = (unsigned char) (n >> 8); |
105 | ((unsigned char*) p) [1] = (unsigned char) n; |
106 | } |
107 | |
108 | inline void set_le32( void* p, blargg_ulong n ) |
109 | { |
110 | ((unsigned char*) p) [0] = (unsigned char) n; |
111 | ((unsigned char*) p) [1] = (unsigned char) (n >> 8); |
112 | ((unsigned char*) p) [2] = (unsigned char) (n >> 16); |
113 | ((unsigned char*) p) [3] = (unsigned char) (n >> 24); |
114 | } |
115 | |
116 | inline void set_be32( void* p, blargg_ulong n ) |
117 | { |
118 | ((unsigned char*) p) [3] = (unsigned char) n; |
119 | ((unsigned char*) p) [2] = (unsigned char) (n >> 8); |
120 | ((unsigned char*) p) [1] = (unsigned char) (n >> 16); |
121 | ((unsigned char*) p) [0] = (unsigned char) (n >> 24); |
122 | } |
123 | |
124 | #if BLARGG_NONPORTABLE |
125 | // Optimized implementation if byte order is known |
126 | #if BLARGG_LITTLE_ENDIAN |
127 | #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) |
128 | #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) |
129 | #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) |
130 | #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) |
131 | #elif BLARGG_BIG_ENDIAN |
132 | #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) |
133 | #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) |
134 | #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) |
135 | #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) |
136 | |
137 | #if BLARGG_CPU_POWERPC |
138 | // PowerPC has special byte-reversed instructions |
139 | #if defined (__MWERKS__) |
140 | #define GET_LE16( addr ) (__lhbrx( addr, 0 )) |
141 | #define GET_LE32( addr ) (__lwbrx( addr, 0 )) |
142 | #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) |
143 | #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) |
144 | #elif defined (__GNUC__) |
145 | #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) |
146 | #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) |
147 | #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) |
148 | #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) |
149 | #endif |
150 | #endif |
151 | #endif |
152 | #endif |
153 | |
154 | #ifndef GET_LE16 |
155 | #define GET_LE16( addr ) get_le16( addr ) |
156 | #define SET_LE16( addr, data ) set_le16( addr, data ) |
157 | #endif |
158 | |
159 | #ifndef GET_LE32 |
160 | #define GET_LE32( addr ) get_le32( addr ) |
161 | #define SET_LE32( addr, data ) set_le32( addr, data ) |
162 | #endif |
163 | |
164 | #ifndef GET_BE16 |
165 | #define GET_BE16( addr ) get_be16( addr ) |
166 | #define SET_BE16( addr, data ) set_be16( addr, data ) |
167 | #endif |
168 | |
169 | #ifndef GET_BE32 |
170 | #define GET_BE32( addr ) get_be32( addr ) |
171 | #define SET_BE32( addr, data ) set_be32( addr, data ) |
172 | #endif |
173 | |
174 | // auto-selecting versions |
175 | |
176 | inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } |
177 | inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } |
178 | inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } |
179 | inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } |
180 | inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } |
181 | inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } |
182 | inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } |
183 | inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } |
184 | |
185 | #endif |
186 | |