1 // sidtypes.h - Different data types and automatic conversions between
2 // them (for example, big and little endian integrals). -*- C++ -*-
4 // Copyright (C) 1999, 2000 Red Hat.
5 // This file is part of SID and is licensed under the GPL.
6 // See the file COPYING.SID for conditions for redistribution.
15 // In order to make the sid core header files host-independent,
16 // host-specific (autoconf-generated) headers are not #included here.
17 // Instead, we use a handful of compiler-provided macros to determine
18 // some key platform parameters.
20 #if defined(__NetBSD__)
21 # include <machine/endian.h>
22 # if BYTE_ORDER == LITTLE_ENDIAN
23 # define HOST_BIG_ENDIAN false
25 # define HOST_BIG_ENDIAN true
28 # if defined(__i386__) || defined(__x86_64__) || defined(__alpha__) || (defined(__mips__) && defined(_MIPSEL))
29 # define HOST_BIG_ENDIAN false
30 # elif defined(__sparc__) || defined(__powerpc__) || (defined(__mips__) && defined(_MIPSEB))
31 # define HOST_BIG_ENDIAN true
33 # error "Unknown host platform"
39 // XXX: Define these conditionally.
40 typedef unsigned char host_int_1;
41 typedef unsigned short host_int_2;
42 typedef unsigned int host_int_4;
43 typedef unsigned long long host_int_8;
44 typedef signed char signed_host_int_1;
45 typedef signed short signed_host_int_2;
46 typedef signed int signed_host_int_4;
47 typedef signed long long signed_host_int_8;
52 // The following bytereverse functions are used to convert between
53 // big-endian and little-endian integers.
56 bytereverse(host_int_1 value)
62 bytereverse(host_int_2 value)
64 // This is a 386 instruction.
65 #if defined(__GNUC__) && (defined(__i386__) || defined (__x86_64__))
66 __asm__("xchgb %b0,%h0" : "=q" (value) : "0" (value));
68 value = ( ((value & 0xff00U) >> 8)
69 | ((value & 0x00ffU) << 8));
75 bytereverse(host_int_4 value)
77 #if defined(__GNUC__) && (defined(__i486__) || defined(__i586__) || defined(__i686__) || defined (__x86_64__))
78 // This is a 486+ instruction
79 __asm__ ("bswap %0" : "=r" (value) : "0" (value));
81 value = ( ((value & 0xff000000UL) >> 24)
82 | ((value & 0x00ff0000UL) >> 8)
83 | ((value & 0x0000ff00UL) << 8)
84 | ((value & 0x000000ffUL) << 24));
90 bytereverse(host_int_8 value)
92 #if defined (__GNUC__) && defined (__x86_64__)
93 // This is an x86_64 instruction.
94 __asm__ ("bswap %0" : "=r" (value) : "0" (value));
96 host_int_4 upper = (value & 0xffffffff00000000ULL) >> 32;
97 host_int_4 lower = (value & 0x00000000ffffffffULL);
98 upper = bytereverse(upper);
99 lower = bytereverse(lower);
100 value = ((host_int_8)lower) << 32 | (host_int_8)upper;
106 // A bi-endian integer class.
108 // Each instance represents an integer quanitity, with an additional
109 // tag that describes how that value should be stored in simulated
112 // The template class any_int<> should not be used directly.
113 // Rather, use one of the typedef'd classes:
114 // big_int_1, big_int_2, big_int_4, big_int_8
115 // little_int_1, little_int_2, little_int_4, or little_int_8
117 template <typename IntType, bool IsBig>
121 // Utility related types
122 typedef IntType value_type;
123 typedef any_int<IntType,HOST_BIG_ENDIAN> host_int_type;
124 typedef any_int<host_int_1,IsBig> size_1_type;
125 typedef any_int<host_int_2,IsBig> size_2_type;
126 typedef any_int<host_int_4,IsBig> size_4_type;
127 typedef any_int<host_int_8,IsBig> size_8_type;
130 // Return the natural integer value represented by this object.
131 // This value is the same, whether this class represents a big or
132 // little endian value.
133 IntType integer_value() const { return _integer_value; }
134 operator IntType () const { return _integer_value; }
136 // Return the simulated memory image of this value. This may be
137 // a byte-reversed copy of integer_value().
138 IntType target_memory_value() const
140 if (IsBig == HOST_BIG_ENDIAN)
141 return this->_integer_value;
143 return bytereverse (_integer_value);
146 // Set the simulated memory image of this value. It may be
148 void set_target_memory_value(IntType v)
150 if (IsBig == HOST_BIG_ENDIAN)
151 this->_integer_value = v;
153 this->_integer_value = bytereverse(v);
158 // The default constructor constructs an object with value 0.
159 any_int(): _integer_value (0) {}
161 // Construct from a big_int type.
162 // Copies the integer_value. Regardless of types, the value is
163 // NOT byte-reversed by this call.
164 // v is the big_int value to construct the new object from.
165 any_int(const any_int<IntType,true>& v): _integer_value (v.integer_value()) {}
167 // Construct from a little_int type.
168 // Copies the integer_value. Regardless of types, the value is
169 // NOT byte-reversed by this call.
170 // v is the little_int value to construct the new object from.
171 any_int(const any_int<IntType,false>& v): _integer_value (v.integer_value()) {}
173 // Construct from a integer type.
174 // The new object's integer_value() method will return `v'.
175 // v is the integer value to construct the new object from.
176 any_int(IntType v): _integer_value(v) {}
179 // Assign from a little_int type.
180 // Copies the integer_value. Regardless of types, the value is
181 // NOT byte-reversed by this call.
182 // v is the little_int value to be assigned from.
183 any_int<IntType,IsBig>& operator = (const any_int<IntType,false>& v)
185 _integer_value = v.integer_value();
189 // Assign from a big_int type.
190 // Copies the integer_value. Regardless of types, the value is
191 // NOT byte-reversed by this call.
192 // v is the little_int value to be assigned from.
193 any_int<IntType,IsBig>& operator = (const any_int<IntType,true>& v)
195 _integer_value = v.integer_value();
199 // Assign from a integer type.
200 // The new object's integer_value() method will return `v'.
201 // v is the integer value to construct the new object from.
202 any_int<IntType,IsBig>& operator = (IntType v) {
207 // These functions access the stored value as if it was a byte array.
209 // Write byte at offset ix in target memory image.
210 // ix is the index of the byte in the in-memory image.
211 // byte is the value to write.
212 void write_byte(unsigned ix, host_int_1 byte)
214 assert (0 <= ix && ix < sizeof(IntType));
215 char* value_ptr = reinterpret_cast<char*>(&this->_integer_value);
216 if (IsBig != HOST_BIG_ENDIAN) {
217 value_ptr[(sizeof(IntType)-1)-ix] = byte;
219 value_ptr[ix] = byte;
223 // Read byte at offset ix from the target memory image.
224 // ix is the index of the byte in the in-memory image.
225 // Returns the value of the byte.
226 host_int_1 read_byte(unsigned ix) const
228 assert (0 <= ix && ix < sizeof(IntType));
229 const char* value_ptr = reinterpret_cast<const char*>(&this->_integer_value);
230 if (IsBig != HOST_BIG_ENDIAN) {
231 return value_ptr[(sizeof(IntType)-1)-ix];
233 return value_ptr[ix];
238 IntType _integer_value;
242 // ----------------------------------------------------------------------------
245 // Stream any_int using current stream flags
246 template <typename IntType, bool IsBig>
248 operator << (std::ostream& o, const any_int<IntType,IsBig>& v)
257 // Destream any_int using current stream flags
258 template <typename IntType, bool IsBig>
260 operator >> (std::istream& i, any_int<IntType,IsBig>& v)
271 // ----------------------------------------------------------------------------
274 // A series of big-endian quantities: 1-8 bytes.
275 typedef any_int<host_int_1,true> big_int_1;
276 typedef any_int<host_int_2,true> big_int_2;
277 typedef any_int<host_int_4,true> big_int_4;
278 typedef any_int<host_int_8,true> big_int_8;
281 // A series of little-endian quantities: 1-8 bytes.
282 typedef any_int<host_int_1,false> little_int_1;
283 typedef any_int<host_int_2,false> little_int_2;
284 typedef any_int<host_int_4,false> little_int_4;
285 typedef any_int<host_int_8,false> little_int_8;