Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/tools/armips.cpp
7854 views
1
// armips assembler v0.11
2
// https://github.com/Kingcom/armips/
3
// To simplify compilation, all files have been concatenated into one.
4
// MIPS only, ARM is not included.
5
6
/*
7
The MIT License (MIT)
8
9
Copyright (c) 2009-2020 Kingcom
10
11
Permission is hereby granted, free of charge, to any person obtaining a copy
12
of this software and associated documentation files (the "Software"), to deal
13
in the Software without restriction, including without limitation the rights
14
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
copies of the Software, and to permit persons to whom the Software is
16
furnished to do so, subject to the following conditions:
17
18
The above copyright notice and this permission notice shall be included in all
19
copies or substantial portions of the Software.
20
21
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
SOFTWARE.
28
29
*/
30
31
// file: stdafx.h
32
33
34
#define _CRT_SECURE_NO_WARNINGS
35
// #undef __STRICT_ANSI__
36
37
#if defined(__clang__)
38
#if __has_feature(cxx_exceptions)
39
#define ARMIPS_EXCEPTIONS 1
40
#else
41
#define ARMIPS_EXCEPTIONS 0
42
#endif
43
#elif defined(_MSC_VER) && defined(_CPPUNWIND)
44
#define ARMIPS_EXCEPTIONS 1
45
#elif defined(__EXCEPTIONS) || defined(__cpp_exceptions)
46
#define ARMIPS_EXCEPTIONS 1
47
#else
48
#define ARMIPS_EXCEPTIONS 0
49
#endif
50
51
#include <cstdio>
52
#include <vector>
53
#include <cstdlib>
54
#include <cstdarg>
55
#include <cctype>
56
#include <cstring>
57
#include <cmath>
58
#include <clocale>
59
60
#include <sstream>
61
#include <iomanip>
62
#include <memory>
63
64
#define formatString tfm::format
65
66
// Custom make_unique so that C++14 support will not be necessary for compilation
67
template<typename T, typename... Args>
68
std::unique_ptr<T> make_unique(Args&&... args)
69
{
70
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
71
}
72
73
// file: ext/tinyformat/tinyformat.h
74
// tinyformat.h
75
// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
76
//
77
// Boost Software License - Version 1.0
78
//
79
// Permission is hereby granted, free of charge, to any person or organization
80
// obtaining a copy of the software and accompanying documentation covered by
81
// this license (the "Software") to use, reproduce, display, distribute,
82
// execute, and transmit the Software, and to prepare derivative works of the
83
// Software, and to permit third-parties to whom the Software is furnished to
84
// do so, all subject to the following:
85
//
86
// The copyright notices in the Software and this entire statement, including
87
// the above license grant, this restriction and the following disclaimer,
88
// must be included in all copies of the Software, in whole or in part, and
89
// all derivative works of the Software, unless such copies or derivative
90
// works are solely in the form of machine-executable object code generated by
91
// a source language processor.
92
//
93
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
94
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
95
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
96
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
97
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
98
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
99
// DEALINGS IN THE SOFTWARE.
100
101
//------------------------------------------------------------------------------
102
// Tinyformat: A minimal type safe printf replacement
103
//
104
// tinyformat.h is a type safe printf replacement library in a single C++
105
// header file. Design goals include:
106
//
107
// * Type safety and extensibility for user defined types.
108
// * C99 printf() compatibility, to the extent possible using std::wostream
109
// * Simplicity and minimalism. A single header file to include and distribute
110
// with your projects.
111
// * Augment rather than replace the standard stream formatting mechanism
112
// * C++98 support, with optional C++11 niceties
113
//
114
//
115
// Main interface example usage
116
// ----------------------------
117
//
118
// To print a date to std::wcout:
119
//
120
// std::wstring weekday = L"Wednesday";
121
// const wchar_t* month = L"July";
122
// size_t day = 27;
123
// long hour = 14;
124
// int min = 44;
125
//
126
// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
127
//
128
// The strange types here emphasize the type safety of the interface; it is
129
// possible to print a std::wstring using the "%s" conversion, and a
130
// size_t using the "%d" conversion. A similar result could be achieved
131
// using either of the tfm::format() functions. One prints on a user provided
132
// stream:
133
//
134
// tfm::format(std::cerr, L"%s, %s %d, %.2d:%.2d\n",
135
// weekday, month, day, hour, min);
136
//
137
// The other returns a std::wstring:
138
//
139
// std::wstring date = tfm::format(L"%s, %s %d, %.2d:%.2d\n",
140
// weekday, month, day, hour, min);
141
// std::wcout << date;
142
//
143
// These are the three primary interface functions. There is also a
144
// convenience function printfln() which appends a newline to the usual result
145
// of printf() for super simple logging.
146
//
147
//
148
// User defined format functions
149
// -----------------------------
150
//
151
// Simulating variadic templates in C++98 is pretty painful since it requires
152
// writing out the same function for each desired number of arguments. To make
153
// this bearable tinyformat comes with a set of macros which are used
154
// internally to generate the API, but which may also be used in user code.
155
//
156
// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and
157
// TINYFORMAT_PASSARGS(n) will generate a list of n argument types,
158
// type/name pairs and argument names respectively when called with an integer
159
// n between 1 and 16. We can use these to define a macro which generates the
160
// desired user defined function with n arguments. To generate all 16 user
161
// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
162
// example, see the implementation of printf() at the end of the source file.
163
//
164
// Sometimes it's useful to be able to pass a list of format arguments through
165
// to a non-template function. The FormatList class is provided as a way to do
166
// this by storing the argument list in a type-opaque way. Continuing the
167
// example from above, we construct a FormatList using makeFormatList():
168
//
169
// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min);
170
//
171
// The format list can now be passed into any non-template function and used
172
// via a call to the vformat() function:
173
//
174
// tfm::vformat(std::wcout, L"%s, %s %d, %.2d:%.2d\n", formatList);
175
//
176
//
177
// Additional API information
178
// --------------------------
179
//
180
// Error handling: Define TINYFORMAT_ERROR to customize the error handling for
181
// format strings which are unsupported or have the wrong number of format
182
// specifiers (calls assert() by default).
183
//
184
// User defined types: Uses operator<< for user defined types by default.
185
// Overload formatValue() for more control.
186
187
188
#ifndef TINYFORMAT_H_INCLUDED
189
#define TINYFORMAT_H_INCLUDED
190
191
namespace tinyformat {}
192
//------------------------------------------------------------------------------
193
// Config section. Customize to your liking!
194
195
// Namespace alias to encourage brevity
196
namespace tfm = tinyformat;
197
198
// Error handling; calls assert() by default.
199
// #define TINYFORMAT_ERROR(reasonString) your_error_handler(reasonString)
200
201
// Define for C++11 variadic templates which make the code shorter & more
202
// general. If you don't define this, C++11 support is autodetected below.
203
// #define TINYFORMAT_USE_VARIADIC_TEMPLATES
204
205
206
//------------------------------------------------------------------------------
207
// Implementation details.
208
#include <algorithm>
209
#include <iostream>
210
#include <sstream>
211
212
#ifndef TINYFORMAT_ASSERT
213
# include <cassert>
214
# define TINYFORMAT_ASSERT(cond) assert(cond)
215
#endif
216
217
#define TINYFORMAT_ALLOW_WCHAR_STRINGS
218
#define TINYFORMAT_USE_VARIADIC_TEMPLATES
219
220
#ifndef TINYFORMAT_ERROR
221
# include <cassert>
222
# include <cstdint>
223
# define TINYFORMAT_ERROR(reason) assert(0 && reason)
224
#endif
225
226
#if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)
227
# ifdef __GXX_EXPERIMENTAL_CXX0X__
228
# define TINYFORMAT_USE_VARIADIC_TEMPLATES
229
# endif
230
#endif
231
232
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
233
// std::showpos is broken on old libstdc++ as provided with OSX. See
234
// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
235
# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
236
#endif
237
238
#ifdef __APPLE__
239
// Workaround OSX linker warning: xcode uses different default symbol
240
// visibilities for static libs vs executables (see issue #25)
241
# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
242
#else
243
# define TINYFORMAT_HIDDEN
244
#endif
245
246
namespace tinyformat {
247
248
//------------------------------------------------------------------------------
249
namespace detail {
250
251
// Test whether type T1 is convertible to type T2
252
template <typename T1, typename T2>
253
struct is_convertible
254
{
255
private:
256
// two types of different size
257
struct fail { wchar_t dummy[2]; };
258
struct succeed { wchar_t dummy; };
259
// Try to convert a T1 to a T2 by plugging into tryConvert
260
static fail tryConvert(...);
261
static succeed tryConvert(const T2&);
262
static const T1& makeT1();
263
public:
264
# ifdef _MSC_VER
265
// Disable spurious loss of precision warnings in tryConvert(makeT1())
266
# pragma warning(push)
267
# pragma warning(disable:4244)
268
# pragma warning(disable:4267)
269
# endif
270
// Standard trick: the (...) version of tryConvert will be chosen from
271
// the overload set only if the version taking a T2 doesn't match.
272
// Then we compare the sizes of the return types to check which
273
// function matched. Very neat, in a disgusting kind of way :)
274
static const bool value =
275
sizeof(tryConvert(makeT1())) == sizeof(succeed);
276
# ifdef _MSC_VER
277
# pragma warning(pop)
278
# endif
279
};
280
281
282
// Detect when a type is not a wchar_t string
283
template<typename T> struct is_wchar { typedef int tinyformat_wchar_is_not_supported; };
284
template<> struct is_wchar<wchar_t*> {};
285
template<> struct is_wchar<const wchar_t*> {};
286
template<int n> struct is_wchar<const wchar_t[n]> {};
287
template<int n> struct is_wchar<wchar_t[n]> {};
288
289
290
// Format the value by casting to type fmtT. This default implementation
291
// should never be called.
292
template<typename T, typename fmtT, bool convertible = is_convertible<T, fmtT>::value>
293
struct formatValueAsType
294
{
295
static void invoke(std::wostream& /*out*/, const T& /*value*/) { TINYFORMAT_ASSERT(0); }
296
};
297
// Specialized version for types that can actually be converted to fmtT, as
298
// indicated by the "convertible" template parameter.
299
template<typename T, typename fmtT>
300
struct formatValueAsType<T,fmtT,true>
301
{
302
static void invoke(std::wostream& out, const T& value)
303
{ out << static_cast<fmtT>(value); }
304
};
305
306
#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
307
template<typename T, bool convertible = is_convertible<T, int>::value>
308
struct formatZeroIntegerWorkaround
309
{
310
static bool invoke(std::wostream& /**/, const T& /**/) { return false; }
311
};
312
template<typename T>
313
struct formatZeroIntegerWorkaround<T,true>
314
{
315
static bool invoke(std::wostream& out, const T& value)
316
{
317
if (static_cast<int>(value) == 0 && out.flags() & std::ios::showpos)
318
{
319
out << "+0";
320
return true;
321
}
322
return false;
323
}
324
};
325
#endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
326
327
// Convert an arbitrary type to integer. The version with convertible=false
328
// throws an error.
329
template<typename T, bool convertible = is_convertible<T,int>::value>
330
struct convertToInt
331
{
332
static int invoke(const T& /*value*/)
333
{
334
TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to "
335
"integer for use as variable width or precision");
336
return 0;
337
}
338
};
339
// Specialization for convertToInt when conversion is possible
340
template<typename T>
341
struct convertToInt<T,true>
342
{
343
static int invoke(const T& value) { return static_cast<int>(value); }
344
};
345
346
// Format at most ntrunc wchar_tacters to the given stream.
347
template<typename T>
348
inline void formatTruncated(std::wostream& out, const T& value, int ntrunc)
349
{
350
std::wostringstream tmp;
351
tmp << value;
352
std::wstring result = tmp.str();
353
out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size())));
354
}
355
#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \
356
inline void formatTruncated(std::wostream& out, type* value, int ntrunc) \
357
{ \
358
std::streamsize len = 0; \
359
while(len < ntrunc && value[len] != 0) \
360
++len; \
361
out.write(value, len); \
362
}
363
// Overload for const wchar_t* and wchar_t*. Could overload for signed & unsigned
364
// wchar_t too, but these are technically unneeded for printf compatibility.
365
TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const wchar_t)
366
TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(wchar_t)
367
#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
368
369
} // namespace detail
370
371
372
//------------------------------------------------------------------------------
373
// Variable formatting functions. May be overridden for user-defined types if
374
// desired.
375
376
377
/// Format a value into a stream, delegating to operator<< by default.
378
///
379
/// Users may override this for their own types. When this function is called,
380
/// the stream flags will have been modified according to the format string.
381
/// The format specification is provided in the range [fmtBegin, fmtEnd). For
382
/// truncating conversions, ntrunc is set to the desired maximum number of
383
/// characters, for example "%.7s" calls formatValue with ntrunc = 7.
384
///
385
/// By default, formatValue() uses the usual stream insertion operator
386
/// operator<< to format the type T, with special cases for the %c and %p
387
/// conversions.
388
template<typename T>
389
inline void formatValue(std::wostream& out, const wchar_t* /*fmtBegin*/,
390
const wchar_t* fmtEnd, int ntrunc, const T& value)
391
{
392
#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
393
// Since we don't support printing of wchar_t using "%ls", make it fail at
394
// compile time in preference to printing as a void* at runtime.
395
typedef typename detail::is_wchar<T>::tinyformat_wchar_is_not_supported DummyType;
396
(void) DummyType(); // avoid unused type warning with gcc-4.8
397
#endif
398
// The mess here is to support the %c and %p conversions: if these
399
// conversions are active we try to convert the type to a wchar_t or const
400
// void* respectively and format that instead of the value itself. For the
401
// %p conversion it's important to avoid dereferencing the pointer, which
402
// could otherwise lead to a crash when printing a dangling (const wchar_t*).
403
const bool canConvertToChar = detail::is_convertible<T,wchar_t>::value;
404
const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value;
405
if(canConvertToChar && *(fmtEnd-1) == 'c')
406
detail::formatValueAsType<T, wchar_t>::invoke(out, value);
407
else if(canConvertToVoidPtr && *(fmtEnd-1) == 'p')
408
detail::formatValueAsType<T, const void*>::invoke(out, value);
409
#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
410
else if(detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/;
411
#endif
412
else if(ntrunc >= 0)
413
{
414
// Take care not to overread C strings in truncating conversions like
415
// "%.4s" where at most 4 wchar_tacters may be read.
416
detail::formatTruncated(out, value, ntrunc);
417
}
418
else
419
out << value;
420
}
421
422
423
// Overloaded version for wchar_t types to support printing as an integer
424
#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(wchar_tType) \
425
inline void formatValue(std::wostream& out, const wchar_t* /*fmtBegin*/, \
426
const wchar_t* fmtEnd, int /**/, wchar_tType value) \
427
{ \
428
switch(*(fmtEnd-1)) \
429
{ \
430
case 'u': case 'd': case 'i': case 'o': case 'X': case 'x': \
431
out << static_cast<int>(value); break; \
432
default: \
433
out << value; break; \
434
} \
435
}
436
// per 3.9.1: char, signed char and unsigned char are all distinct types
437
TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)
438
TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)
439
TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char)
440
#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
441
442
443
//------------------------------------------------------------------------------
444
// Tools for emulating variadic templates in C++98. The basic idea here is
445
// stolen from the boost preprocessor metaprogramming library and cut down to
446
// be just general enough for what we need.
447
448
#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_ ## n
449
#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_ ## n
450
#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_ ## n
451
#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_ ## n
452
453
// To keep it as transparent as possible, the macros below have been generated
454
// using python via the excellent cog.py code generation script. This avoids
455
// the need for a bunch of complex (but more general) preprocessor tricks as
456
// used in boost.preprocessor.
457
//
458
// To rerun the code generation in place, use `cog.py -r tinyformat.h`
459
// (see http://nedbatchelder.com/code/cog). Alternatively you can just create
460
// extra versions by hand.
461
462
/*[[[cog
463
maxParams = 16
464
465
def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):
466
for j in range(startInd,maxParams+1):
467
list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])
468
cog.outl(lineTemplate % {'j':j, 'list':list})
469
470
makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',
471
'class T%(i)d')
472
473
cog.outl()
474
makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',
475
'const T%(i)d& v%(i)d')
476
477
cog.outl()
478
makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')
479
480
cog.outl()
481
cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')
482
makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',
483
'v%(i)d', startInd = 2)
484
485
cog.outl()
486
cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' +
487
' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))
488
]]]*/
489
#define TINYFORMAT_ARGTYPES_1 class T1
490
#define TINYFORMAT_ARGTYPES_2 class T1, class T2
491
#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3
492
#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4
493
#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5
494
#define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6
495
#define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7
496
#define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8
497
#define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9
498
#define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10
499
#define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11
500
#define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12
501
#define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13
502
#define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14
503
#define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15
504
#define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16
505
506
#define TINYFORMAT_VARARGS_1 const T1& v1
507
#define TINYFORMAT_VARARGS_2 const T1& v1, const T2& v2
508
#define TINYFORMAT_VARARGS_3 const T1& v1, const T2& v2, const T3& v3
509
#define TINYFORMAT_VARARGS_4 const T1& v1, const T2& v2, const T3& v3, const T4& v4
510
#define TINYFORMAT_VARARGS_5 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5
511
#define TINYFORMAT_VARARGS_6 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6
512
#define TINYFORMAT_VARARGS_7 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7
513
#define TINYFORMAT_VARARGS_8 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8
514
#define TINYFORMAT_VARARGS_9 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9
515
#define TINYFORMAT_VARARGS_10 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10
516
#define TINYFORMAT_VARARGS_11 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11
517
#define TINYFORMAT_VARARGS_12 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12
518
#define TINYFORMAT_VARARGS_13 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13
519
#define TINYFORMAT_VARARGS_14 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14
520
#define TINYFORMAT_VARARGS_15 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15
521
#define TINYFORMAT_VARARGS_16 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15, const T16& v16
522
523
#define TINYFORMAT_PASSARGS_1 v1
524
#define TINYFORMAT_PASSARGS_2 v1, v2
525
#define TINYFORMAT_PASSARGS_3 v1, v2, v3
526
#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4
527
#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5
528
#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6
529
#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7
530
#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8
531
#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9
532
#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
533
#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
534
#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
535
#define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
536
#define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
537
#define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
538
#define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
539
540
#define TINYFORMAT_PASSARGS_TAIL_1
541
#define TINYFORMAT_PASSARGS_TAIL_2 , v2
542
#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3
543
#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4
544
#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5
545
#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6
546
#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7
547
#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8
548
#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9
549
#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10
550
#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
551
#define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
552
#define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
553
#define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
554
#define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
555
#define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
556
557
#define TINYFORMAT_FOREACH_ARGNUM(m) \
558
m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16)
559
//[[[end]]]
560
561
562
563
namespace detail {
564
565
// Type-opaque holder for an argument to format(), with associated actions on
566
// the type held as explicit function pointers. This allows FormatArg's for
567
// each argument to be allocated as a homogenous array inside FormatList
568
// whereas a naive implementation based on inheritance does not.
569
class FormatArg
570
{
571
public:
572
FormatArg()
573
: m_value(NULL),
574
m_formatImpl(NULL),
575
m_toIntImpl(NULL)
576
{ }
577
578
template<typename T>
579
FormatArg(const T& value)
580
: m_value(static_cast<const void*>(&value)),
581
m_formatImpl(&formatImpl<T>),
582
m_toIntImpl(&toIntImpl<T>)
583
{ }
584
585
void format(std::wostream& out, const wchar_t* fmtBegin,
586
const wchar_t* fmtEnd, int ntrunc) const
587
{
588
TINYFORMAT_ASSERT(m_value);
589
TINYFORMAT_ASSERT(m_formatImpl);
590
m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
591
}
592
593
int toInt() const
594
{
595
TINYFORMAT_ASSERT(m_value);
596
TINYFORMAT_ASSERT(m_toIntImpl);
597
return m_toIntImpl(m_value);
598
}
599
600
private:
601
template<typename T>
602
TINYFORMAT_HIDDEN static void formatImpl(std::wostream& out, const wchar_t* fmtBegin,
603
const wchar_t* fmtEnd, int ntrunc, const void* value)
604
{
605
formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value));
606
}
607
608
template<typename T>
609
TINYFORMAT_HIDDEN static int toIntImpl(const void* value)
610
{
611
return convertToInt<T>::invoke(*static_cast<const T*>(value));
612
}
613
614
const void* m_value;
615
void (*m_formatImpl)(std::wostream& out, const wchar_t* fmtBegin,
616
const wchar_t* fmtEnd, int ntrunc, const void* value);
617
int (*m_toIntImpl)(const void* value);
618
};
619
620
621
// Parse and return an integer from the string c, as atoi()
622
// On return, c is set to one past the end of the integer.
623
inline int parseIntAndAdvance(const wchar_t*& c)
624
{
625
int i = 0;
626
for(;*c >= '0' && *c <= '9'; ++c)
627
i = 10*i + (*c - '0');
628
return i;
629
}
630
631
// Print literal part of format string and return next format spec
632
// position.
633
//
634
// Skips over any occurrences of '%%', printing a literal '%' to the
635
// output. The position of the first % character of the next
636
// nontrivial format spec is returned, or the end of string.
637
inline const wchar_t* printFormatStringLiteral(std::wostream& out, const wchar_t* fmt)
638
{
639
const wchar_t* c = fmt;
640
for(;; ++c)
641
{
642
switch(*c)
643
{
644
case '\0':
645
out.write(fmt, c - fmt);
646
return c;
647
case '%':
648
out.write(fmt, c - fmt);
649
if(*(c+1) != '%')
650
return c;
651
// for "%%", tack trailing % onto next literal section.
652
fmt = ++c;
653
break;
654
default:
655
break;
656
}
657
}
658
}
659
660
661
// Parse a format string and set the stream state accordingly.
662
//
663
// The format mini-language recognized here is meant to be the one from C99,
664
// with the form "%[flags][width][.precision][length]type".
665
//
666
// Formatting options which can't be natively represented using the ostream
667
// state are returned in spacePadPositive (for space padded positive numbers)
668
// and ntrunc (for truncating conversions). argIndex is incremented if
669
// necessary to pull out variable width and precision . The function returns a
670
// pointer to the wchar_tacter after the end of the current format spec.
671
inline const wchar_t* streamStateFromFormat(std::wostream& out, bool& spacePadPositive,
672
int& ntrunc, const wchar_t* fmtStart,
673
const detail::FormatArg* formatters,
674
int& argIndex, int numFormatters)
675
{
676
if(*fmtStart != '%')
677
{
678
TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string");
679
return fmtStart;
680
}
681
// Reset stream state to defaults.
682
out.width(0);
683
out.precision(6);
684
out.fill(' ');
685
// Reset most flags; ignore irrelevant unitbuf & skipws.
686
out.unsetf(std::ios::adjustfield | std::ios::basefield |
687
std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
688
std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
689
bool precisionSet = false;
690
bool widthSet = false;
691
int widthExtra = 0;
692
const wchar_t* c = fmtStart + 1;
693
// 1) Parse flags
694
for(;; ++c)
695
{
696
switch(*c)
697
{
698
case '#':
699
out.setf(std::ios::showpoint | std::ios::showbase);
700
continue;
701
case '0':
702
// overridden by left alignment ('-' flag)
703
if(!(out.flags() & std::ios::left))
704
{
705
// Use internal padding so that numeric values are
706
// formatted correctly, eg -00010 rather than 000-10
707
out.fill('0');
708
out.setf(std::ios::internal, std::ios::adjustfield);
709
}
710
continue;
711
case '-':
712
out.fill(' ');
713
out.setf(std::ios::left, std::ios::adjustfield);
714
continue;
715
case ' ':
716
// overridden by show positive sign, '+' flag.
717
if(!(out.flags() & std::ios::showpos))
718
spacePadPositive = true;
719
continue;
720
case '+':
721
out.setf(std::ios::showpos);
722
spacePadPositive = false;
723
widthExtra = 1;
724
continue;
725
default:
726
break;
727
}
728
break;
729
}
730
// 2) Parse width
731
if(*c >= '0' && *c <= '9')
732
{
733
widthSet = true;
734
out.width(parseIntAndAdvance(c));
735
}
736
if(*c == '*')
737
{
738
widthSet = true;
739
int width = 0;
740
if(argIndex < numFormatters)
741
width = formatters[argIndex++].toInt();
742
else
743
TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width");
744
if(width < 0)
745
{
746
// negative widths correspond to '-' flag set
747
out.fill(' ');
748
out.setf(std::ios::left, std::ios::adjustfield);
749
width = -width;
750
}
751
out.width(width);
752
++c;
753
}
754
// 3) Parse precision
755
if(*c == '.')
756
{
757
++c;
758
int precision = 0;
759
if(*c == '*')
760
{
761
++c;
762
if(argIndex < numFormatters)
763
precision = formatters[argIndex++].toInt();
764
else
765
TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision");
766
}
767
else
768
{
769
if(*c >= '0' && *c <= '9')
770
precision = parseIntAndAdvance(c);
771
else if(*c == '-') // negative precisions ignored, treated as zero.
772
parseIntAndAdvance(++c);
773
}
774
out.precision(precision);
775
precisionSet = true;
776
}
777
// 4) Ignore any C99 length modifier
778
while(*c == 'l' || *c == 'h' || *c == 'L' ||
779
*c == 'j' || *c == 'z' || *c == 't')
780
++c;
781
// 5) We're up to the conversion specifier character.
782
// Set stream flags based on conversion specifier (thanks to the
783
// boost::format class for forging the way here).
784
bool intConversion = false;
785
switch(*c)
786
{
787
case 'u': case 'd': case 'i':
788
out.setf(std::ios::dec, std::ios::basefield);
789
intConversion = true;
790
break;
791
case 'o':
792
out.setf(std::ios::oct, std::ios::basefield);
793
intConversion = true;
794
break;
795
case 'X':
796
out.setf(std::ios::uppercase);
797
// Falls through
798
case 'x': case 'p':
799
out.setf(std::ios::hex, std::ios::basefield);
800
intConversion = true;
801
break;
802
case 'E':
803
out.setf(std::ios::uppercase);
804
// Falls through
805
case 'e':
806
out.setf(std::ios::scientific, std::ios::floatfield);
807
out.setf(std::ios::dec, std::ios::basefield);
808
break;
809
case 'F':
810
out.setf(std::ios::uppercase);
811
// Falls through
812
case 'f':
813
out.setf(std::ios::fixed, std::ios::floatfield);
814
break;
815
case 'G':
816
out.setf(std::ios::uppercase);
817
// Falls through
818
case 'g':
819
out.setf(std::ios::dec, std::ios::basefield);
820
// As in boost::format, let stream decide float format.
821
out.flags(out.flags() & ~std::ios::floatfield);
822
break;
823
case 'a': case 'A':
824
TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs "
825
"are not supported");
826
break;
827
case 'c':
828
// Handled as special case inside formatValue()
829
break;
830
case 's':
831
if(precisionSet)
832
ntrunc = static_cast<int>(out.precision());
833
// Make %s print booleans as "true" and "false"
834
out.setf(std::ios::boolalpha);
835
break;
836
case 'n':
837
// Not supported - will cause problems!
838
TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported");
839
break;
840
case '\0':
841
TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
842
"terminated by end of string");
843
return c;
844
default:
845
break;
846
}
847
if(intConversion && precisionSet && !widthSet)
848
{
849
// "precision" for integers gives the minimum number of digits (to be
850
// padded with zeros on the left). This isn't really supported by the
851
// iostreams, but we can approximately simulate it with the width if
852
// the width isn't otherwise used.
853
out.width(out.precision() + widthExtra);
854
out.setf(std::ios::internal, std::ios::adjustfield);
855
out.fill('0');
856
}
857
return c+1;
858
}
859
860
861
//------------------------------------------------------------------------------
862
inline void formatImpl(std::wostream& out, const wchar_t* fmt,
863
const detail::FormatArg* formatters,
864
int numFormatters)
865
{
866
// Saved stream state
867
std::streamsize origWidth = out.width();
868
std::streamsize origPrecision = out.precision();
869
std::ios::fmtflags origFlags = out.flags();
870
wchar_t origFill = out.fill();
871
872
for (int argIndex = 0; argIndex < numFormatters; ++argIndex)
873
{
874
// Parse the format string
875
fmt = printFormatStringLiteral(out, fmt);
876
bool spacePadPositive = false;
877
int ntrunc = -1;
878
const wchar_t* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt,
879
formatters, argIndex, numFormatters);
880
if (argIndex >= numFormatters)
881
{
882
// Check args remain after reading any variable width/precision
883
TINYFORMAT_ERROR("tinyformat: Not enough format arguments");
884
return;
885
}
886
const FormatArg& arg = formatters[argIndex];
887
// Format the arg into the stream.
888
if(!spacePadPositive)
889
arg.format(out, fmt, fmtEnd, ntrunc);
890
else
891
{
892
// The following is a special case with no direct correspondence
893
// between stream formatting and the printf() behaviour. Simulate
894
// it crudely by formatting into a temporary string stream and
895
// munging the resulting string.
896
std::wostringstream tmpStream;
897
tmpStream.copyfmt(out);
898
tmpStream.setf(std::ios::showpos);
899
arg.format(tmpStream, fmt, fmtEnd, ntrunc);
900
std::wstring result = tmpStream.str(); // allocates... yuck.
901
for(size_t i = 0, iend = result.size(); i < iend; ++i)
902
if(result[i] == '+') result[i] = ' ';
903
out << result;
904
}
905
fmt = fmtEnd;
906
}
907
908
// Print remaining part of format string.
909
fmt = printFormatStringLiteral(out, fmt);
910
if(*fmt != '\0')
911
TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
912
913
// Restore stream state
914
out.width(origWidth);
915
out.precision(origPrecision);
916
out.flags(origFlags);
917
out.fill(origFill);
918
}
919
920
} // namespace detail
921
922
923
/// List of template arguments format(), held in a type-opaque way.
924
///
925
/// A const reference to FormatList (typedef'd as FormatListRef) may be
926
/// conveniently used to pass arguments to non-template functions: All type
927
/// information has been stripped from the arguments, leaving just enough of a
928
/// common interface to perform formatting as required.
929
class FormatList
930
{
931
public:
932
FormatList(detail::FormatArg* formatters, int N)
933
: m_formatters(formatters), m_N(N) { }
934
935
friend void vformat(std::wostream& out, const wchar_t* fmt,
936
const FormatList& list);
937
938
private:
939
const detail::FormatArg* m_formatters;
940
int m_N;
941
};
942
943
/// Reference to type-opaque format list for passing to vformat()
944
typedef const FormatList& FormatListRef;
945
946
947
namespace detail {
948
949
// Format list subclass with fixed storage to avoid dynamic allocation
950
template<int N>
951
class FormatListN : public FormatList
952
{
953
public:
954
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
955
template<typename... Args>
956
FormatListN(const Args&... args)
957
: FormatList(&m_formatterStore[0], N),
958
m_formatterStore { FormatArg(args)... }
959
{ static_assert(sizeof...(args) == N, "Number of args must be N"); }
960
#else // C++98 version
961
void init(int) {}
962
# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
963
\
964
template<TINYFORMAT_ARGTYPES(n)> \
965
FormatListN(TINYFORMAT_VARARGS(n)) \
966
: FormatList(&m_formatterStore[0], n) \
967
{ TINYFORMAT_ASSERT(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
968
\
969
template<TINYFORMAT_ARGTYPES(n)> \
970
void init(int i, TINYFORMAT_VARARGS(n)) \
971
{ \
972
m_formatterStore[i] = FormatArg(v1); \
973
init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \
974
}
975
976
TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)
977
# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
978
#endif
979
980
private:
981
FormatArg m_formatterStore[N];
982
};
983
984
// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard
985
template<> class FormatListN<0> : public FormatList
986
{
987
public: FormatListN() : FormatList(0, 0) {}
988
};
989
990
} // namespace detail
991
992
993
//------------------------------------------------------------------------------
994
// Primary API functions
995
996
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
997
998
/// Make type-agnostic format list from list of template arguments.
999
///
1000
/// The exact return type of this function is an implementation detail and
1001
/// shouldn't be relied upon. Instead it should be stored as a FormatListRef:
1002
///
1003
/// FormatListRef formatList = makeFormatList( /*...*/ );
1004
template<typename... Args>
1005
detail::FormatListN<sizeof...(Args)> makeFormatList(const Args&... args)
1006
{
1007
return detail::FormatListN<sizeof...(args)>(args...);
1008
}
1009
1010
#else // C++98 version
1011
1012
inline detail::FormatListN<0> makeFormatList()
1013
{
1014
return detail::FormatListN<0>();
1015
}
1016
#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \
1017
template<TINYFORMAT_ARGTYPES(n)> \
1018
detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) \
1019
{ \
1020
return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n)); \
1021
}
1022
TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)
1023
#undef TINYFORMAT_MAKE_MAKEFORMATLIST
1024
1025
#endif
1026
1027
/// Format list of arguments to the stream according to the given format string.
1028
///
1029
/// The name vformat() is chosen for the semantic similarity to vprintf(): the
1030
/// list of format arguments is held in a single function argument.
1031
inline void vformat(std::wostream& out, const wchar_t* fmt, FormatListRef list)
1032
{
1033
detail::formatImpl(out, fmt, list.m_formatters, list.m_N);
1034
}
1035
1036
1037
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
1038
1039
/// Format list of arguments to the stream according to given format string.
1040
template<typename... Args>
1041
void format(std::wostream& out, const wchar_t* fmt, const Args&... args)
1042
{
1043
vformat(out, fmt, makeFormatList(args...));
1044
}
1045
1046
/// Format list of arguments according to the given format string and return
1047
/// the result as a string.
1048
template<typename... Args>
1049
std::wstring format(const wchar_t* fmt, const Args&... args)
1050
{
1051
std::wostringstream oss;
1052
format(oss, fmt, args...);
1053
return oss.str();
1054
}
1055
1056
/// Format list of arguments to std::wcout, according to the given format string
1057
template<typename... Args>
1058
void printf(const wchar_t* fmt, const Args&... args)
1059
{
1060
format(std::wcout, fmt, args...);
1061
}
1062
1063
template<typename... Args>
1064
void printfln(const wchar_t* fmt, const Args&... args)
1065
{
1066
format(std::wcout, fmt, args...);
1067
std::wcout << '\n';
1068
}
1069
1070
1071
#else // C++98 version
1072
1073
inline void format(std::wostream& out, const wchar_t* fmt)
1074
{
1075
vformat(out, fmt, makeFormatList());
1076
}
1077
1078
inline std::wstring format(const wchar_t* fmt)
1079
{
1080
std::wostringstream oss;
1081
format(oss, fmt);
1082
return oss.str();
1083
}
1084
1085
inline void printf(const wchar_t* fmt)
1086
{
1087
format(std::wcout, fmt);
1088
}
1089
1090
inline void printfln(const wchar_t* fmt)
1091
{
1092
format(std::wcout, fmt);
1093
std::wcout << '\n';
1094
}
1095
1096
#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \
1097
\
1098
template<TINYFORMAT_ARGTYPES(n)> \
1099
void format(std::wostream& out, const wchar_t* fmt, TINYFORMAT_VARARGS(n)) \
1100
{ \
1101
vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \
1102
} \
1103
\
1104
template<TINYFORMAT_ARGTYPES(n)> \
1105
std::wstring format(const wchar_t* fmt, TINYFORMAT_VARARGS(n)) \
1106
{ \
1107
std::wostringstream oss; \
1108
format(oss, fmt, TINYFORMAT_PASSARGS(n)); \
1109
return oss.str(); \
1110
} \
1111
\
1112
template<TINYFORMAT_ARGTYPES(n)> \
1113
void printf(const wchar_t* fmt, TINYFORMAT_VARARGS(n)) \
1114
{ \
1115
format(std::wcout, fmt, TINYFORMAT_PASSARGS(n)); \
1116
} \
1117
\
1118
template<TINYFORMAT_ARGTYPES(n)> \
1119
void printfln(const wchar_t* fmt, TINYFORMAT_VARARGS(n)) \
1120
{ \
1121
format(std::wcout, fmt, TINYFORMAT_PASSARGS(n)); \
1122
std::wcout << '\n'; \
1123
}
1124
1125
TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
1126
#undef TINYFORMAT_MAKE_FORMAT_FUNCS
1127
1128
#endif
1129
1130
1131
} // namespace tinyformat
1132
1133
#endif // TINYFORMAT_H_INCLUDED
1134
1135
// file: Commands/CAssemblerCommand.h
1136
1137
class TempData;
1138
class SymbolData;
1139
1140
class CAssemblerCommand
1141
{
1142
public:
1143
CAssemblerCommand();
1144
virtual ~CAssemblerCommand() { };
1145
virtual bool Validate() = 0;
1146
virtual void Encode() const = 0;
1147
virtual void writeTempData(TempData& tempData) const = 0;
1148
virtual void writeSymData(SymbolData& symData) const { };
1149
void applyFileInfo();
1150
int getSection() { return section; }
1151
void updateSection(int num) { section = num; }
1152
protected:
1153
int FileNum;
1154
int FileLine;
1155
private:
1156
int section;
1157
};
1158
1159
class DummyCommand: public CAssemblerCommand
1160
{
1161
public:
1162
virtual bool Validate() { return false; };
1163
virtual void Encode() const { };
1164
virtual void writeTempData(TempData& tempData) const { };
1165
virtual void writeSymData(SymbolData& symData) const { };
1166
};
1167
1168
class InvalidCommand: public CAssemblerCommand
1169
{
1170
public:
1171
virtual bool Validate() { return false; };
1172
virtual void Encode() const { };
1173
virtual void writeTempData(TempData& tempData) const { };
1174
virtual void writeSymData(SymbolData& symData) const { };
1175
};
1176
1177
// file: Core/Expression.h
1178
#include <memory>
1179
1180
inline std::wstring to_wstring(int64_t value)
1181
{
1182
return formatString(L"%d", value);
1183
}
1184
1185
inline std::wstring to_wstring(double value)
1186
{
1187
return formatString(L"%#.17g", value);
1188
}
1189
1190
enum class OperatorType
1191
{
1192
Invalid,
1193
Integer,
1194
Float,
1195
Identifier,
1196
String,
1197
MemoryPos,
1198
Add,
1199
Sub,
1200
Mult,
1201
Div,
1202
Mod,
1203
Neg,
1204
LogNot,
1205
BitNot,
1206
LeftShift,
1207
RightShift,
1208
Less,
1209
Greater,
1210
LessEqual,
1211
GreaterEqual,
1212
Equal,
1213
NotEqual,
1214
BitAnd,
1215
Xor,
1216
BitOr,
1217
LogAnd,
1218
LogOr,
1219
TertiaryIf,
1220
ToString,
1221
FunctionCall
1222
};
1223
1224
enum class ExpressionValueType { Invalid, Integer, Float, String};
1225
1226
struct ExpressionValue
1227
{
1228
ExpressionValueType type;
1229
1230
ExpressionValue()
1231
{
1232
type = ExpressionValueType::Invalid;
1233
}
1234
1235
ExpressionValue(int64_t value)
1236
{
1237
type = ExpressionValueType::Integer;
1238
intValue = value;
1239
}
1240
1241
ExpressionValue(double value)
1242
{
1243
type = ExpressionValueType::Float;
1244
floatValue = value;
1245
}
1246
1247
ExpressionValue(const std::wstring& value)
1248
{
1249
type = ExpressionValueType::String;
1250
strValue = value;
1251
}
1252
1253
bool isFloat() const
1254
{
1255
return type == ExpressionValueType::Float;
1256
}
1257
1258
bool isInt() const
1259
{
1260
return type == ExpressionValueType::Integer;
1261
}
1262
1263
bool isString() const
1264
{
1265
return type == ExpressionValueType::String;
1266
}
1267
1268
bool isValid() const
1269
{
1270
return type != ExpressionValueType::Invalid;
1271
}
1272
1273
struct
1274
{
1275
int64_t intValue;
1276
double floatValue;
1277
};
1278
1279
std::wstring strValue;
1280
1281
ExpressionValue operator!() const;
1282
ExpressionValue operator~() const;
1283
bool operator<(const ExpressionValue& other) const;
1284
bool operator<=(const ExpressionValue& other) const;
1285
bool operator>(const ExpressionValue& other) const;
1286
bool operator>=(const ExpressionValue& other) const;
1287
bool operator==(const ExpressionValue& other) const;
1288
bool operator!=(const ExpressionValue& other) const;
1289
ExpressionValue operator+(const ExpressionValue& other) const;
1290
ExpressionValue operator-(const ExpressionValue& other) const;
1291
ExpressionValue operator*(const ExpressionValue& other) const;
1292
ExpressionValue operator/(const ExpressionValue& other) const;
1293
ExpressionValue operator%(const ExpressionValue& other) const;
1294
ExpressionValue operator<<(const ExpressionValue& other) const;
1295
ExpressionValue operator>>(const ExpressionValue& other) const;
1296
ExpressionValue operator&(const ExpressionValue& other) const;
1297
ExpressionValue operator|(const ExpressionValue& other) const;
1298
ExpressionValue operator&&(const ExpressionValue& other) const;
1299
ExpressionValue operator||(const ExpressionValue& other) const;
1300
ExpressionValue operator^(const ExpressionValue& other) const;
1301
};
1302
1303
class Label;
1304
1305
struct ExpressionFunctionEntry;
1306
struct ExpressionLabelFunctionEntry;
1307
1308
class ExpressionInternal
1309
{
1310
public:
1311
ExpressionInternal();
1312
~ExpressionInternal();
1313
ExpressionInternal(int64_t value);
1314
ExpressionInternal(double value);
1315
ExpressionInternal(const std::wstring& value, OperatorType type);
1316
ExpressionInternal(OperatorType op, ExpressionInternal* a = nullptr,
1317
ExpressionInternal* b = nullptr, ExpressionInternal* c = nullptr);
1318
ExpressionInternal(const std::wstring& name, const std::vector<ExpressionInternal*>& parameters);
1319
ExpressionValue evaluate();
1320
std::wstring toString();
1321
bool isIdentifier() { return type == OperatorType::Identifier; }
1322
std::wstring getStringValue() { return strValue; }
1323
void replaceMemoryPos(const std::wstring& identifierName);
1324
bool simplify(bool inUnknownOrFalseBlock);
1325
unsigned int getFileNum() { return fileNum; }
1326
unsigned int getSection() { return section; }
1327
private:
1328
void allocate(size_t count);
1329
void deallocate();
1330
std::wstring formatFunctionCall();
1331
ExpressionValue executeExpressionFunctionCall(const ExpressionFunctionEntry& entry);
1332
ExpressionValue executeExpressionLabelFunctionCall(const ExpressionLabelFunctionEntry& entry);
1333
ExpressionValue executeFunctionCall();
1334
bool checkParameterCount(size_t min, size_t max);
1335
1336
OperatorType type;
1337
ExpressionInternal** children;
1338
size_t childrenCount;
1339
1340
union
1341
{
1342
int64_t intValue;
1343
double floatValue;
1344
};
1345
std::wstring strValue;
1346
1347
unsigned int fileNum, section;
1348
};
1349
1350
class Expression
1351
{
1352
public:
1353
Expression();
1354
ExpressionValue evaluate();
1355
bool isLoaded() const { return expression != nullptr; }
1356
void setExpression(ExpressionInternal* exp, bool inUnknownOrFalseBlock);
1357
void replaceMemoryPos(const std::wstring& identifierName);
1358
bool isConstExpression() { return constExpression; }
1359
1360
template<typename T>
1361
bool evaluateInteger(T& dest)
1362
{
1363
if (expression == nullptr)
1364
return false;
1365
1366
ExpressionValue value = expression->evaluate();
1367
if (value.isInt() == false)
1368
return false;
1369
1370
dest = (T) value.intValue;
1371
return true;
1372
}
1373
1374
bool evaluateString(std::wstring& dest, bool convert)
1375
{
1376
if (expression == nullptr)
1377
return false;
1378
1379
ExpressionValue value = expression->evaluate();
1380
if (convert && value.isInt())
1381
{
1382
dest = to_wstring(value.intValue);
1383
return true;
1384
}
1385
1386
if (convert && value.isFloat())
1387
{
1388
dest = to_wstring(value.floatValue);
1389
return true;
1390
}
1391
1392
if (value.isString() == false)
1393
return false;
1394
1395
dest = value.strValue;
1396
return true;
1397
}
1398
1399
bool evaluateIdentifier(std::wstring& dest)
1400
{
1401
if (expression == nullptr || expression->isIdentifier() == false)
1402
return false;
1403
1404
dest = expression->getStringValue();
1405
return true;
1406
}
1407
1408
std::wstring toString() { return expression != nullptr ? expression->toString() : L""; };
1409
private:
1410
std::shared_ptr<ExpressionInternal> expression;
1411
std::wstring originalText;
1412
bool constExpression;
1413
};
1414
1415
Expression createConstExpression(int64_t value);
1416
1417
// file: Core/ExpressionFunctions.h
1418
#include <map>
1419
1420
bool getExpFuncParameter(const std::vector<ExpressionValue>& parameters, size_t index, int64_t& dest,
1421
const std::wstring& funcName, bool optional);
1422
1423
bool getExpFuncParameter(const std::vector<ExpressionValue>& parameters, size_t index, const std::wstring*& dest,
1424
const std::wstring& funcName, bool optional);
1425
1426
using ExpressionFunction = ExpressionValue (*)(const std::wstring& funcName, const std::vector<ExpressionValue>&);
1427
using ExpressionLabelFunction = ExpressionValue (*)(const std::wstring& funcName, const std::vector<std::shared_ptr<Label>> &);
1428
1429
enum class ExpFuncSafety
1430
{
1431
// Result may depend entirely on the internal state
1432
Unsafe,
1433
// Result is unsafe in conditional blocks, safe otherwise
1434
ConditionalUnsafe,
1435
// Result is completely independent of the internal state
1436
Safe,
1437
};
1438
1439
struct ExpressionFunctionEntry
1440
{
1441
ExpressionFunction function;
1442
size_t minParams;
1443
size_t maxParams;
1444
ExpFuncSafety safety;
1445
};
1446
1447
struct ExpressionLabelFunctionEntry
1448
{
1449
ExpressionLabelFunction function;
1450
size_t minParams;
1451
size_t maxParams;
1452
ExpFuncSafety safety;
1453
};
1454
1455
1456
using ExpressionFunctionMap = std::map<std::wstring, const ExpressionFunctionEntry>;
1457
using ExpressionLabelFunctionMap = std::map<std::wstring, const ExpressionLabelFunctionEntry>;
1458
1459
extern const ExpressionFunctionMap expressionFunctions;
1460
extern const ExpressionLabelFunctionMap expressionLabelFunctions;
1461
1462
// file: Core/SymbolData.h
1463
#include <set>
1464
1465
class AssemblerFile;
1466
1467
struct SymDataSymbol
1468
{
1469
std::wstring name;
1470
int64_t address;
1471
1472
bool operator<(const SymDataSymbol& other) const
1473
{
1474
return address < other.address;
1475
}
1476
};
1477
1478
struct SymDataAddressInfo
1479
{
1480
int64_t address;
1481
size_t fileIndex;
1482
size_t lineNumber;
1483
1484
bool operator<(const SymDataAddressInfo& other) const
1485
{
1486
return address < other.address;
1487
}
1488
};
1489
1490
struct SymDataFunction
1491
{
1492
int64_t address;
1493
size_t size;
1494
1495
bool operator<(const SymDataFunction& other) const
1496
{
1497
return address < other.address;
1498
}
1499
};
1500
1501
struct SymDataData
1502
{
1503
int64_t address;
1504
size_t size;
1505
int type;
1506
1507
bool operator<(const SymDataData& other) const
1508
{
1509
if (address != other.address)
1510
return address < other.address;
1511
1512
if (size != other.size)
1513
return size < other.size;
1514
1515
return type < other.type;
1516
}
1517
};
1518
1519
struct SymDataModule
1520
{
1521
AssemblerFile* file;
1522
std::vector<SymDataSymbol> symbols;
1523
std::vector<SymDataFunction> functions;
1524
std::set<SymDataData> data;
1525
};
1526
1527
struct SymDataModuleInfo
1528
{
1529
unsigned int crc32;
1530
};
1531
1532
class SymbolData
1533
{
1534
public:
1535
enum DataType { Data8, Data16, Data32, Data64, DataAscii };
1536
1537
SymbolData();
1538
void clear();
1539
void setNocashSymFileName(const std::wstring& name, int version) { nocashSymFileName = name; nocashSymVersion = version; };
1540
void write();
1541
void setEnabled(bool b) { enabled = b; };
1542
1543
void addLabel(int64_t address, const std::wstring& name);
1544
void addData(int64_t address, size_t size, DataType type);
1545
void startModule(AssemblerFile* file);
1546
void endModule(AssemblerFile* file);
1547
void startFunction(int64_t address);
1548
void endFunction(int64_t address);
1549
private:
1550
void writeNocashSym();
1551
size_t addFileName(const std::wstring& fileName);
1552
1553
std::wstring nocashSymFileName;
1554
bool enabled;
1555
int nocashSymVersion;
1556
1557
// entry 0 is for data without parent modules
1558
std::vector<SymDataModule> modules;
1559
std::vector<std::wstring> files;
1560
int currentModule;
1561
int currentFunction;
1562
};
1563
1564
// file: Util/Util.h
1565
#include <string>
1566
#include <stdio.h>
1567
1568
1569
typedef std::vector<std::wstring> StringList;
1570
1571
std::wstring convertUtf8ToWString(const char* source);
1572
std::string convertWCharToUtf8(wchar_t character);
1573
;std::string convertWStringToUtf8(const std::wstring& source);
1574
1575
std::wstring intToHexString(unsigned int value, int digits, bool prefix = false);
1576
std::wstring intToString(unsigned int value, int digits);
1577
bool stringToInt(const std::wstring& line, size_t start, size_t end, int64_t& result);
1578
int32_t getFloatBits(float value);
1579
float bitsToFloat(int32_t value);
1580
int64_t getDoubleBits(double value);
1581
1582
StringList getStringListFromArray(wchar_t** source, int count);
1583
StringList splitString(const std::wstring& str, const wchar_t delim, bool skipEmpty);
1584
1585
int64_t fileSize(const std::wstring& fileName);
1586
bool fileExists(const std::wstring& strFilename);
1587
bool copyFile(const std::wstring& existingFile, const std::wstring& newFile);
1588
bool deleteFile(const std::wstring& fileName);;
1589
1590
std::wstring toWLowercase(const std::string& str);
1591
std::wstring getFileNameFromPath(const std::wstring& path);
1592
size_t replaceAll(std::wstring& str, const wchar_t* oldValue,const std::wstring& newValue);
1593
bool startsWith(const std::wstring& str, const wchar_t* value, size_t stringPos = 0);
1594
1595
enum class OpenFileMode { ReadBinary, WriteBinary, ReadWriteBinary };
1596
FILE* openFile(const std::wstring& fileName, OpenFileMode mode);
1597
std::wstring getCurrentDirectory();
1598
bool changeDirectory(const std::wstring& dir);
1599
bool isAbsolutePath(const std::wstring& path);
1600
1601
#ifndef ARRAY_SIZE
1602
#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
1603
#endif
1604
1605
// file: Util/FileClasses.h
1606
#include <list>
1607
1608
class BinaryFile
1609
{
1610
public:
1611
enum Mode { Read, Write, ReadWrite };
1612
1613
BinaryFile();
1614
~BinaryFile();
1615
1616
bool open(const std::wstring& fileName, Mode mode);
1617
bool open(Mode mode);
1618
bool isOpen() { return handle != nullptr; };
1619
bool atEnd() { return isOpen() && mode != Write && ftell(handle) == size_; };
1620
void setPos(long pos) { if (isOpen()) fseek(handle,pos,SEEK_SET); };
1621
long pos() { return isOpen() ? ftell(handle) : -1; }
1622
long size() { return size_; };
1623
void close();
1624
1625
void setFileName(const std::wstring& name) { fileName = name; };
1626
const std::wstring& getFileName() { return fileName; };
1627
1628
size_t read(void* dest, size_t length);
1629
size_t write(void* source, size_t length);
1630
private:
1631
FILE* handle;
1632
std::wstring fileName;
1633
Mode mode;
1634
long size_;
1635
};
1636
1637
class TextFile
1638
{
1639
public:
1640
enum Encoding { ASCII, UTF8, UTF16LE, UTF16BE, SJIS, GUESS };
1641
enum Mode { Read, Write };
1642
1643
TextFile();
1644
~TextFile();
1645
void openMemory(const std::wstring& content);
1646
bool open(const std::wstring& fileName, Mode mode, Encoding defaultEncoding = GUESS);
1647
bool open(Mode mode, Encoding defaultEncoding = GUESS);
1648
bool isOpen() { return fromMemory || handle != nullptr; };
1649
bool atEnd() { return isOpen() && mode == Read && tell() >= size_; };
1650
long size() { return size_; };
1651
void close();
1652
1653
bool hasGuessedEncoding() { return guessedEncoding; };
1654
bool isFromMemory() { return fromMemory; }
1655
int getNumLines() { return lineCount; }
1656
1657
void setFileName(const std::wstring& name) { fileName = name; };
1658
const std::wstring& getFileName() { return fileName; };
1659
1660
wchar_t readCharacter();
1661
std::wstring readLine();
1662
StringList readAll();
1663
void writeCharacter(wchar_t character);
1664
void write(const wchar_t* line);
1665
void write(const std::wstring& line);
1666
void write(const char* value);
1667
void write(const std::string& value);
1668
void writeLine(const wchar_t* line);
1669
void writeLine(const std::wstring& line);
1670
void writeLine(const char* line);
1671
void writeLine(const std::string& line);
1672
void writeLines(StringList& list);
1673
1674
template <typename... Args>
1675
void writeFormat(const wchar_t* text, const Args&... args)
1676
{
1677
std::wstring message = formatString(text,args...);
1678
write(message);
1679
}
1680
1681
bool hasError() { return errorText.size() != 0 && !errorRetrieved; };
1682
const std::wstring& getErrorText() { errorRetrieved = true; return errorText; };
1683
private:
1684
long tell();
1685
void seek(long pos);
1686
1687
FILE* handle;
1688
std::wstring fileName;
1689
Encoding encoding;
1690
Mode mode;
1691
bool recursion;
1692
bool guessedEncoding;
1693
long size_;
1694
std::wstring errorText;
1695
bool errorRetrieved;
1696
bool fromMemory;
1697
std::wstring content;
1698
size_t contentPos;
1699
int lineCount;
1700
1701
std::string buf;
1702
size_t bufPos;
1703
1704
inline unsigned char bufGetChar()
1705
{
1706
if (buf.size() <= bufPos)
1707
{
1708
bufFillRead();
1709
if (buf.size() == 0)
1710
return 0;
1711
}
1712
return buf[bufPos++];
1713
}
1714
inline unsigned short bufGet16LE()
1715
{
1716
char c1 = bufGetChar();
1717
char c2 = bufGetChar();
1718
return c1 | (c2 << 8);
1719
}
1720
inline unsigned short bufGet16BE()
1721
{
1722
char c1 = bufGetChar();
1723
char c2 = bufGetChar();
1724
return c2 | (c1 << 8);
1725
}
1726
1727
void bufPut(const void *p, const size_t len);
1728
void bufPut(const char c);
1729
1730
void bufFillRead();
1731
void bufDrainWrite();
1732
};
1733
1734
wchar_t sjisToUnicode(unsigned short);
1735
TextFile::Encoding getEncodingFromString(const std::wstring& str);
1736
1737
// file: Util/ByteArray.h
1738
1739
#include <sys/types.h>
1740
1741
#if defined(_MSC_VER) && !defined(ssize_t)
1742
typedef intptr_t ssize_t;
1743
#endif
1744
1745
typedef unsigned char byte;
1746
1747
enum class Endianness { Big, Little };
1748
1749
class ByteArray
1750
{
1751
public:
1752
ByteArray();
1753
ByteArray(const ByteArray& other);
1754
ByteArray(byte* data, size_t size);
1755
ByteArray(ByteArray&& other);
1756
~ByteArray();
1757
ByteArray& operator=(ByteArray& other);
1758
ByteArray& operator=(ByteArray&& other);
1759
1760
size_t append(const ByteArray& other);
1761
size_t append(void* data, size_t size);
1762
size_t appendByte(byte b) { return append(&b,1); };
1763
void replaceByte(size_t pos, byte b) { data_[pos] = b; };
1764
void replaceBytes(size_t pos, byte* data, size_t size);
1765
void reserveBytes(size_t count, byte value = 0);
1766
void alignSize(size_t alignment);
1767
1768
int getWord(size_t pos, Endianness endianness = Endianness::Little) const
1769
{
1770
if (pos+1 >= this->size()) return -1;
1771
unsigned char* d = (unsigned char*) this->data();
1772
1773
if (endianness == Endianness::Little)
1774
{
1775
return d[pos+0] | (d[pos+1] << 8);
1776
} else {
1777
return d[pos+1] | (d[pos+0] << 8);
1778
}
1779
}
1780
1781
int getDoubleWord(size_t pos, Endianness endianness = Endianness::Little) const
1782
{
1783
if (pos+3 >= this->size()) return -1;
1784
unsigned char* d = (unsigned char*) this->data();
1785
1786
if (endianness == Endianness::Little)
1787
{
1788
return d[pos+0] | (d[pos+1] << 8) | (d[pos+2] << 16) | (d[pos+3] << 24);
1789
} else {
1790
return d[pos+3] | (d[pos+2] << 8) | (d[pos+1] << 16) | (d[pos+0] << 24);
1791
}
1792
}
1793
1794
void replaceWord(size_t pos, unsigned int w, Endianness endianness = Endianness::Little)
1795
{
1796
if (pos+1 >= this->size()) return;
1797
unsigned char* d = (unsigned char*) this->data();
1798
1799
if (endianness == Endianness::Little)
1800
{
1801
d[pos+0] = w & 0xFF;
1802
d[pos+1] = (w >> 8) & 0xFF;
1803
} else {
1804
d[pos+0] = (w >> 8) & 0xFF;
1805
d[pos+1] = w & 0xFF;
1806
}
1807
}
1808
1809
void replaceDoubleWord(size_t pos, unsigned int w, Endianness endianness = Endianness::Little)
1810
{
1811
if (pos+3 >= this->size()) return;
1812
unsigned char* d = (unsigned char*) this->data();
1813
1814
if (endianness == Endianness::Little)
1815
{
1816
d[pos+0] = w & 0xFF;
1817
d[pos+1] = (w >> 8) & 0xFF;
1818
d[pos+2] = (w >> 16) & 0xFF;
1819
d[pos+3] = (w >> 24) & 0xFF;
1820
} else {
1821
d[pos+0] = (w >> 24) & 0xFF;
1822
d[pos+1] = (w >> 16) & 0xFF;
1823
d[pos+2] = (w >> 8) & 0xFF;
1824
d[pos+3] = w & 0xFF;
1825
}
1826
}
1827
1828
byte& operator [](size_t index)
1829
{
1830
return data_[index];
1831
};
1832
1833
const byte& operator [](size_t index) const
1834
{
1835
return data_[index];
1836
};
1837
1838
size_t size() const { return size_; };
1839
byte* data(size_t pos = 0) const { return &data_[pos]; };
1840
void clear() { size_ = 0; };
1841
void resize(size_t newSize);
1842
ByteArray mid(size_t start, ssize_t length = 0);
1843
ByteArray left(size_t length) { return mid(0,length); };
1844
ByteArray right(size_t length) { return mid(size_-length,length); };
1845
1846
static ByteArray fromFile(const std::wstring& fileName, long start = 0, size_t size = 0);
1847
bool toFile(const std::wstring& fileName);
1848
private:
1849
void grow(size_t neededSize);
1850
byte* data_;
1851
size_t size_;
1852
size_t allocatedSize_;
1853
};
1854
1855
// file: Core/FileManager.h
1856
#include <vector>
1857
1858
class AssemblerFile
1859
{
1860
public:
1861
virtual ~AssemblerFile() { };
1862
1863
virtual bool open(bool onlyCheck) = 0;
1864
virtual void close() = 0;
1865
virtual bool isOpen() = 0;
1866
virtual bool write(void* data, size_t length) = 0;
1867
virtual int64_t getVirtualAddress() = 0;
1868
virtual int64_t getPhysicalAddress() = 0;
1869
virtual int64_t getHeaderSize() = 0;
1870
virtual bool seekVirtual(int64_t virtualAddress) = 0;
1871
virtual bool seekPhysical(int64_t physicalAddress) = 0;
1872
virtual bool getModuleInfo(SymDataModuleInfo& info) { return false; };
1873
virtual bool hasFixedVirtualAddress() { return false; };
1874
virtual void beginSymData(SymbolData& symData) { };
1875
virtual void endSymData(SymbolData& symData) { };
1876
virtual const std::wstring& getFileName() = 0;
1877
};
1878
1879
class GenericAssemblerFile: public AssemblerFile
1880
{
1881
public:
1882
GenericAssemblerFile(const std::wstring& fileName, int64_t headerSize, bool overwrite);
1883
GenericAssemblerFile(const std::wstring& fileName, const std::wstring& originalFileName, int64_t headerSize);
1884
1885
virtual bool open(bool onlyCheck);
1886
virtual void close() { if (handle.isOpen()) handle.close(); };
1887
virtual bool isOpen() { return handle.isOpen(); };
1888
virtual bool write(void* data, size_t length);
1889
virtual int64_t getVirtualAddress() { return virtualAddress; };
1890
virtual int64_t getPhysicalAddress() { return virtualAddress-headerSize; };
1891
virtual int64_t getHeaderSize() { return headerSize; };
1892
virtual bool seekVirtual(int64_t virtualAddress);
1893
virtual bool seekPhysical(int64_t physicalAddress);
1894
virtual bool hasFixedVirtualAddress() { return true; };
1895
1896
virtual const std::wstring& getFileName() { return fileName; };
1897
const std::wstring& getOriginalFileName() { return originalName; };
1898
int64_t getOriginalHeaderSize() { return originalHeaderSize; };
1899
void setHeaderSize(int64_t size) { headerSize = size; };
1900
1901
private:
1902
enum Mode { Open, Create, Copy };
1903
1904
Mode mode;
1905
int64_t originalHeaderSize;
1906
int64_t headerSize;
1907
int64_t virtualAddress;
1908
BinaryFile handle;
1909
std::wstring fileName;
1910
std::wstring originalName;
1911
};
1912
1913
1914
class FileManager
1915
{
1916
public:
1917
FileManager();
1918
~FileManager();
1919
void reset();
1920
bool openFile(std::shared_ptr<AssemblerFile> file, bool onlyCheck);
1921
void addFile(std::shared_ptr<AssemblerFile> file);
1922
bool hasOpenFile() { return activeFile != nullptr; };
1923
void closeFile();
1924
bool write(void* data, size_t length);
1925
bool writeU8(uint8_t data);
1926
bool writeU16(uint16_t data);
1927
bool writeU32(uint32_t data);
1928
bool writeU64(uint64_t data);
1929
int64_t getVirtualAddress();
1930
int64_t getPhysicalAddress();
1931
int64_t getHeaderSize();
1932
bool seekVirtual(int64_t virtualAddress);
1933
bool seekPhysical(int64_t physicalAddress);
1934
bool advanceMemory(size_t bytes);
1935
std::shared_ptr<AssemblerFile> getOpenFile() { return activeFile; };
1936
void setEndianness(Endianness endianness) { this->endianness = endianness; };
1937
Endianness getEndianness() { return endianness; }
1938
private:
1939
bool checkActiveFile();
1940
std::vector<std::shared_ptr<AssemblerFile>> files;
1941
std::shared_ptr<AssemblerFile> activeFile;
1942
Endianness endianness;
1943
Endianness ownEndianness;
1944
};
1945
1946
// file: Core/ELF/ElfTypes.h
1947
1948
///////////////////////
1949
// ELF Header Constants
1950
1951
// File type
1952
enum ElfType
1953
{
1954
ET_NONE =0,
1955
ET_REL =1,
1956
ET_EXEC =2,
1957
ET_DYN =3,
1958
ET_CORE =4,
1959
ET_LOPROC =0xFF00,
1960
ET_HIPROC =0xFFFF,
1961
};
1962
1963
// Machine/Architecture
1964
enum ElfMachine
1965
{
1966
EM_NONE =0,
1967
EM_MIPS =8,
1968
EM_ARM =40,
1969
};
1970
1971
// File version
1972
#define EV_NONE 0
1973
#define EV_CURRENT 1
1974
1975
// Identification index
1976
#define EI_MAG0 0
1977
#define EI_MAG1 1
1978
#define EI_MAG2 2
1979
#define EI_MAG3 3
1980
#define EI_CLASS 4
1981
#define EI_DATA 5
1982
#define EI_VERSION 6
1983
#define EI_PAD 7
1984
#define EI_NIDENT 16
1985
1986
// Magic number
1987
#define ELFMAG0 0x7F
1988
#define ELFMAG1 'E'
1989
#define ELFMAG2 'L'
1990
#define ELFMAG3 'F'
1991
1992
// File class
1993
#define ELFCLASSNONE 0
1994
#define ELFCLASS32 1
1995
#define ELFCLASS64 2
1996
1997
// Encoding
1998
#define ELFDATANONE 0
1999
#define ELFDATA2LSB 1
2000
#define ELFDATA2MSB 2
2001
2002
2003
/////////////////////
2004
// Sections constants
2005
2006
// Section indexes
2007
#define SHN_UNDEF 0
2008
#define SHN_LORESERVE 0xFF00
2009
#define SHN_LOPROC 0xFF00
2010
#define SHN_HIPROC 0xFF1F
2011
#define SHN_ABS 0xFFF1
2012
#define SHN_COMMON 0xFFF2
2013
#define SHN_HIRESERVE 0xFFFF
2014
2015
// Section types
2016
#define SHT_NULL 0
2017
#define SHT_PROGBITS 1
2018
#define SHT_SYMTAB 2
2019
#define SHT_STRTAB 3
2020
#define SHT_RELA 4
2021
#define SHT_HASH 5
2022
#define SHT_DYNAMIC 6
2023
#define SHT_NOTE 7
2024
#define SHT_NOBITS 8
2025
#define SHT_REL 9
2026
#define SHT_SHLIB 10
2027
#define SHT_DYNSYM 11
2028
#define SHT_INIT_ARRAY 14
2029
#define SHT_LOPROC 0x70000000
2030
#define SHT_HIPROC 0x7FFFFFFF
2031
#define SHT_LOUSER 0x80000000
2032
#define SHT_HIUSER 0xFFFFFFFF
2033
2034
// Custom section types
2035
#define SHT_PSPREL 0x700000a0
2036
2037
2038
// Section flags
2039
enum ElfSectionFlags
2040
{
2041
SHF_WRITE =0x1,
2042
SHF_ALLOC =0x2,
2043
SHF_EXECINSTR =0x4,
2044
SHF_MASKPROC =0xF0000000,
2045
};
2046
2047
// Symbol binding
2048
#define STB_LOCAL 0
2049
#define STB_GLOBAL 1
2050
#define STB_WEAK 2
2051
#define STB_LOPROC 13
2052
#define STB_HIPROC 15
2053
2054
// Symbol types
2055
#define STT_NOTYPE 0
2056
#define STT_OBJECT 1
2057
#define STT_FUNC 2
2058
#define STT_SECTION 3
2059
#define STT_FILE 4
2060
#define STT_LOPROC 13
2061
#define STT_HIPROC 15
2062
2063
// Undefined name
2064
#define STN_UNDEF 0
2065
2066
// Relocation types
2067
#define R_386_NONE 0
2068
#define R_386_32 1
2069
#define R_386_PC32 2
2070
#define R_386_GOT32 3
2071
#define R_386_PLT32 4
2072
#define R_386_COPY 5
2073
#define R_386_GLOB_DAT 6
2074
#define R_386_JMP_SLOT 7
2075
#define R_386_RELATIVE 8
2076
#define R_386_GOTOFF 9
2077
#define R_386_GOTPC 10
2078
2079
// Segment types
2080
#define PT_NULL 0
2081
#define PT_LOAD 1
2082
#define PT_DYNAMIC 2
2083
#define PT_INTERP 3
2084
#define PT_NOTE 4
2085
#define PT_SHLIB 5
2086
#define PT_PHDR 6
2087
#define PT_LOPROC 0x70000000
2088
#define PT_HIPROC 0x7FFFFFFF
2089
2090
// Segment flags
2091
#define PF_X 1
2092
#define PF_W 2
2093
#define PF_R 4
2094
2095
// Dynamic Array Tags
2096
#define DT_NULL 0
2097
#define DT_NEEDED 1
2098
#define DT_PLTRELSZ 2
2099
#define DT_PLTGOT 3
2100
#define DT_HASH 4
2101
#define DT_STRTAB 5
2102
#define DT_SYMTAB 6
2103
#define DT_RELA 7
2104
#define DT_RELASZ 8
2105
#define DT_RELAENT 9
2106
#define DT_STRSZ 10
2107
#define DT_SYMENT 11
2108
#define DT_INIT 12
2109
#define DT_FINI 13
2110
#define DT_SONAME 14
2111
#define DT_RPATH 15
2112
#define DT_SYMBOLIC 16
2113
#define DT_REL 17
2114
#define DT_RELSZ 18
2115
#define DT_RELENT 19
2116
#define DT_PLTREL 20
2117
#define DT_DEBUG 21
2118
#define DT_TEXTREL 22
2119
#define DT_JMPREL 23
2120
#define DT_LOPROC 0x70000000
2121
#define DT_HIPROC 0x7FFFFFFF
2122
2123
typedef unsigned int Elf32_Addr;
2124
typedef unsigned short Elf32_Half;
2125
typedef unsigned int Elf32_Off;
2126
typedef signed int Elf32_Sword;
2127
typedef unsigned int Elf32_Word;
2128
2129
2130
// ELF file header
2131
struct Elf32_Ehdr
2132
{
2133
unsigned char e_ident[EI_NIDENT];
2134
Elf32_Half e_type;
2135
Elf32_Half e_machine;
2136
Elf32_Word e_version;
2137
Elf32_Addr e_entry;
2138
Elf32_Off e_phoff;
2139
Elf32_Off e_shoff;
2140
Elf32_Word e_flags;
2141
Elf32_Half e_ehsize;
2142
Elf32_Half e_phentsize;
2143
Elf32_Half e_phnum;
2144
Elf32_Half e_shentsize;
2145
Elf32_Half e_shnum;
2146
Elf32_Half e_shstrndx;
2147
};
2148
2149
// Section header
2150
struct Elf32_Shdr
2151
{
2152
Elf32_Word sh_name;
2153
Elf32_Word sh_type;
2154
Elf32_Word sh_flags;
2155
Elf32_Addr sh_addr;
2156
Elf32_Off sh_offset;
2157
Elf32_Word sh_size;
2158
Elf32_Word sh_link;
2159
Elf32_Word sh_info;
2160
Elf32_Word sh_addralign;
2161
Elf32_Word sh_entsize;
2162
};
2163
2164
// Segment header
2165
struct Elf32_Phdr
2166
{
2167
Elf32_Word p_type;
2168
Elf32_Off p_offset;
2169
Elf32_Addr p_vaddr;
2170
Elf32_Addr p_paddr;
2171
Elf32_Word p_filesz;
2172
Elf32_Word p_memsz;
2173
Elf32_Word p_flags;
2174
Elf32_Word p_align;
2175
};
2176
2177
// Symbol table entry
2178
struct Elf32_Sym
2179
{
2180
Elf32_Word st_name;
2181
Elf32_Addr st_value;
2182
Elf32_Word st_size;
2183
unsigned char st_info;
2184
unsigned char st_other;
2185
Elf32_Half st_shndx;
2186
};
2187
2188
#define ELF32_ST_BIND(i) ((i)>>4)
2189
#define ELF32_ST_TYPE(i) ((i)&0xf)
2190
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
2191
2192
// Relocation entries
2193
struct Elf32_Rel
2194
{
2195
Elf32_Addr r_offset;
2196
Elf32_Word r_info;
2197
2198
unsigned char getType()
2199
{
2200
return r_info & 0xFF;
2201
}
2202
2203
Elf32_Word getSymbolNum()
2204
{
2205
return r_info >> 8;
2206
}
2207
};
2208
2209
struct Elf32_Rela
2210
{
2211
Elf32_Addr r_offset;
2212
Elf32_Word r_info;
2213
Elf32_Sword r_addend;
2214
};
2215
2216
#define ELF32_R_SYM(i) ((i)>>8)
2217
#define ELF32_R_TYPE(i) ((unsigned char)(i))
2218
#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t))
2219
2220
// file: Core/ELF/ElfFile.h
2221
2222
#include <vector>
2223
2224
enum ElfPart { ELFPART_SEGMENTTABLE, ELFPART_SECTIONTABLE, ELFPART_SEGMENTS, ELFPART_SEGMENTLESSSECTIONS };
2225
2226
class ElfSegment;
2227
class ElfSection;
2228
2229
class ElfFile
2230
{
2231
public:
2232
2233
bool load(const std::wstring&fileName, bool sort);
2234
bool load(ByteArray& data, bool sort);
2235
void save(const std::wstring&fileName);
2236
2237
Elf32_Half getType() { return fileHeader.e_type; };
2238
Elf32_Half getMachine() { return fileHeader.e_machine; };
2239
Endianness getEndianness()
2240
{
2241
return fileHeader.e_ident[EI_DATA] == ELFDATA2MSB ? Endianness::Big : Endianness::Little;
2242
}
2243
size_t getSegmentCount() { return segments.size(); };
2244
ElfSegment* getSegment(size_t index) { return segments[index]; };
2245
2246
int findSegmentlessSection(const std::string& name);
2247
ElfSection* getSegmentlessSection(size_t index) { return segmentlessSections[index]; };
2248
size_t getSegmentlessSectionCount() { return segmentlessSections.size(); };
2249
ByteArray& getFileData() { return fileData; }
2250
2251
int getSymbolCount();
2252
bool getSymbol(Elf32_Sym& symbol, size_t index);
2253
const char* getStrTableString(size_t pos);
2254
private:
2255
void loadElfHeader();
2256
void writeHeader(ByteArray& data, int pos, Endianness endianness);
2257
void loadProgramHeader(Elf32_Phdr& header, ByteArray& data, int pos);
2258
void loadSectionHeader(Elf32_Shdr& header, ByteArray& data, int pos);
2259
void loadSectionNames();
2260
void determinePartOrder();
2261
2262
Elf32_Ehdr fileHeader;
2263
std::vector<ElfSegment*> segments;
2264
std::vector<ElfSection*> sections;
2265
std::vector<ElfSection*> segmentlessSections;
2266
ByteArray fileData;
2267
ElfPart partsOrder[4];
2268
2269
ElfSection* symTab;
2270
ElfSection* strTab;
2271
};
2272
2273
2274
class ElfSection
2275
{
2276
public:
2277
ElfSection(Elf32_Shdr header);
2278
void setName(std::string& name) { this->name = name; };
2279
const std::string& getName() { return name; };
2280
void setData(ByteArray& data) { this->data = data; };
2281
void setOwner(ElfSegment* segment);
2282
bool hasOwner() { return owner != nullptr; };
2283
void writeHeader(ByteArray& data, int pos, Endianness endianness);
2284
void writeData(ByteArray& output);
2285
void setOffsetBase(int base);
2286
ByteArray& getData() { return data; };
2287
2288
Elf32_Word getType() { return header.sh_type; };
2289
Elf32_Off getOffset() { return header.sh_offset; };
2290
Elf32_Word getSize() { return header.sh_size; };
2291
Elf32_Word getNameOffset() { return header.sh_name; };
2292
Elf32_Word getAlignment() { return header.sh_addralign; };
2293
Elf32_Addr getAddress() { return header.sh_addr; };
2294
Elf32_Half getInfo() { return header.sh_info; };
2295
Elf32_Word getFlags() { return header.sh_flags; };
2296
private:
2297
Elf32_Shdr header;
2298
std::string name;
2299
ByteArray data;
2300
ElfSegment* owner;
2301
};
2302
2303
class ElfSegment
2304
{
2305
public:
2306
ElfSegment(Elf32_Phdr header, ByteArray& segmentData);
2307
bool isSectionPartOf(ElfSection* section);
2308
void addSection(ElfSection* section);
2309
Elf32_Off getOffset() { return header.p_offset; };
2310
Elf32_Word getPhysSize() { return header.p_filesz; };
2311
Elf32_Word getType() { return header.p_type; };
2312
Elf32_Addr getVirtualAddress() { return header.p_vaddr; };
2313
size_t getSectionCount() { return sections.size(); };
2314
void writeHeader(ByteArray& data, int pos, Endianness endianness);
2315
void writeData(ByteArray& output);
2316
void splitSections();
2317
2318
int findSection(const std::string& name);
2319
ElfSection* getSection(size_t index) { return sections[index]; };
2320
void writeToData(size_t offset, void* data, size_t size);
2321
void sortSections();
2322
private:
2323
Elf32_Phdr header;
2324
ByteArray data;
2325
std::vector<ElfSection*> sections;
2326
ElfSection* paddrSection;
2327
};
2328
2329
struct RelocationData
2330
{
2331
int64_t opcodeOffset;
2332
int64_t relocationBase;
2333
uint32_t opcode;
2334
2335
int64_t symbolAddress;
2336
int targetSymbolType;
2337
int targetSymbolInfo;
2338
};
2339
2340
// file: Core/ELF/ElfRelocator.h
2341
2342
struct ElfRelocatorCtor
2343
{
2344
std::wstring symbolName;
2345
size_t size;
2346
};
2347
2348
struct RelocationAction
2349
{
2350
RelocationAction(int64_t offset, uint32_t newValue) : offset(offset), newValue(newValue) {}
2351
int64_t offset;
2352
uint32_t newValue;
2353
};
2354
2355
class CAssemblerCommand;
2356
class Parser;
2357
2358
class IElfRelocator
2359
{
2360
public:
2361
virtual ~IElfRelocator() {};
2362
virtual int expectedMachine() const = 0;
2363
virtual bool isDummyRelocationType(int type) const { return false; }
2364
virtual bool relocateOpcode(int type, const RelocationData& data, std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors) = 0;
2365
virtual bool finish(std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors) { return true; }
2366
virtual void setSymbolAddress(RelocationData& data, int64_t symbolAddress, int symbolType) = 0;
2367
2368
virtual std::unique_ptr<CAssemblerCommand> generateCtorStub(std::vector<ElfRelocatorCtor>& ctors) { return nullptr; }
2369
};
2370
2371
2372
class Label;
2373
2374
struct ElfRelocatorSection
2375
{
2376
ElfSection* section;
2377
size_t index;
2378
ElfSection* relSection;
2379
std::shared_ptr<Label> label;
2380
};
2381
2382
struct ElfRelocatorSymbol
2383
{
2384
std::shared_ptr<Label> label;
2385
std::wstring name;
2386
int64_t relativeAddress;
2387
int64_t relocatedAddress;
2388
size_t section;
2389
size_t size;
2390
int type;
2391
};
2392
2393
struct ElfRelocatorFile
2394
{
2395
ElfFile* elf;
2396
std::vector<ElfRelocatorSection> sections;
2397
std::vector<ElfRelocatorSymbol> symbols;
2398
std::wstring name;
2399
};
2400
2401
class ElfRelocator
2402
{
2403
public:
2404
bool init(const std::wstring& inputName);
2405
bool exportSymbols();
2406
void writeSymbols(SymbolData& symData) const;
2407
std::unique_ptr<CAssemblerCommand> generateCtor(const std::wstring& ctorName);
2408
bool relocate(int64_t& memoryAddress);
2409
bool hasDataChanged() { return dataChanged; };
2410
const ByteArray& getData() const { return outputData; };
2411
private:
2412
bool relocateFile(ElfRelocatorFile& file, int64_t& relocationAddress);
2413
void loadRelocation(Elf32_Rel& rel, ByteArray& data, int offset, Endianness endianness);
2414
2415
ByteArray outputData;
2416
std::unique_ptr<IElfRelocator> relocator;
2417
std::vector<ElfRelocatorFile> files;
2418
std::vector<ElfRelocatorCtor> ctors;
2419
bool dataChanged;
2420
};
2421
2422
// file: Archs/Architecture.h
2423
2424
class Tokenizer;
2425
class Parser;
2426
2427
class CArchitecture
2428
{
2429
public:
2430
virtual std::unique_ptr<CAssemblerCommand> parseDirective(Parser& parser) { return nullptr; }
2431
virtual std::unique_ptr<CAssemblerCommand> parseOpcode(Parser& parser) { return nullptr; }
2432
virtual const ExpressionFunctionMap& getExpressionFunctions() { return emptyMap; }
2433
virtual void NextSection() = 0;
2434
virtual void Pass2() = 0;
2435
virtual void Revalidate() = 0;
2436
virtual std::unique_ptr<IElfRelocator> getElfRelocator() = 0;
2437
virtual Endianness getEndianness() = 0;
2438
private:
2439
const ExpressionFunctionMap emptyMap = {};
2440
};
2441
2442
class ArchitectureCommand: public CAssemblerCommand
2443
{
2444
public:
2445
ArchitectureCommand(const std::wstring& tempText, const std::wstring& symText);
2446
virtual bool Validate();
2447
virtual void Encode() const;
2448
virtual void writeTempData(TempData& tempData) const;
2449
virtual void writeSymData(SymbolData& symData) const;
2450
private:
2451
int64_t position;
2452
Endianness endianness;
2453
std::wstring tempText;
2454
std::wstring symText;
2455
};
2456
2457
class CInvalidArchitecture: public CArchitecture
2458
{
2459
public:
2460
virtual void NextSection();
2461
virtual void Pass2();
2462
virtual void Revalidate();
2463
virtual std::unique_ptr<IElfRelocator> getElfRelocator();
2464
virtual Endianness getEndianness() { return Endianness::Little; }
2465
};
2466
2467
extern CInvalidArchitecture InvalidArchitecture;
2468
2469
// file: Archs/MIPS/Mips.h
2470
2471
enum MipsArchType { MARCH_PSX = 0, MARCH_N64, MARCH_PS2, MARCH_PSP, MARCH_RSP, MARCH_INVALID };
2472
2473
class CMipsArchitecture: public CArchitecture
2474
{
2475
public:
2476
CMipsArchitecture();
2477
virtual std::unique_ptr<CAssemblerCommand> parseDirective(Parser& parser);
2478
virtual std::unique_ptr<CAssemblerCommand> parseOpcode(Parser& parser);
2479
virtual const ExpressionFunctionMap& getExpressionFunctions();
2480
virtual void NextSection();
2481
virtual void Pass2() { return; };
2482
virtual void Revalidate();
2483
virtual std::unique_ptr<IElfRelocator> getElfRelocator();
2484
virtual Endianness getEndianness()
2485
{
2486
return Version == MARCH_N64 || Version == MARCH_RSP ? Endianness::Big : Endianness::Little;
2487
};
2488
void SetLoadDelay(bool Delay, int Register);
2489
bool GetLoadDelay() { return LoadDelay; };
2490
int GetLoadDelayRegister() { return LoadDelayRegister; };
2491
bool GetIgnoreDelay() { return IgnoreLoadDelay; };
2492
void SetIgnoreDelay(bool b) { IgnoreLoadDelay = b; };
2493
void SetFixLoadDelay(bool b) { FixLoadDelay = b; };
2494
bool GetFixLoadDelay() { return FixLoadDelay; };
2495
void SetVersion(MipsArchType v) { Version = v; };
2496
MipsArchType GetVersion() { return Version; };
2497
bool GetDelaySlot() { return DelaySlot; };
2498
void SetDelaySlot(bool b) {DelaySlot = b; };
2499
bool hasLoadDelay() { return Version == MARCH_PSX; };
2500
private:
2501
bool FixLoadDelay;
2502
bool IgnoreLoadDelay;
2503
bool LoadDelay;
2504
int LoadDelayRegister;
2505
bool DelaySlot;
2506
MipsArchType Version;
2507
};
2508
2509
typedef struct {
2510
const char* name;
2511
short num;
2512
short len;
2513
} tMipsRegister;
2514
2515
typedef struct {
2516
char name[5];
2517
short num;
2518
} MipsRegisterInfo;
2519
2520
enum MipsVfpuType { MIPSVFPU_VECTOR, MIPSVFPU_MATRIX };
2521
2522
struct MipsVFPURegister
2523
{
2524
MipsVfpuType type;
2525
int num;
2526
char name[8];
2527
};
2528
2529
extern const tMipsRegister MipsRegister[];
2530
extern CMipsArchitecture Mips;
2531
2532
bool MipsGetRegister(const char* source, int& RetLen, MipsRegisterInfo& Result);
2533
int MipsGetRegister(const char* source, int& RetLen);
2534
bool MipsGetFloatRegister(const char* source, int& RetLen, MipsRegisterInfo& Result);
2535
bool MipsGetPs2VectorRegister(const char* source, int& RetLen, MipsRegisterInfo& Result);
2536
int MipsGetFloatRegister(const char* source, int& RetLen);
2537
bool MipsCheckImmediate(const char* Source, Expression& Dest, int& RetLen);
2538
2539
2540
// file: Archs/MIPS/MipsOpcodes.h
2541
2542
#define MA_MIPS1 0x00000001
2543
#define MA_MIPS2 0x00000002
2544
#define MA_MIPS3 0x00000004
2545
#define MA_MIPS4 0x00000008
2546
#define MA_PSX 0x00000010
2547
#define MA_PS2 0x00000040
2548
#define MA_PSP 0x00000080
2549
#define MA_RSP 0x00000100
2550
2551
#define MA_EXPSX 0x00001000
2552
#define MA_EXN64 0x00002000
2553
#define MA_EXPS2 0x00004000
2554
#define MA_EXPSP 0x00008000
2555
#define MA_EXRSP 0x00010000
2556
2557
#define MO_IPCA 0x00000001 // pc >> 2
2558
#define MO_IPCR 0x00000002 // PC, -> difference >> 2
2559
#define MO_RSD 0x00000004 // rs = rd
2560
#define MO_RST 0x00000008 // rs = rt
2561
#define MO_RDT 0x00000010 // rd = rt
2562
#define MO_DELAY 0x00000020 // delay slot follows
2563
#define MO_NODELAYSLOT 0x00000040 // can't be in a delay slot
2564
#define MO_DELAYRT 0x00000080 // rt won't be available for one instruction
2565
#define MO_IGNORERTD 0x00000100 // don't care for rt delay
2566
#define MO_FRSD 0x00000200 // float rs + rd
2567
#define MO_IMMALIGNED 0x00000400 // immediate 4 byte aligned
2568
#define MO_VFPU_MIXED 0x00000800 // mixed mode vfpu register
2569
#define MO_VFPU_6BIT 0x00001000 // vfpu register can have 6 bits max
2570
#define MO_VFPU_SINGLE 0x00002000 // single vfpu reg
2571
#define MO_VFPU_QUAD 0x00004000 // quad vfpu reg
2572
#define MO_VFPU 0x00008000 // vfpu type opcode
2573
#define MO_64BIT 0x00010000 // only available on 64 bit cpus
2574
#define MO_FPU 0x00020000 // only available with an fpu
2575
#define MO_TRANSPOSE_VS 0x00040000 // matrix vs has to be transposed
2576
#define MO_VFPU_PAIR 0x00080000 // pair vfpu reg
2577
#define MO_VFPU_TRIPLE 0x00100000 // triple vfpu reg
2578
#define MO_DFPU 0x00200000 // double-precision fpu opcodes
2579
#define MO_RSPVRSD 0x00400000 // rsp vector rs + rd
2580
#define MO_NEGIMM 0x00800000 // negated immediate (for subi)
2581
#define MO_RSP_HWOFFSET 0x01000000 // RSP halfword load/store offset
2582
#define MO_RSP_WOFFSET 0x02000000 // RSP word load/store offset
2583
#define MO_RSP_DWOFFSET 0x04000000 // RSP doubleword load/store offset
2584
#define MO_RSP_QWOFFSET 0x08000000 // RSP quadword load/store offset
2585
2586
#define BITFIELD(START,LENGTH,VALUE) (((VALUE) & ((1 << (LENGTH)) - 1)) << (START))
2587
#define MIPS_FUNC(VALUE) BITFIELD(0,6,(VALUE))
2588
#define MIPS_SA(VALUE) BITFIELD(6,5,(VALUE))
2589
#define MIPS_SECFUNC(VALUE) MIPS_SA((VALUE))
2590
#define MIPS_OP(VALUE) BITFIELD(26,6,(VALUE))
2591
2592
#define MIPS_RS(VALUE) BITFIELD(21,5,(VALUE))
2593
#define MIPS_RT(VALUE) BITFIELD(16,5,(VALUE))
2594
#define MIPS_RD(VALUE) BITFIELD(11,5,(VALUE))
2595
#define MIPS_FS(VALUE) MIPS_RD((VALUE))
2596
#define MIPS_FT(VALUE) MIPS_RT((VALUE))
2597
#define MIPS_FD(VALUE) MIPS_SA((VALUE))
2598
2599
#define MIPS_SPECIAL(VALUE) (MIPS_OP(0) | MIPS_FUNC(VALUE))
2600
#define MIPS_REGIMM(VALUE) (MIPS_OP(1) | MIPS_RT(VALUE))
2601
#define MIPS_COP0(VALUE) (MIPS_OP(16) | MIPS_RS(VALUE))
2602
#define MIPS_COP0FUNCT(VALUE) (MIPS_COP0(16) | MIPS_FUNC(VALUE))
2603
#define MIPS_COP1(VALUE) (MIPS_OP(17) | MIPS_RS(VALUE))
2604
#define MIPS_COP1BC(VALUE) (MIPS_COP1(8) | MIPS_RT(VALUE))
2605
#define MIPS_COP1S(VALUE) (MIPS_COP1(16) | MIPS_FUNC(VALUE))
2606
#define MIPS_COP1D(VALUE) (MIPS_COP1(17) | MIPS_FUNC(VALUE))
2607
#define MIPS_COP1W(VALUE) (MIPS_COP1(20) | MIPS_FUNC(VALUE))
2608
#define MIPS_COP1L(VALUE) (MIPS_COP1(21) | MIPS_FUNC(VALUE))
2609
2610
#define MIPS_VFPUSIZE(VALUE) ( (((VALUE) & 1) << 7) | (((VALUE) & 2) << 14) )
2611
#define MIPS_VFPUFUNC(VALUE) BITFIELD(23, 3, (VALUE))
2612
#define MIPS_COP2(VALUE) (MIPS_OP(18) | MIPS_RS(VALUE))
2613
#define MIPS_COP2BC(VALUE) (MIPS_COP2(8) | MIPS_RT(VALUE))
2614
#define MIPS_RSP_COP2(VALUE) (MIPS_OP(18) | (1 << 25) | MIPS_FUNC(VALUE))
2615
#define MIPS_RSP_LWC2(VALUE) (MIPS_OP(50) | MIPS_RD(VALUE))
2616
#define MIPS_RSP_SWC2(VALUE) (MIPS_OP(58) | MIPS_RD(VALUE))
2617
#define MIPS_RSP_VE(VALUE) BITFIELD(21, 4, (VALUE))
2618
#define MIPS_RSP_VDE(VALUE) BITFIELD(11, 4, (VALUE))
2619
#define MIPS_RSP_VEALT(VALUE) BITFIELD(7, 4, (VALUE))
2620
#define MIPS_VFPU0(VALUE) (MIPS_OP(24) | MIPS_VFPUFUNC(VALUE))
2621
#define MIPS_VFPU1(VALUE) (MIPS_OP(25) | MIPS_VFPUFUNC(VALUE))
2622
#define MIPS_VFPU3(VALUE) (MIPS_OP(27) | MIPS_VFPUFUNC(VALUE))
2623
#define MIPS_SPECIAL3(VALUE) (MIPS_OP(31) | MIPS_FUNC(VALUE))
2624
#define MIPS_ALLEGREX0(VALUE) (MIPS_SPECIAL3(32) | MIPS_SECFUNC(VALUE))
2625
#define MIPS_VFPU4(VALUE) (MIPS_OP(52) | MIPS_RS(VALUE))
2626
#define MIPS_VFPU4_11(VALUE) (MIPS_VFPU4(0) | MIPS_RT(VALUE))
2627
#define MIPS_VFPU4_12(VALUE) (MIPS_VFPU4(1) | MIPS_RT(VALUE))
2628
#define MIPS_VFPU4_13(VALUE) (MIPS_VFPU4(2) | MIPS_RT(VALUE))
2629
#define MIPS_VFPU5(VALUE) (MIPS_OP(55) | MIPS_VFPUFUNC(VALUE))
2630
#define MIPS_VFPU6(VALUE) (MIPS_OP(60) | MIPS_VFPUFUNC(VALUE))
2631
#define MIPS_VFPU6_1(VALUE) (MIPS_VFPU6(7) | BITFIELD(20, 3, VALUE))
2632
// This is a bit ugly, VFPU opcodes are encoded strangely.
2633
#define MIPS_VFPU6_1VROT() (MIPS_VFPU6(7) | BITFIELD(21, 2, 1))
2634
#define MIPS_VFPU6_2(VALUE) (MIPS_VFPU6_1(0) | MIPS_RT(VALUE))
2635
2636
2637
struct MipsArchDefinition
2638
{
2639
const char* name;
2640
int supportSets;
2641
int excludeMask;
2642
int flags;
2643
};
2644
2645
extern const MipsArchDefinition mipsArchs[];
2646
2647
typedef struct {
2648
const char* name;
2649
const char* encoding;
2650
int destencoding;
2651
int archs;
2652
int flags;
2653
} tMipsOpcode;
2654
2655
extern const tMipsOpcode MipsOpcodes[];
2656
2657
// file: Archs/MIPS/CMipsInstruction.h
2658
2659
enum class MipsRegisterType
2660
{
2661
Normal,
2662
Float,
2663
FpuControl,
2664
Cop0,
2665
Ps2Cop2,
2666
PsxCop2Data,
2667
PsxCop2Control,
2668
VfpuVector,
2669
VfpuMatrix,
2670
RspCop0,
2671
RspVector,
2672
RspVectorControl,
2673
RspVectorElement,
2674
RspScalarElement,
2675
RspOffsetElement
2676
};
2677
2678
enum class MipsImmediateType
2679
{
2680
None,
2681
Immediate5,
2682
Immediate10,
2683
Immediate16,
2684
Immediate20,
2685
Immediate25,
2686
Immediate26,
2687
Immediate20_0,
2688
ImmediateHalfFloat,
2689
Immediate7,
2690
CacheOp,
2691
Ext,
2692
Ins,
2693
Cop2BranchType
2694
};
2695
2696
struct MipsRegisterValue
2697
{
2698
MipsRegisterType type;
2699
std::wstring name;
2700
int num;
2701
};
2702
2703
struct MipsRegisterData {
2704
MipsRegisterValue grs; // general source reg
2705
MipsRegisterValue grt; // general target reg
2706
MipsRegisterValue grd; // general dest reg
2707
2708
MipsRegisterValue frs; // float source reg
2709
MipsRegisterValue frt; // float target reg
2710
MipsRegisterValue frd; // float dest reg
2711
2712
MipsRegisterValue ps2vrs; // ps2 vector source reg
2713
MipsRegisterValue ps2vrt; // ps2 vector target reg
2714
MipsRegisterValue ps2vrd; // ps2 vector dest reg
2715
2716
MipsRegisterValue rspvrs; // rsp vector source reg
2717
MipsRegisterValue rspvrt; // rsp vector target reg
2718
MipsRegisterValue rspvrd; // rsp vector dest reg
2719
MipsRegisterValue rspve; // rsp vector element reg
2720
MipsRegisterValue rspvde; // rsp vector dest element reg
2721
MipsRegisterValue rspvealt; // rsp vector element reg (alt. placement)
2722
2723
MipsRegisterValue vrs; // vfpu source reg
2724
MipsRegisterValue vrt; // vfpu target reg
2725
MipsRegisterValue vrd; // vfpu dest reg
2726
2727
void reset()
2728
{
2729
grs.num = grt.num = grd.num = -1;
2730
frs.num = frt.num = frd.num = -1;
2731
vrs.num = vrt.num = vrd.num = -1;
2732
ps2vrs.num = ps2vrt.num = ps2vrd.num = -1;
2733
rspvrs.num = rspvrt.num = rspvrd.num = -1;
2734
rspve.num = rspvde.num = rspvealt.num = -1;
2735
}
2736
};
2737
2738
struct MipsImmediateData
2739
{
2740
struct
2741
{
2742
MipsImmediateType type;
2743
Expression expression;
2744
int value;
2745
int originalValue;
2746
} primary;
2747
2748
struct
2749
{
2750
MipsImmediateType type;
2751
Expression expression;
2752
int value;
2753
int originalValue;
2754
} secondary;
2755
2756
void reset()
2757
{
2758
primary.type = MipsImmediateType::None;
2759
if (primary.expression.isLoaded())
2760
primary.expression = Expression();
2761
2762
secondary.type = MipsImmediateType::None;
2763
if (secondary.expression.isLoaded())
2764
secondary.expression = Expression();
2765
}
2766
};
2767
2768
struct MipsOpcodeData
2769
{
2770
tMipsOpcode opcode;
2771
int vfpuSize;
2772
int vectorCondition;
2773
2774
void reset()
2775
{
2776
vfpuSize = vectorCondition = -1;
2777
}
2778
};
2779
2780
class CMipsInstruction: public CAssemblerCommand
2781
{
2782
public:
2783
CMipsInstruction(MipsOpcodeData& opcode, MipsImmediateData& immediate, MipsRegisterData& registers);
2784
~CMipsInstruction();
2785
virtual bool Validate();
2786
virtual void Encode() const;
2787
virtual void writeTempData(TempData& tempData) const;
2788
private:
2789
void encodeNormal() const;
2790
void encodeVfpu() const;
2791
int floatToHalfFloat(int i);
2792
2793
bool IgnoreLoadDelay;
2794
int64_t RamPos;
2795
bool addNop;
2796
2797
// opcode variables
2798
MipsOpcodeData opcodeData;
2799
MipsImmediateData immediateData;
2800
MipsRegisterData registerData;
2801
};
2802
2803
// file: Util/EncodingTable.h
2804
#include <map>
2805
2806
class Trie
2807
{
2808
public:
2809
Trie();
2810
void insert(const wchar_t* text, size_t value);
2811
void insert(wchar_t character, size_t value);
2812
bool findLongestPrefix(const wchar_t* text, size_t& result);
2813
private:
2814
struct LookupEntry
2815
{
2816
size_t node;
2817
wchar_t input;
2818
2819
bool operator<(const LookupEntry& other) const
2820
{
2821
if (node != other.node)
2822
return node < other.node;
2823
return input < other.input;
2824
}
2825
};
2826
2827
struct Node
2828
{
2829
size_t index;
2830
bool hasValue;
2831
size_t value;
2832
};
2833
2834
std::vector<Node> nodes;
2835
std::map<LookupEntry,size_t> lookup;
2836
};
2837
2838
class EncodingTable
2839
{
2840
public:
2841
EncodingTable();
2842
~EncodingTable();
2843
void clear();
2844
bool load(const std::wstring& fileName, TextFile::Encoding encoding = TextFile::GUESS);
2845
bool isLoaded() { return entries.size() != 0; };
2846
void addEntry(unsigned char* hex, size_t hexLength, const std::wstring& value);
2847
void addEntry(unsigned char* hex, size_t hexLength, wchar_t value);
2848
void setTerminationEntry(unsigned char* hex, size_t hexLength);
2849
ByteArray encodeString(const std::wstring& str, bool writeTermination = true);
2850
ByteArray encodeTermination();
2851
private:
2852
struct TableEntry
2853
{
2854
size_t hexPos;
2855
size_t hexLen;
2856
size_t valueLen;
2857
};
2858
2859
ByteArray hexData;
2860
std::vector<TableEntry> entries;
2861
Trie lookup;
2862
TableEntry terminationEntry;
2863
};
2864
2865
// file: Core/Misc.h
2866
#include <vector>
2867
2868
class Logger
2869
{
2870
public:
2871
enum ErrorType { Warning, Error, FatalError, Notice };
2872
2873
static void clear();
2874
static void printLine(const std::wstring& text);
2875
static void printLine(const std::string& text);
2876
2877
template <typename... Args>
2878
static void printLine(const wchar_t* text, const Args&... args)
2879
{
2880
std::wstring message = formatString(text,args...);
2881
printLine(message);
2882
}
2883
2884
static void print(const std::wstring& text);
2885
2886
template <typename... Args>
2887
static void print(const wchar_t* text, const Args&... args)
2888
{
2889
std::wstring message = formatString(text,args...);
2890
print(message);
2891
}
2892
2893
static void printError(ErrorType type, const std::wstring& text);
2894
static void printError(ErrorType type, const wchar_t* text);
2895
static void queueError(ErrorType type, const std::wstring& text);
2896
static void queueError(ErrorType type, const wchar_t* text);
2897
2898
template <typename... Args>
2899
static void printError(ErrorType type, const wchar_t* text, const Args&... args)
2900
{
2901
std::wstring message = formatString(text,args...);
2902
printError(type,message);
2903
}
2904
2905
template <typename... Args>
2906
static void queueError(ErrorType type, const wchar_t* text, const Args&... args)
2907
{
2908
std::wstring message = formatString(text,args...);
2909
queueError(type,message);
2910
}
2911
2912
static void printQueue();
2913
static void clearQueue() { queue.clear(); };
2914
static StringList getErrors() { return errors; };
2915
static bool hasError() { return error; };
2916
static bool hasFatalError() { return fatalError; };
2917
static void setErrorOnWarning(bool b) { errorOnWarning = b; };
2918
static void setSilent(bool b) { silent = b; };
2919
static bool isSilent() { return silent; }
2920
static void suppressErrors() { ++suppressLevel; }
2921
static void unsuppressErrors() { if (suppressLevel) --suppressLevel; }
2922
private:
2923
static std::wstring formatError(ErrorType type, const wchar_t* text);
2924
static void setFlags(ErrorType type);
2925
2926
struct QueueEntry
2927
{
2928
ErrorType type;
2929
std::wstring text;
2930
};
2931
2932
static std::vector<QueueEntry> queue;
2933
static std::vector<std::wstring> errors;
2934
static bool error;
2935
static bool fatalError;
2936
static bool errorOnWarning;
2937
static bool silent;
2938
static int suppressLevel;
2939
};
2940
2941
class TempData
2942
{
2943
public:
2944
void setFileName(const std::wstring& name) { file.setFileName(name); };
2945
void clear() { file.setFileName(L""); }
2946
void start();
2947
void end();
2948
void writeLine(int64_t memoryAddress, const std::wstring& text);
2949
bool isOpen() { return file.isOpen(); }
2950
private:
2951
TextFile file;
2952
};
2953
2954
// file: Core/Assembler.h
2955
2956
#define ARMIPS_VERSION_MAJOR 0
2957
#define ARMIPS_VERSION_MINOR 11
2958
#define ARMIPS_VERSION_REVISION 0
2959
2960
enum class ArmipsMode { FILE, MEMORY };
2961
2962
struct LabelDefinition
2963
{
2964
std::wstring originalName;
2965
std::wstring name;
2966
int64_t value;
2967
};
2968
2969
struct EquationDefinition
2970
{
2971
std::wstring name;
2972
std::wstring value;
2973
};
2974
2975
struct ArmipsArguments
2976
{
2977
// common
2978
ArmipsMode mode;
2979
int symFileVersion;
2980
bool errorOnWarning;
2981
bool silent;
2982
StringList* errorsResult;
2983
std::vector<EquationDefinition> equList;
2984
std::vector<LabelDefinition> labels;
2985
2986
// file mode
2987
std::wstring inputFileName;
2988
std::wstring tempFileName;
2989
std::wstring symFileName;
2990
bool useAbsoluteFileNames;
2991
2992
// memory mode
2993
std::shared_ptr<AssemblerFile> memoryFile;
2994
std::wstring content;
2995
2996
ArmipsArguments()
2997
{
2998
mode = ArmipsMode::FILE;
2999
symFileVersion = 0;
3000
errorOnWarning = false;
3001
silent = false;
3002
errorsResult = nullptr;
3003
useAbsoluteFileNames = true;
3004
}
3005
};
3006
3007
bool runArmips(ArmipsArguments& settings);
3008
3009
// file: Core/SymbolTable.h
3010
3011
#include <map>
3012
3013
struct SymbolKey
3014
{
3015
std::wstring name;
3016
int file;
3017
int section;
3018
};
3019
3020
bool operator<(SymbolKey const& lhs, SymbolKey const& rhs);
3021
3022
class Label
3023
{
3024
public:
3025
Label(std::wstring name): name(name),defined(false),data(false),updateInfo(true),info(0) { };
3026
const std::wstring getName() { return name; };
3027
void setOriginalName(const std::wstring& name) { originalName = name; }
3028
const std::wstring getOriginalName() { return originalName.empty() ? name : originalName; }
3029
int64_t getValue() { return value; };
3030
void setValue(int64_t val) { value = val; };
3031
bool hasPhysicalValue() { return physicalValueSet; }
3032
int64_t getPhysicalValue() { return physicalValue; }
3033
void setPhysicalValue(int64_t val) { physicalValue = val; physicalValueSet = true; }
3034
bool isDefined() { return defined; };
3035
void setDefined(bool b) { defined = b; };
3036
bool isData() { return data; };
3037
void setIsData(bool b) { data = b; };
3038
void setInfo(int inf) { info = inf; };
3039
int getInfo() { return info; };
3040
void setUpdateInfo(bool b) { updateInfo = b; };
3041
bool getUpdateInfo() { return updateInfo; };
3042
void setSection(int num) { section = num; }
3043
int getSection() { return section; }
3044
private:
3045
std::wstring name, originalName;
3046
int64_t value;
3047
int64_t physicalValue;
3048
bool physicalValueSet = false;
3049
bool defined;
3050
bool data;
3051
bool updateInfo;
3052
int info;
3053
int section;
3054
};
3055
3056
class SymbolTable
3057
{
3058
public:
3059
SymbolTable();
3060
~SymbolTable();
3061
void clear();
3062
bool symbolExists(const std::wstring& symbol, int file, int section);
3063
static bool isValidSymbolName(const std::wstring& symbol);
3064
static bool isValidSymbolCharacter(wchar_t character, bool first = false);
3065
static bool isLocalSymbol(const std::wstring& symbol, size_t pos = 0) { return symbol.size() >= pos+2 && symbol[pos+0] == '@' && symbol[pos+1] == '@'; };
3066
static bool isStaticSymbol(const std::wstring& symbol, size_t pos = 0) { return symbol.size() >= pos+1 && symbol[pos+0] == '@'; };
3067
static bool isGlobalSymbol(const std::wstring& symbol, size_t pos = 0) { return !isLocalSymbol(symbol) && !isStaticSymbol(symbol); };
3068
3069
std::shared_ptr<Label> getLabel(const std::wstring& symbol, int file, int section);
3070
bool addEquation(const std::wstring& name, int file, int section, size_t referenceIndex);
3071
bool findEquation(const std::wstring& name, int file, int section, size_t& dest);
3072
void addLabels(const std::vector<LabelDefinition>& labels);
3073
int findSection(int64_t address);
3074
3075
std::wstring getUniqueLabelName(bool local = false);
3076
size_t getLabelCount() { return labels.size(); };
3077
size_t getEquationCount() { return equationsCount; };
3078
bool isGeneratedLabel(const std::wstring& name) { return generatedLabels.find(name) != generatedLabels.end(); }
3079
private:
3080
void setFileSectionValues(const std::wstring& symbol, int& file, int& section);
3081
3082
enum SymbolType { LabelSymbol, EquationSymbol };
3083
struct SymbolInfo
3084
{
3085
SymbolType type;
3086
size_t index;
3087
};
3088
3089
std::map<SymbolKey,SymbolInfo> symbols;
3090
std::vector<std::shared_ptr<Label>> labels;
3091
size_t equationsCount;
3092
size_t uniqueCount;
3093
std::set<std::wstring> generatedLabels;
3094
};
3095
3096
// file: Core/Common.h
3097
3098
#include <vector>
3099
3100
typedef struct {
3101
std::vector<std::wstring> FileList;
3102
int FileCount;
3103
int FileNum;
3104
int LineNumber;
3105
int TotalLineCount;
3106
} tFileInfo;
3107
3108
typedef struct {
3109
tFileInfo FileInfo;
3110
SymbolTable symbolTable;
3111
EncodingTable Table;
3112
int Section;
3113
bool nocash;
3114
bool relativeInclude;
3115
int validationPasses;
3116
bool memoryMode;
3117
std::shared_ptr<AssemblerFile> memoryFile;
3118
bool multiThreading;
3119
} tGlobal;
3120
3121
extern tGlobal Global;
3122
extern CArchitecture* Arch;
3123
3124
class FileManager;
3125
extern FileManager* g_fileManager;
3126
3127
std::wstring getFolderNameFromPath(const std::wstring& src);
3128
std::wstring getFullPathName(const std::wstring& path);
3129
3130
bool checkLabelDefined(const std::wstring& labelName, int section);
3131
bool checkValidLabelName(const std::wstring& labelName);
3132
3133
bool isPowerOfTwo(int64_t n);
3134
3135
// file: Parser/DirectivesParser.h
3136
3137
#include <unordered_map>
3138
3139
class CAssemblerCommand;
3140
class Parser;
3141
3142
using DirectiveFunc = std::unique_ptr<CAssemblerCommand> (*)(Parser&,int);
3143
3144
struct DirectiveEntry {
3145
DirectiveFunc function;
3146
int flags;
3147
};
3148
3149
using DirectiveMap = std::unordered_multimap<std::wstring, const DirectiveEntry>;
3150
3151
#define DIRECTIVE_USERMASK 0x0000FFFF
3152
3153
// Global flags
3154
#define DIRECTIVE_NOCASHON 0x00010000
3155
#define DIRECTIVE_NOCASHOFF 0x00020000
3156
#define DIRECTIVE_MIPSRESETDELAY 0x00040000
3157
#define DIRECTIVE_DISABLED 0x00080000
3158
#define DIRECTIVE_NOTINMEMORY 0x00100000
3159
#define DIRECTIVE_MANUALSEPARATOR 0x00200000
3160
3161
// file directive flags
3162
#define DIRECTIVE_POS_PHYSICAL 0x00000001
3163
#define DIRECTIVE_POS_VIRTUAL 0x00000002
3164
#define DIRECTIVE_ALIGN_PHYSICAL 0x00000001
3165
#define DIRECTIVE_ALIGN_VIRTUAL 0x00000002
3166
#define DIRECTIVE_ALIGN_FILL 0x00000004
3167
3168
// conditional directive flags
3169
#define DIRECTIVE_COND_IF 0x00000001
3170
#define DIRECTIVE_COND_IFDEF 0x00000002
3171
#define DIRECTIVE_COND_IFNDEF 0x00000003
3172
3173
// data directive flags
3174
#define DIRECTIVE_DATA_8 0x00000001
3175
#define DIRECTIVE_DATA_16 0x00000002
3176
#define DIRECTIVE_DATA_32 0x00000003
3177
#define DIRECTIVE_DATA_64 0x00000004
3178
#define DIRECTIVE_DATA_ASCII 0x00000005
3179
#define DIRECTIVE_DATA_SJIS 0x00000006
3180
#define DIRECTIVE_DATA_CUSTOM 0x00000007
3181
#define DIRECTIVE_DATA_FLOAT 0x00000008
3182
#define DIRECTIVE_DATA_DOUBLE 0x00000009
3183
#define DIRECTIVE_DATA_TERMINATION 0x00000100
3184
3185
// message directive flags
3186
#define DIRECTIVE_MSG_WARNING 0x00000001
3187
#define DIRECTIVE_MSG_ERROR 0x00000002
3188
#define DIRECTIVE_MSG_NOTICE 0x00000003
3189
3190
// MIPS directive flags
3191
#define DIRECTIVE_MIPS_PSX 0x00000001
3192
#define DIRECTIVE_MIPS_PS2 0x00000002
3193
#define DIRECTIVE_MIPS_PSP 0x00000003
3194
#define DIRECTIVE_MIPS_N64 0x00000004
3195
#define DIRECTIVE_MIPS_RSP 0x00000005
3196
3197
// ARM directive flags
3198
#define DIRECTIVE_ARM_GBA 0x00000001
3199
#define DIRECTIVE_ARM_NDS 0x00000002
3200
#define DIRECTIVE_ARM_3DS 0x00000003
3201
#define DIRECTIVE_ARM_BIG 0x00000004
3202
#define DIRECTIVE_ARM_LITTLE 0x00000005
3203
3204
extern const DirectiveMap directives;
3205
3206
// file: Parser/Tokenizer.h
3207
3208
enum class TokenType
3209
{
3210
Invalid,
3211
Identifier,
3212
Integer,
3213
String,
3214
Float,
3215
LParen,
3216
RParen,
3217
Plus,
3218
Minus,
3219
Mult,
3220
Div,
3221
Mod,
3222
Caret,
3223
Tilde,
3224
LeftShift,
3225
RightShift,
3226
Less,
3227
Greater,
3228
LessEqual,
3229
GreaterEqual,
3230
Equal,
3231
NotEqual,
3232
BitAnd,
3233
BitOr,
3234
LogAnd,
3235
LogOr,
3236
Exclamation,
3237
Question,
3238
Colon,
3239
LBrack,
3240
RBrack,
3241
Comma,
3242
Assign,
3243
Equ,
3244
EquValue,
3245
Hash,
3246
LBrace,
3247
RBrace,
3248
Dollar,
3249
NumberString,
3250
Degree,
3251
Separator
3252
};
3253
3254
struct Token
3255
{
3256
friend class Tokenizer;
3257
3258
Token() : originalText(nullptr), stringValue(nullptr), checked(false)
3259
{
3260
}
3261
3262
Token(Token &&src)
3263
{
3264
// Move strings.
3265
originalText = src.originalText;
3266
src.originalText = nullptr;
3267
stringValue = src.stringValue;
3268
src.stringValue = nullptr;
3269
3270
// Just copy the rest.
3271
type = src.type;
3272
line = src.line;
3273
column = src.column;
3274
floatValue = src.floatValue;
3275
checked = src.checked;
3276
}
3277
3278
Token(const Token &src) {
3279
// Copy strings.
3280
originalText = nullptr;
3281
if (src.originalText)
3282
setOriginalText(src.originalText);
3283
stringValue = nullptr;
3284
if (src.stringValue)
3285
setStringValue(src.stringValue);
3286
3287
// And copy the rest.
3288
type = src.type;
3289
line = src.line;
3290
column = src.column;
3291
floatValue = src.floatValue;
3292
checked = src.checked;
3293
}
3294
3295
~Token()
3296
{
3297
clearOriginalText();
3298
clearStringValue();
3299
}
3300
3301
Token& operator=(const Token& src)
3302
{
3303
// Copy strings.
3304
originalText = nullptr;
3305
if (src.originalText)
3306
setOriginalText(src.originalText);
3307
stringValue = nullptr;
3308
if (src.stringValue)
3309
setStringValue(src.stringValue);
3310
3311
// And copy the rest.
3312
type = src.type;
3313
line = src.line;
3314
column = src.column;
3315
floatValue = src.floatValue;
3316
checked = src.checked;
3317
3318
return *this;
3319
}
3320
3321
void setOriginalText(const std::wstring& t)
3322
{
3323
setOriginalText(t, 0, t.length());
3324
}
3325
3326
void setOriginalText(const std::wstring& t, const size_t pos, const size_t len)
3327
{
3328
clearOriginalText();
3329
originalText = new wchar_t[len + 1];
3330
wmemcpy(originalText, t.data() + pos, len);
3331
originalText[len] = 0;
3332
}
3333
3334
std::wstring getOriginalText() const
3335
{
3336
return originalText;
3337
}
3338
3339
void setStringValue(const std::wstring& t)
3340
{
3341
setStringValue(t, 0, t.length());
3342
}
3343
3344
void setStringValue(const std::wstring& t, const size_t pos, const size_t len)
3345
{
3346
clearStringValue();
3347
stringValue = new wchar_t[len + 1];
3348
wmemcpy(stringValue, t.data() + pos, len);
3349
stringValue[len] = 0;
3350
}
3351
3352
void setStringAndOriginalValue(const std::wstring& t)
3353
{
3354
setStringAndOriginalValue(t, 0, t.length());
3355
}
3356
3357
void setStringAndOriginalValue(const std::wstring& t, const size_t pos, const size_t len)
3358
{
3359
setStringValue(t, pos, len);
3360
clearOriginalText();
3361
originalText = stringValue;
3362
}
3363
3364
std::wstring getStringValue() const
3365
{
3366
if (stringValue)
3367
return stringValue;
3368
return L"";
3369
}
3370
3371
bool stringValueStartsWith(wchar_t c) const
3372
{
3373
if (stringValue)
3374
return stringValue[0] == c;
3375
return false;
3376
}
3377
3378
TokenType type;
3379
size_t line;
3380
size_t column;
3381
3382
union
3383
{
3384
int64_t intValue;
3385
double floatValue;
3386
};
3387
3388
protected:
3389
void clearOriginalText()
3390
{
3391
if (originalText != stringValue)
3392
delete [] originalText;
3393
originalText = nullptr;
3394
}
3395
3396
void clearStringValue()
3397
{
3398
if (stringValue != originalText)
3399
delete [] stringValue;
3400
stringValue = nullptr;
3401
}
3402
3403
wchar_t* originalText;
3404
wchar_t* stringValue;
3405
3406
bool checked;
3407
};
3408
3409
typedef std::list<Token> TokenList;
3410
3411
struct TokenizerPosition
3412
{
3413
friend class Tokenizer;
3414
3415
TokenizerPosition previous()
3416
{
3417
TokenizerPosition pos = *this;
3418
pos.it--;
3419
return pos;
3420
}
3421
private:
3422
TokenList::iterator it;
3423
};
3424
3425
class Tokenizer
3426
{
3427
public:
3428
Tokenizer();
3429
const Token& nextToken();
3430
const Token& peekToken(int ahead = 0);
3431
void eatToken() { eatTokens(1); }
3432
void eatTokens(int num);
3433
bool atEnd() { return position.it == tokens.end(); }
3434
TokenizerPosition getPosition() { return position; }
3435
void setPosition(TokenizerPosition pos) { position = pos; }
3436
void skipLookahead();
3437
std::vector<Token> getTokens(TokenizerPosition start, TokenizerPosition end) const;
3438
void registerReplacement(const std::wstring& identifier, std::vector<Token>& tokens);
3439
void registerReplacement(const std::wstring& identifier, const std::wstring& newValue);
3440
static size_t addEquValue(const std::vector<Token>& tokens);
3441
static void clearEquValues() { equValues.clear(); }
3442
void resetLookaheadCheckMarks();
3443
protected:
3444
void clearTokens() { tokens.clear(); };
3445
void resetPosition() { position.it = tokens.begin(); }
3446
void addToken(Token token);
3447
private:
3448
bool processElement(TokenList::iterator& it);
3449
3450
TokenList tokens;
3451
TokenizerPosition position;
3452
3453
struct Replacement
3454
{
3455
std::wstring identifier;
3456
std::vector<Token> value;
3457
};
3458
3459
Token invalidToken;
3460
std::vector<Replacement> replacements;
3461
static std::vector<std::vector<Token>> equValues;
3462
};
3463
3464
class FileTokenizer: public Tokenizer
3465
{
3466
public:
3467
bool init(TextFile* input);
3468
protected:
3469
Token loadToken();
3470
bool isInputAtEnd() { return linePos >= currentLine.size() && input->atEnd(); };
3471
3472
void skipWhitespace();
3473
void createToken(TokenType type, size_t length);
3474
void createToken(TokenType type, size_t length, int64_t value);
3475
void createToken(TokenType type, size_t length, double value);
3476
void createToken(TokenType type, size_t length, const std::wstring& value);
3477
void createToken(TokenType type, size_t length, const std::wstring& value, size_t valuePos, size_t valueLength);
3478
void createTokenCurrentString(TokenType type, size_t length);
3479
3480
bool convertInteger(size_t start, size_t end, int64_t& result);
3481
bool convertFloat(size_t start, size_t end, double& result);
3482
bool parseOperator();
3483
3484
TextFile* input;
3485
std::wstring currentLine;
3486
size_t lineNumber;
3487
size_t linePos;
3488
3489
Token token;
3490
bool equActive;
3491
};
3492
3493
class TokenStreamTokenizer: public Tokenizer
3494
{
3495
public:
3496
void init(const std::vector<Token>& tokens)
3497
{
3498
clearTokens();
3499
3500
for (const Token &tok: tokens)
3501
addToken(tok);
3502
3503
resetPosition();
3504
}
3505
};
3506
3507
// file: Archs/MIPS/MipsMacros.h
3508
3509
#define MIPSM_B 0x00000001
3510
#define MIPSM_BU 0x00000002
3511
#define MIPSM_HW 0x00000003
3512
#define MIPSM_HWU 0x00000004
3513
#define MIPSM_W 0x00000005
3514
#define MIPSM_WU 0x00000006
3515
#define MIPSM_DW 0x00000007
3516
#define MIPSM_LLSCW 0x00000008
3517
#define MIPSM_LLSCDW 0x00000009
3518
#define MIPSM_COP1 0x0000000a
3519
#define MIPSM_COP2 0x0000000b
3520
#define MIPSM_DCOP1 0x0000000c
3521
#define MIPSM_DCOP2 0x0000000d
3522
#define MIPSM_ACCESSMASK 0x0000000f
3523
3524
#define MIPSM_NE 0x00000001
3525
#define MIPSM_LT 0x00000002
3526
#define MIPSM_LTU 0x00000003
3527
#define MIPSM_GE 0x00000004
3528
#define MIPSM_GEU 0x00000005
3529
#define MIPSM_EQ 0x00000006
3530
#define MIPSM_CONDITIONMASK 0x00000007
3531
3532
#define MIPSM_IMM 0x00000200
3533
#define MIPSM_LEFT 0x00000400
3534
#define MIPSM_RIGHT 0x00000800
3535
#define MIPSM_UNALIGNED 0x00001000
3536
#define MIPSM_DONTWARNDELAYSLOT 0x00002000
3537
#define MIPSM_UPPER 0x00004000
3538
#define MIPSM_LOWER 0x00008000
3539
#define MIPSM_LOAD 0x00010000
3540
#define MIPSM_STORE 0x00020000
3541
#define MIPSM_LIKELY 0x00040000
3542
#define MIPSM_REVCMP 0x00080000
3543
3544
class Parser;
3545
3546
using MipsMacroFunc = std::unique_ptr<CAssemblerCommand> (*)(Parser&,MipsRegisterData&,MipsImmediateData&,int);
3547
3548
struct MipsMacroDefinition {
3549
const wchar_t* name;
3550
const wchar_t* args;
3551
MipsMacroFunc function;
3552
int flags;
3553
};
3554
3555
extern const MipsMacroDefinition mipsMacros[];
3556
3557
class MipsMacroCommand: public CAssemblerCommand
3558
{
3559
public:
3560
MipsMacroCommand(std::unique_ptr<CAssemblerCommand> content, int macroFlags);
3561
virtual bool Validate();
3562
virtual void Encode() const;
3563
virtual void writeTempData(TempData& tempData) const;
3564
private:
3565
std::unique_ptr<CAssemblerCommand> content;
3566
int macroFlags;
3567
bool IgnoreLoadDelay;
3568
};
3569
3570
// file: Archs/MIPS/MipsParser.h
3571
#include <unordered_map>
3572
3573
struct MipsRegisterDescriptor {
3574
const wchar_t* name;
3575
int num;
3576
};
3577
3578
class MipsParser
3579
{
3580
public:
3581
std::unique_ptr<CAssemblerCommand> parseDirective(Parser& parser);
3582
std::unique_ptr<CMipsInstruction> parseOpcode(Parser& parser);
3583
std::unique_ptr<CAssemblerCommand> parseMacro(Parser& parser);
3584
private:
3585
bool parseRegisterNumber(Parser& parser, MipsRegisterValue& dest, int numValues);
3586
bool parseRegisterTable(Parser& parser, MipsRegisterValue& dest, const MipsRegisterDescriptor* table, size_t count);
3587
bool parseRegister(Parser& parser, MipsRegisterValue& dest);
3588
bool parseFpuRegister(Parser& parser, MipsRegisterValue& dest);
3589
bool parseFpuControlRegister(Parser& parser, MipsRegisterValue& dest);
3590
bool parseCop0Register(Parser& parser, MipsRegisterValue& dest);
3591
bool parsePs2Cop2Register(Parser& parser, MipsRegisterValue& dest);
3592
bool parsePsxCop2DataRegister(Parser& parser, MipsRegisterValue& dest);
3593
bool parsePsxCop2ControlRegister(Parser& parser, MipsRegisterValue& dest);
3594
bool parseRspCop0Register(Parser& parser, MipsRegisterValue& dest);
3595
bool parseRspVectorControlRegister(Parser& parser, MipsRegisterValue& dest);
3596
bool parseRspVectorRegister(Parser& parser, MipsRegisterValue& dest);
3597
bool parseRspVectorElement(Parser& parser, MipsRegisterValue& dest);
3598
bool parseRspScalarElement(Parser& parser, MipsRegisterValue& dest);
3599
bool parseRspOffsetElement(Parser& parser, MipsRegisterValue& dest);
3600
bool parseVfpuRegister(Parser& parser, MipsRegisterValue& reg, int size);
3601
bool parseVfpuControlRegister(Parser& parser, MipsRegisterValue& reg);
3602
bool parseImmediate(Parser& parser, Expression& dest);
3603
bool parseVcstParameter(Parser& parser, int& result);
3604
bool parseVfpuVrot(Parser& parser, int& result, int size);
3605
bool parseVfpuCondition(Parser& parser, int& result);
3606
bool parseVpfxsParameter(Parser& parser, int& result);
3607
bool parseVpfxdParameter(Parser& parser, int& result);
3608
bool parseCop2BranchCondition(Parser& parser, int& result);
3609
bool parseWb(Parser& parser);
3610
3611
bool decodeCop2BranchCondition(const std::wstring& text, size_t& pos, int& result);
3612
bool decodeVfpuType(const std::wstring& name, size_t& pos, int& dest);
3613
bool decodeOpcode(const std::wstring& name, const tMipsOpcode& opcode);
3614
3615
void setOmittedRegisters(const tMipsOpcode& opcode);
3616
bool matchSymbol(Parser& parser, wchar_t symbol);
3617
bool parseParameters(Parser& parser, const tMipsOpcode& opcode);
3618
bool parseMacroParameters(Parser& parser, const MipsMacroDefinition& macro);
3619
3620
MipsRegisterData registers;
3621
MipsImmediateData immediate;
3622
MipsOpcodeData opcodeData;
3623
bool hasFixedSecondaryImmediate;
3624
};
3625
3626
class MipsOpcodeFormatter
3627
{
3628
public:
3629
const std::wstring& formatOpcode(const MipsOpcodeData& opData, const MipsRegisterData& regData,
3630
const MipsImmediateData& immData);
3631
private:
3632
void handleOpcodeName(const MipsOpcodeData& opData);
3633
void handleOpcodeParameters(const MipsOpcodeData& opData, const MipsRegisterData& regData,
3634
const MipsImmediateData& immData);
3635
void handleImmediate(MipsImmediateType type, unsigned int originalValue, unsigned int opcodeFlags);
3636
3637
std::wstring buffer;
3638
};
3639
3640
// file: Archs/MIPS/CMipsInstruction.cpp
3641
3642
CMipsInstruction::CMipsInstruction(MipsOpcodeData& opcode, MipsImmediateData& immediate, MipsRegisterData& registers)
3643
{
3644
this->opcodeData = opcode;
3645
this->immediateData = immediate;
3646
this->registerData = registers;
3647
3648
addNop = false;
3649
IgnoreLoadDelay = Mips.GetIgnoreDelay();
3650
}
3651
3652
CMipsInstruction::~CMipsInstruction()
3653
{
3654
3655
}
3656
3657
int getImmediateBits(MipsImmediateType type)
3658
{
3659
switch (type)
3660
{
3661
case MipsImmediateType::Immediate5:
3662
return 5;
3663
case MipsImmediateType::Immediate7:
3664
return 7;
3665
case MipsImmediateType::Immediate10:
3666
return 10;
3667
case MipsImmediateType::Immediate16:
3668
case MipsImmediateType::ImmediateHalfFloat:
3669
return 16;
3670
case MipsImmediateType::Immediate20:
3671
case MipsImmediateType::Immediate20_0:
3672
return 20;
3673
case MipsImmediateType::Immediate25:
3674
return 25;
3675
case MipsImmediateType::Immediate26:
3676
return 26;
3677
default:
3678
return 0;
3679
}
3680
}
3681
3682
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/Allegrex/VfpuState.java?spec=svn3676&r=3383#1196
3683
int CMipsInstruction::floatToHalfFloat(int i)
3684
{
3685
int s = ((i >> 16) & 0x00008000); // sign
3686
int e = ((i >> 23) & 0x000000ff) - (127 - 15); // exponent
3687
int f = ((i >> 0) & 0x007fffff); // fraction
3688
3689
// need to handle NaNs and Inf?
3690
if (e <= 0) {
3691
if (e < -10) {
3692
if (s != 0) {
3693
// handle -0.0
3694
return 0x8000;
3695
}
3696
return 0;
3697
}
3698
f = (f | 0x00800000) >> (1 - e);
3699
return s | (f >> 13);
3700
} else if (e == 0xff - (127 - 15)) {
3701
if (f == 0) {
3702
// Inf
3703
return s | 0x7c00;
3704
}
3705
// NAN
3706
return s | 0x7fff;
3707
}
3708
3709
if (e > 30) {
3710
// Overflow
3711
return s | 0x7c00;
3712
}
3713
3714
return s | (e << 10) | (f >> 13);
3715
}
3716
3717
bool CMipsInstruction::Validate()
3718
{
3719
bool Result = false;
3720
3721
bool previousNop = addNop;
3722
addNop = false;
3723
3724
RamPos = g_fileManager->getVirtualAddress();
3725
if (RamPos % 4)
3726
{
3727
Logger::queueError(Logger::Error,L"opcode not aligned to word boundary");
3728
return false;
3729
}
3730
3731
// check immediates
3732
if (immediateData.primary.type != MipsImmediateType::None)
3733
{
3734
if (immediateData.primary.expression.isLoaded())
3735
{
3736
if (immediateData.primary.expression.evaluateInteger(immediateData.primary.value) == false)
3737
{
3738
Logger::queueError(Logger::Error, L"Invalid immediate expression");
3739
return false;
3740
}
3741
3742
immediateData.primary.originalValue = immediateData.primary.value;
3743
}
3744
3745
if (immediateData.primary.type == MipsImmediateType::ImmediateHalfFloat)
3746
immediateData.primary.value = floatToHalfFloat(immediateData.primary.originalValue);
3747
3748
if (opcodeData.opcode.flags & MO_IMMALIGNED) // immediate must be aligned
3749
{
3750
if (immediateData.primary.value % 4)
3751
{
3752
Logger::queueError(Logger::Error,L"Immediate must be word aligned");
3753
return false;
3754
}
3755
}
3756
3757
if (opcodeData.opcode.flags & MO_NEGIMM) // negated immediate
3758
{
3759
immediateData.primary.value = -immediateData.primary.value;
3760
} else if (opcodeData.opcode.flags & MO_IPCA) // absolute value >> 2
3761
{
3762
immediateData.primary.value = (immediateData.primary.value >> 2) & 0x3FFFFFF;
3763
} else if (opcodeData.opcode.flags & MO_IPCR) // relative 16 bit value
3764
{
3765
int num = (int) (immediateData.primary.value-RamPos-4);
3766
3767
if (num > 0x20000 || num < (-0x20000))
3768
{
3769
Logger::queueError(Logger::Error,L"Branch target %08X out of range",immediateData.primary.value);
3770
return false;
3771
}
3772
immediateData.primary.value = num >> 2;
3773
} else if (opcodeData.opcode.flags & (MO_RSP_HWOFFSET | MO_RSP_WOFFSET | MO_RSP_DWOFFSET | MO_RSP_QWOFFSET))
3774
{
3775
int shift = 0;
3776
3777
if (opcodeData.opcode.flags & MO_RSP_HWOFFSET) shift = 1;
3778
else if (opcodeData.opcode.flags & MO_RSP_WOFFSET) shift = 2;
3779
else if (opcodeData.opcode.flags & MO_RSP_DWOFFSET) shift = 3;
3780
else if (opcodeData.opcode.flags & MO_RSP_QWOFFSET) shift = 4;
3781
3782
if (immediateData.primary.value & ((1 << shift) - 1))
3783
{
3784
Logger::queueError(Logger::Error,L"Offset must be %d-byte aligned",1<<shift);
3785
return false;
3786
}
3787
immediateData.primary.value = immediateData.primary.value >> shift;
3788
}
3789
3790
int immediateBits = getImmediateBits(immediateData.primary.type);
3791
unsigned int mask = (0xFFFFFFFF << (32-immediateBits)) >> (32-immediateBits);
3792
int digits = (immediateBits+3) / 4;
3793
3794
if ((unsigned int)std::abs(immediateData.primary.value) > mask)
3795
{
3796
Logger::queueError(Logger::Error,L"Immediate value 0x%0*X out of range",digits,immediateData.primary.value);
3797
return false;
3798
}
3799
3800
immediateData.primary.value &= mask;
3801
}
3802
3803
if (immediateData.secondary.type != MipsImmediateType::None)
3804
{
3805
if (immediateData.secondary.expression.isLoaded())
3806
{
3807
if (immediateData.secondary.expression.evaluateInteger(immediateData.secondary.value) == false)
3808
{
3809
Logger::queueError(Logger::Error, L"Invalid immediate expression");
3810
return false;
3811
}
3812
3813
immediateData.secondary.originalValue = immediateData.secondary.value;
3814
}
3815
3816
switch (immediateData.secondary.type)
3817
{
3818
case MipsImmediateType::CacheOp:
3819
if ((unsigned int)immediateData.secondary.value > 0x1f)
3820
{
3821
Logger::queueError(Logger::Error,L"Immediate value %02X out of range",immediateData.secondary.value);
3822
return false;
3823
}
3824
break;
3825
case MipsImmediateType::Ext:
3826
case MipsImmediateType::Ins:
3827
if (immediateData.secondary.value > 32 || immediateData.secondary.value == 0)
3828
{
3829
Logger::queueError(Logger::Error,L"Immediate value %02X out of range",immediateData.secondary.value);
3830
return false;
3831
}
3832
3833
immediateData.secondary.value--;
3834
if (immediateData.secondary.type == MipsImmediateType::Ins)
3835
immediateData.secondary.value += immediateData.primary.value;
3836
break;
3837
case MipsImmediateType::Cop2BranchType:
3838
default:
3839
break;
3840
}
3841
}
3842
3843
// check load delay
3844
if (Mips.hasLoadDelay() && Mips.GetLoadDelay() && IgnoreLoadDelay == false)
3845
{
3846
bool fix = false;
3847
3848
if (registerData.grd.num != -1 && registerData.grd.num == Mips.GetLoadDelayRegister())
3849
{
3850
Logger::queueError(Logger::Warning,L"register %S may not be available due to load delay",registerData.grd.name);
3851
fix = true;
3852
} else if (registerData.grs.num != -1 && registerData.grs.num == Mips.GetLoadDelayRegister())
3853
{
3854
Logger::queueError(Logger::Warning,L"register %S may not be available due to load delay",registerData.grs.name);
3855
fix = true;
3856
} else if (registerData.grt.num != -1 && registerData.grt.num == Mips.GetLoadDelayRegister()
3857
&& !(opcodeData.opcode.flags & MO_IGNORERTD))
3858
{
3859
Logger::queueError(Logger::Warning,L"register %S may not be available due to load delay",registerData.grt.name);
3860
fix = true;
3861
}
3862
3863
if (Mips.GetFixLoadDelay() == true && fix == true)
3864
{
3865
addNop = true;
3866
Logger::queueError(Logger::Notice,L"added nop to ensure correct behavior");
3867
}
3868
}
3869
3870
if ((opcodeData.opcode.flags & MO_NODELAYSLOT) && Mips.GetDelaySlot() == true && IgnoreLoadDelay == false)
3871
{
3872
Logger::queueError(Logger::Error,L"This instruction can't be in a delay slot");
3873
}
3874
3875
Mips.SetDelaySlot(opcodeData.opcode.flags & MO_DELAY ? true : false);
3876
3877
// now check if this opcode causes a load delay
3878
if (Mips.hasLoadDelay())
3879
Mips.SetLoadDelay(opcodeData.opcode.flags & MO_DELAYRT ? true : false,registerData.grt.num);
3880
3881
if (previousNop != addNop)
3882
Result = true;
3883
3884
g_fileManager->advanceMemory(addNop ? 8 : 4);
3885
return Result;
3886
}
3887
3888
void CMipsInstruction::encodeNormal() const
3889
{
3890
int encoding = opcodeData.opcode.destencoding;
3891
3892
if (registerData.grs.num != -1) encoding |= MIPS_RS(registerData.grs.num); // source reg
3893
if (registerData.grt.num != -1) encoding |= MIPS_RT(registerData.grt.num); // target reg
3894
if (registerData.grd.num != -1) encoding |= MIPS_RD(registerData.grd.num); // dest reg
3895
3896
if (registerData.frt.num != -1) encoding |= MIPS_FT(registerData.frt.num); // float target reg
3897
if (registerData.frs.num != -1) encoding |= MIPS_FS(registerData.frs.num); // float source reg
3898
if (registerData.frd.num != -1) encoding |= MIPS_FD(registerData.frd.num); // float dest reg
3899
3900
if (registerData.ps2vrt.num != -1) encoding |= (registerData.ps2vrt.num << 16); // ps2 vector target reg
3901
if (registerData.ps2vrs.num != -1) encoding |= (registerData.ps2vrs.num << 21); // ps2 vector source reg
3902
if (registerData.ps2vrd.num != -1) encoding |= (registerData.ps2vrd.num << 6); // ps2 vector dest reg
3903
3904
if (registerData.rspvrt.num != -1) encoding |= MIPS_FT(registerData.rspvrt.num); // rsp vector target reg
3905
if (registerData.rspvrs.num != -1) encoding |= MIPS_FS(registerData.rspvrs.num); // rsp vector source reg
3906
if (registerData.rspvrd.num != -1) encoding |= MIPS_FD(registerData.rspvrd.num); // rsp vector dest reg
3907
3908
if (registerData.rspve.num != -1) encoding |= MIPS_RSP_VE(registerData.rspve.num); // rsp element
3909
if (registerData.rspvde.num != -1) encoding |= MIPS_RSP_VDE(registerData.rspvde.num); // rsp destination element
3910
if (registerData.rspvealt.num != -1) encoding |= MIPS_RSP_VEALT(registerData.rspvealt.num); // rsp element (alt. placement)
3911
3912
if (!(opcodeData.opcode.flags & MO_VFPU_MIXED) && registerData.vrt.num != -1) // vfpu rt
3913
encoding |= registerData.vrt.num << 16;
3914
3915
switch (immediateData.primary.type)
3916
{
3917
case MipsImmediateType::Immediate5:
3918
case MipsImmediateType::Immediate10:
3919
case MipsImmediateType::Immediate20:
3920
encoding |= immediateData.primary.value << 6;
3921
break;
3922
case MipsImmediateType::Immediate16:
3923
case MipsImmediateType::Immediate25:
3924
case MipsImmediateType::Immediate26:
3925
case MipsImmediateType::Immediate20_0:
3926
case MipsImmediateType::Immediate7:
3927
case MipsImmediateType::ImmediateHalfFloat:
3928
encoding |= immediateData.primary.value;
3929
break;
3930
default:
3931
// TODO: Assert?
3932
break;
3933
}
3934
3935
switch (immediateData.secondary.type)
3936
{
3937
case MipsImmediateType::CacheOp:
3938
encoding |= immediateData.secondary.value << 16;
3939
break;
3940
case MipsImmediateType::Ext:
3941
case MipsImmediateType::Ins:
3942
encoding |= immediateData.secondary.value << 11;
3943
break;
3944
case MipsImmediateType::Cop2BranchType:
3945
encoding |= immediateData.secondary.value << 18;
3946
break;
3947
default:
3948
// TODO: Assert?
3949
break;
3950
}
3951
3952
if (opcodeData.opcode.flags & MO_VFPU_MIXED)
3953
{
3954
// always vrt
3955
encoding |= registerData.vrt.num >> 5;
3956
encoding |= (registerData.vrt.num & 0x1F) << 16;
3957
}
3958
3959
g_fileManager->writeU32((uint32_t)encoding);
3960
}
3961
3962
void CMipsInstruction::encodeVfpu() const
3963
{
3964
int encoding = opcodeData.opcode.destencoding;
3965
3966
if (opcodeData.vectorCondition != -1) encoding |= (opcodeData.vectorCondition << 0);
3967
if (registerData.vrd.num != -1) encoding |= (registerData.vrd.num << 0);
3968
if (registerData.vrs.num != -1) encoding |= (registerData.vrs.num << 8);
3969
if (registerData.vrt.num != -1) encoding |= (registerData.vrt.num << 16);
3970
if (opcodeData.vfpuSize != -1 && (opcodeData.opcode.flags & (MO_VFPU_PAIR|MO_VFPU_SINGLE|MO_VFPU_TRIPLE|MO_VFPU_QUAD)) == 0)
3971
{
3972
if (opcodeData.vfpuSize & 1) encoding |= (1 << 7);
3973
if (opcodeData.vfpuSize & 2) encoding |= (1 << 15);
3974
}
3975
3976
if (registerData.grt.num != -1) encoding |= (registerData.grt.num << 16);
3977
3978
switch (immediateData.primary.type)
3979
{
3980
case MipsImmediateType::Immediate5:
3981
encoding |= immediateData.primary.value << 16;
3982
break;
3983
case MipsImmediateType::Immediate7:
3984
encoding |= immediateData.primary.value << 0;
3985
break;
3986
default:
3987
// TODO: Assert?
3988
break;
3989
}
3990
3991
g_fileManager->writeU32((uint32_t)encoding);
3992
}
3993
3994
void CMipsInstruction::Encode() const
3995
{
3996
if (addNop)
3997
g_fileManager->writeU32(0);
3998
3999
if (opcodeData.opcode.flags & MO_VFPU)
4000
encodeVfpu();
4001
else
4002
encodeNormal();
4003
}
4004
4005
void CMipsInstruction::writeTempData(TempData& tempData) const
4006
{
4007
MipsOpcodeFormatter formatter;
4008
tempData.writeLine(RamPos,formatter.formatOpcode(opcodeData,registerData,immediateData));
4009
}
4010
4011
// file: Archs/MIPS/MipsExpressionFunctions.h
4012
4013
extern const ExpressionFunctionMap mipsExpressionFunctions;
4014
4015
// file: Archs/MIPS/MipsElfRelocator.h
4016
4017
enum {
4018
R_MIPS_NONE,
4019
R_MIPS_16,
4020
R_MIPS_32,
4021
R_MIPS_REL32,
4022
R_MIPS_26,
4023
R_MIPS_HI16,
4024
R_MIPS_LO16,
4025
R_MIPS_GPREL16,
4026
R_MIPS_LITERAL,
4027
R_MIPS_GOT16,
4028
R_MIPS_PC16,
4029
R_MIPS_CALL16,
4030
R_MIPS_GPREL32
4031
};
4032
4033
class MipsElfRelocator: public IElfRelocator
4034
{
4035
public:
4036
int expectedMachine() const override;
4037
bool relocateOpcode(int type, const RelocationData& data, std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors) override;
4038
bool finish(std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors) override;
4039
void setSymbolAddress(RelocationData& data, int64_t symbolAddress, int symbolType) override;
4040
std::unique_ptr<CAssemblerCommand> generateCtorStub(std::vector<ElfRelocatorCtor>& ctors) override;
4041
private:
4042
bool processHi16Entries(uint32_t lo16Opcode, int64_t lo16RelocationBase, std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors);
4043
4044
struct Hi16Entry
4045
{
4046
Hi16Entry(int64_t offset, int64_t relocationBase, uint32_t opcode) : offset(offset), relocationBase(relocationBase), opcode(opcode) {}
4047
int64_t offset;
4048
int64_t relocationBase;
4049
uint32_t opcode;
4050
};
4051
4052
std::vector<Hi16Entry> hi16Entries;
4053
};
4054
4055
// file: Archs/MIPS/Mips.cpp
4056
4057
CMipsArchitecture Mips;
4058
4059
CMipsArchitecture::CMipsArchitecture()
4060
{
4061
FixLoadDelay = false;
4062
IgnoreLoadDelay = false;
4063
LoadDelay = false;
4064
LoadDelayRegister = 0;
4065
DelaySlot = false;
4066
Version = MARCH_INVALID;
4067
}
4068
4069
std::unique_ptr<CAssemblerCommand> CMipsArchitecture::parseDirective(Parser& parser)
4070
{
4071
MipsParser mipsParser;
4072
return mipsParser.parseDirective(parser);
4073
}
4074
4075
std::unique_ptr<CAssemblerCommand> CMipsArchitecture::parseOpcode(Parser& parser)
4076
{
4077
MipsParser mipsParser;
4078
4079
std::unique_ptr<CAssemblerCommand> macro = mipsParser.parseMacro(parser);
4080
if (macro != nullptr)
4081
return macro;
4082
4083
return mipsParser.parseOpcode(parser);
4084
}
4085
4086
const ExpressionFunctionMap& CMipsArchitecture::getExpressionFunctions()
4087
{
4088
return mipsExpressionFunctions;
4089
}
4090
4091
void CMipsArchitecture::NextSection()
4092
{
4093
LoadDelay = false;
4094
LoadDelayRegister = 0;
4095
DelaySlot = false;
4096
}
4097
4098
void CMipsArchitecture::Revalidate()
4099
{
4100
LoadDelay = false;
4101
LoadDelayRegister = 0;
4102
DelaySlot = false;
4103
}
4104
4105
std::unique_ptr<IElfRelocator> CMipsArchitecture::getElfRelocator()
4106
{
4107
switch (Version)
4108
{
4109
case MARCH_PS2:
4110
case MARCH_PSP:
4111
case MARCH_N64:
4112
return ::make_unique<MipsElfRelocator>();
4113
case MARCH_PSX:
4114
case MARCH_RSP:
4115
default:
4116
return nullptr;
4117
}
4118
}
4119
4120
void CMipsArchitecture::SetLoadDelay(bool Delay, int Register)
4121
{
4122
LoadDelay = Delay;
4123
LoadDelayRegister = Register;
4124
}
4125
4126
// file: Archs/MIPS/MipsElfFile.h
4127
4128
class MipsElfFile: public AssemblerFile
4129
{
4130
public:
4131
MipsElfFile();
4132
virtual bool open(bool onlyCheck);
4133
virtual void close();
4134
virtual bool isOpen() { return opened; };
4135
virtual bool write(void* data, size_t length);
4136
virtual int64_t getVirtualAddress();
4137
virtual int64_t getPhysicalAddress();
4138
virtual int64_t getHeaderSize();
4139
virtual bool seekVirtual(int64_t virtualAddress);
4140
virtual bool seekPhysical(int64_t physicalAddress);
4141
virtual bool getModuleInfo(SymDataModuleInfo& info);
4142
virtual void beginSymData(SymbolData& symData);
4143
virtual void endSymData(SymbolData& symData);
4144
virtual const std::wstring& getFileName() { return fileName; };
4145
4146
bool load(const std::wstring& fileName, const std::wstring& outputFileName);
4147
void save();
4148
bool setSection(const std::wstring& name);
4149
private:
4150
ElfFile elf;
4151
std::wstring fileName;
4152
std::wstring outputFileName;
4153
bool opened;
4154
int platform;
4155
4156
int segment;
4157
int section;
4158
size_t sectionOffset;
4159
};
4160
4161
4162
class DirectiveLoadMipsElf: public CAssemblerCommand
4163
{
4164
public:
4165
DirectiveLoadMipsElf(const std::wstring& fileName);
4166
DirectiveLoadMipsElf(const std::wstring& inputName, const std::wstring& outputName);
4167
virtual bool Validate();
4168
virtual void Encode() const;
4169
virtual void writeTempData(TempData& tempData) const;
4170
virtual void writeSymData(SymbolData& symData) const;
4171
private:
4172
std::shared_ptr<MipsElfFile> file;
4173
std::wstring inputName;
4174
std::wstring outputName;
4175
};
4176
4177
// file: Util/CRC.h
4178
4179
unsigned short getCrc16(unsigned char* Source, size_t len);
4180
unsigned int getCrc32(unsigned char* Source, size_t len);
4181
unsigned int getChecksum(unsigned char* Source, size_t len);
4182
4183
// file: Archs/MIPS/MipsElfFile.cpp
4184
4185
MipsElfFile::MipsElfFile()
4186
{
4187
platform = Mips.GetVersion();
4188
section = segment = -1;
4189
opened = false;
4190
}
4191
4192
bool MipsElfFile::open(bool onlyCheck)
4193
{
4194
opened = !onlyCheck;
4195
return true;
4196
}
4197
4198
void MipsElfFile::close()
4199
{
4200
if (isOpen())
4201
save();
4202
}
4203
4204
void MipsElfFile::beginSymData(SymbolData& symData)
4205
{
4206
symData.startModule(this);
4207
}
4208
4209
void MipsElfFile::endSymData(SymbolData& symData)
4210
{
4211
symData.endModule(this);
4212
}
4213
4214
int64_t MipsElfFile::getVirtualAddress()
4215
{
4216
if (segment != -1)
4217
{
4218
ElfSegment* seg = elf.getSegment(segment);
4219
ElfSection* sect = seg->getSection(section);
4220
int64_t addr = seg->getVirtualAddress() + sect->getOffset();
4221
return addr+sectionOffset;
4222
}
4223
4224
// segmentless sections don't have a virtual address
4225
Logger::queueError(Logger::Error,L"Not inside a mapped section");
4226
return -1;
4227
}
4228
4229
int64_t MipsElfFile::getPhysicalAddress()
4230
{
4231
if (segment != -1)
4232
{
4233
ElfSegment* seg = elf.getSegment(segment);
4234
ElfSection* sect = seg->getSection(section);
4235
int64_t addr = seg->getOffset() + sect->getOffset();
4236
return addr;
4237
}
4238
4239
if (section != -1)
4240
{
4241
ElfSection* sect = elf.getSegmentlessSection(section);
4242
return sect->getOffset();
4243
}
4244
4245
Logger::queueError(Logger::Error,L"Not inside a section");
4246
return -1;
4247
}
4248
4249
int64_t MipsElfFile::getHeaderSize()
4250
{
4251
// this method is not used
4252
Logger::queueError(Logger::Error,L"Unimplemented method");
4253
return -1;
4254
}
4255
4256
bool MipsElfFile::seekVirtual(int64_t virtualAddress)
4257
{
4258
// search in segments
4259
for (size_t i = 0; i < elf.getSegmentCount(); i++)
4260
{
4261
ElfSegment* seg = elf.getSegment(i);
4262
int64_t segStart = seg->getVirtualAddress();
4263
int64_t segEnd = segStart+seg->getPhysSize();
4264
4265
if (segStart <= virtualAddress && virtualAddress < segEnd)
4266
{
4267
// find section
4268
for (size_t l = 0; l < seg->getSectionCount(); l++)
4269
{
4270
ElfSection* sect = seg->getSection(l);
4271
int64_t sectStart = segStart+sect->getOffset();
4272
int64_t sectEnd = sectStart+sect->getSize();
4273
4274
if (sectStart <= virtualAddress && virtualAddress < sectEnd)
4275
{
4276
segment = (int) i;
4277
section = (int) l;
4278
sectionOffset = (size_t) (virtualAddress-sectStart);
4279
return true;
4280
}
4281
}
4282
4283
Logger::queueError(Logger::Error,L"Found segment, but no containing section");
4284
return false;
4285
}
4286
}
4287
4288
// segmentless sections don't have a virtual address
4289
Logger::printError(Logger::Error,L"Couldn't find a mapped section");
4290
return false;
4291
}
4292
4293
bool MipsElfFile::seekPhysical(int64_t physicalAddress)
4294
{
4295
// search in segments
4296
for (size_t i = 0; i < elf.getSegmentCount(); i++)
4297
{
4298
ElfSegment* seg = elf.getSegment(i);
4299
int64_t segStart = seg->getOffset();
4300
int64_t segEnd = segStart+seg->getPhysSize();
4301
4302
if (segStart <= physicalAddress && physicalAddress < segEnd)
4303
{
4304
// find section
4305
for (size_t l = 0; l < seg->getSectionCount(); l++)
4306
{
4307
ElfSection* sect = seg->getSection(l);
4308
int64_t sectStart = segStart+sect->getOffset();
4309
int64_t sectEnd = sectStart+sect->getSize();
4310
4311
if (sectStart <= physicalAddress && physicalAddress < sectEnd)
4312
{
4313
segment = (int) i;
4314
section = (int) l;
4315
sectionOffset = physicalAddress-sectStart;
4316
return true;
4317
}
4318
}
4319
4320
Logger::queueError(Logger::Error,L"Found segment, but no containing section");
4321
return false;
4322
}
4323
}
4324
4325
// search in segmentless sections
4326
for (size_t i = 0; i < elf.getSegmentlessSectionCount(); i++)
4327
{
4328
ElfSection* sect = elf.getSegmentlessSection(i);
4329
int64_t sectStart = sect->getOffset();
4330
int64_t sectEnd = sectStart+sect->getSize();
4331
4332
if (sectStart <= physicalAddress && physicalAddress < sectEnd)
4333
{
4334
segment = -1;
4335
section = (int) i;
4336
sectionOffset = physicalAddress-sectStart;
4337
return true;
4338
}
4339
}
4340
4341
segment = -1;
4342
section = -1;
4343
Logger::queueError(Logger::Error,L"Couldn't find a section");
4344
return false;
4345
}
4346
4347
bool MipsElfFile::getModuleInfo(SymDataModuleInfo& info)
4348
{
4349
info.crc32 = getCrc32(elf.getFileData().data(),elf.getFileData().size());
4350
return true;
4351
}
4352
4353
bool MipsElfFile::write(void* data, size_t length)
4354
{
4355
if (segment != -1)
4356
{
4357
ElfSegment* seg = elf.getSegment(segment);
4358
ElfSection* sect = seg->getSection(section);
4359
4360
int64_t pos = sect->getOffset()+sectionOffset;
4361
seg->writeToData(pos,data,length);
4362
sectionOffset += length;
4363
return true;
4364
}
4365
4366
if (section != -1)
4367
{
4368
// TODO: segmentless sections
4369
return false;
4370
}
4371
4372
Logger::printError(Logger::Error,L"Not inside a section");
4373
return false;
4374
}
4375
4376
bool MipsElfFile::load(const std::wstring& fileName, const std::wstring& outputFileName)
4377
{
4378
this->outputFileName = outputFileName;
4379
4380
if (elf.load(fileName,true) == false)
4381
{
4382
Logger::printError(Logger::FatalError,L"Failed to load %s",fileName);
4383
return false;
4384
}
4385
4386
if (elf.getType() == 0xFFA0)
4387
{
4388
Logger::printError(Logger::FatalError,L"Relocatable ELF %s not supported yet",fileName);
4389
return false;
4390
}
4391
4392
if (elf.getType() != 2)
4393
{
4394
Logger::printError(Logger::FatalError,L"Unknown ELF %s type %d",fileName,elf.getType());
4395
return false;
4396
}
4397
4398
if (elf.getSegmentCount() != 0)
4399
seekVirtual(elf.getSegment(0)->getVirtualAddress());
4400
4401
return true;
4402
}
4403
4404
bool MipsElfFile::setSection(const std::wstring& name)
4405
{
4406
std::string utf8Name = convertWStringToUtf8(name);
4407
4408
// look in segments
4409
for (size_t i = 0; i < elf.getSegmentCount(); i++)
4410
{
4411
ElfSegment* seg = elf.getSegment(i);
4412
int n = seg->findSection(utf8Name);
4413
if (n != -1)
4414
{
4415
segment = (int) i;
4416
section = n;
4417
return true;
4418
}
4419
}
4420
4421
// look in stray sections
4422
int n = elf.findSegmentlessSection(utf8Name);
4423
if (n != -1)
4424
{
4425
segment = -1;
4426
section = n;
4427
return true;
4428
}
4429
4430
Logger::queueError(Logger::Warning,L"Section %s not found",name);
4431
return false;
4432
}
4433
4434
void MipsElfFile::save()
4435
{
4436
elf.save(outputFileName);
4437
}
4438
4439
//
4440
// DirectiveLoadPspElf
4441
//
4442
4443
DirectiveLoadMipsElf::DirectiveLoadMipsElf(const std::wstring& fileName)
4444
{
4445
file = std::make_shared<MipsElfFile>();
4446
4447
this->inputName = getFullPathName(fileName);
4448
if (file->load(this->inputName,this->inputName) == false)
4449
{
4450
file = nullptr;
4451
return;
4452
}
4453
4454
g_fileManager->addFile(file);
4455
}
4456
4457
DirectiveLoadMipsElf::DirectiveLoadMipsElf(const std::wstring& inputName, const std::wstring& outputName)
4458
{
4459
file = std::make_shared<MipsElfFile>();
4460
4461
this->inputName = getFullPathName(inputName);
4462
this->outputName = getFullPathName(outputName);
4463
if (file->load(this->inputName,this->outputName) == false)
4464
{
4465
file = nullptr;
4466
return;
4467
}
4468
4469
g_fileManager->addFile(file);
4470
}
4471
4472
bool DirectiveLoadMipsElf::Validate()
4473
{
4474
Arch->NextSection();
4475
g_fileManager->openFile(file,true);
4476
return false;
4477
}
4478
4479
void DirectiveLoadMipsElf::Encode() const
4480
{
4481
g_fileManager->openFile(file,false);
4482
}
4483
4484
void DirectiveLoadMipsElf::writeTempData(TempData& tempData) const
4485
{
4486
if (outputName.empty())
4487
{
4488
tempData.writeLine(g_fileManager->getVirtualAddress(),formatString(L".loadelf \"%s\"",inputName));
4489
} else {
4490
tempData.writeLine(g_fileManager->getVirtualAddress(),formatString(L".loadelf \"%s\",\"%s\"",
4491
inputName,outputName));
4492
}
4493
}
4494
4495
void DirectiveLoadMipsElf::writeSymData(SymbolData& symData) const
4496
{
4497
file->beginSymData(symData);
4498
}
4499
4500
// file: Commands/CommandSequence.h
4501
4502
class Label;
4503
4504
class CommandSequence: public CAssemblerCommand
4505
{
4506
public:
4507
CommandSequence();
4508
virtual bool Validate();
4509
virtual void Encode() const;
4510
virtual void writeTempData(TempData& tempData) const;
4511
virtual void writeSymData(SymbolData& symData) const;
4512
void addCommand(std::unique_ptr<CAssemblerCommand> cmd) { commands.push_back(std::move(cmd)); }
4513
private:
4514
std::vector<std::unique_ptr<CAssemblerCommand>> commands;
4515
};
4516
4517
// file: Parser/Parser.h
4518
#include <set>
4519
#include <map>
4520
#include <unordered_map>
4521
4522
struct AssemblyTemplateArgument
4523
{
4524
const wchar_t* variableName;
4525
std::wstring value;
4526
};
4527
4528
struct ParserMacro
4529
{
4530
std::wstring name;
4531
std::vector<std::wstring> parameters;
4532
std::set<std::wstring> labels;
4533
std::vector<Token> content;
4534
size_t counter;
4535
};
4536
4537
enum class ConditionalResult { Unknown, True, False };
4538
4539
class Parser
4540
{
4541
public:
4542
Parser();
4543
bool atEnd() { return entries.back().tokenizer->atEnd(); }
4544
4545
void addEquation(const Token& start, const std::wstring& name, const std::wstring& value);
4546
4547
Expression parseExpression();
4548
bool parseExpressionList(std::vector<Expression>& list, int min = -1, int max = -1);
4549
bool parseIdentifier(std::wstring& dest);
4550
std::unique_ptr<CAssemblerCommand> parseCommand();
4551
std::unique_ptr<CAssemblerCommand> parseCommandSequence(wchar_t indicator = 0, const std::initializer_list<const wchar_t*> terminators = {});
4552
std::unique_ptr<CAssemblerCommand> parseFile(TextFile& file, bool virtualFile = false);
4553
std::unique_ptr<CAssemblerCommand> parseString(const std::wstring& text);
4554
std::unique_ptr<CAssemblerCommand> parseTemplate(const std::wstring& text, const std::initializer_list<AssemblyTemplateArgument> variables = {});
4555
std::unique_ptr<CAssemblerCommand> parseDirective(const DirectiveMap &directiveSet);
4556
bool matchToken(TokenType type, bool optional = false);
4557
4558
Tokenizer* getTokenizer() { return entries.back().tokenizer; };
4559
const Token& peekToken(int ahead = 0) { return getTokenizer()->peekToken(ahead); };
4560
const Token& nextToken() { return getTokenizer()->nextToken(); };
4561
void eatToken() { getTokenizer()->eatToken(); };
4562
void eatTokens(int num) { getTokenizer()->eatTokens(num); };
4563
4564
void pushConditionalResult(ConditionalResult cond);
4565
void popConditionalResult() { conditionStack.pop_back(); };
4566
bool isInsideTrueBlock() { return conditionStack.back().inTrueBlock; }
4567
bool isInsideUnknownBlock() { return conditionStack.back().inUnknownBlock; }
4568
4569
template <typename... Args>
4570
void printError(const Token& token, const wchar_t* text, const Args&... args)
4571
{
4572
errorLine = token.line;
4573
Global.FileInfo.LineNumber = (int) token.line;
4574
std::wstring errorText = formatString(text,args...);
4575
Logger::printError(Logger::Error,errorText);
4576
error = true;
4577
}
4578
4579
bool hasError() { return error; }
4580
void updateFileInfo();
4581
protected:
4582
void clearError() { error = false; }
4583
std::unique_ptr<CAssemblerCommand> handleError();
4584
4585
std::unique_ptr<CAssemblerCommand> parse(Tokenizer* tokenizer, bool virtualFile, const std::wstring& name = L"");
4586
std::unique_ptr<CAssemblerCommand> parseLabel();
4587
bool checkEquLabel();
4588
bool checkMacroDefinition();
4589
std::unique_ptr<CAssemblerCommand> parseMacroCall();
4590
4591
struct FileEntry
4592
{
4593
Tokenizer* tokenizer;
4594
bool virtualFile;
4595
int fileNum;
4596
int previousCommandLine;
4597
};
4598
4599
std::vector<FileEntry> entries;
4600
std::map<std::wstring,ParserMacro> macros;
4601
std::set<std::wstring> macroLabels;
4602
bool initializingMacro;
4603
bool error;
4604
size_t errorLine;
4605
4606
bool overrideFileInfo;
4607
int overrideFileNum;
4608
int overrideLineNum;
4609
4610
struct ConditionInfo
4611
{
4612
bool inTrueBlock;
4613
bool inUnknownBlock;
4614
};
4615
4616
std::vector<ConditionInfo> conditionStack;
4617
};
4618
4619
struct TokenSequenceValue
4620
{
4621
TokenSequenceValue(const wchar_t* text)
4622
{
4623
type = TokenType::Identifier;
4624
textValue = text;
4625
}
4626
4627
TokenSequenceValue(int64_t num)
4628
{
4629
type = TokenType::Integer;
4630
intValue = num;
4631
}
4632
4633
TokenSequenceValue(double num)
4634
{
4635
type = TokenType::Float;
4636
floatValue = num;
4637
}
4638
4639
4640
TokenType type;
4641
union
4642
{
4643
const wchar_t* textValue;
4644
int64_t intValue;
4645
double floatValue;
4646
};
4647
};
4648
4649
using TokenSequence = std::initializer_list<TokenType>;
4650
using TokenValueSequence = std::initializer_list<TokenSequenceValue>;
4651
4652
class TokenSequenceParser
4653
{
4654
public:
4655
void addEntry(int result, TokenSequence tokens, TokenValueSequence values);
4656
bool parse(Parser& parser, int& result);
4657
size_t getEntryCount() { return entries.size(); }
4658
private:
4659
struct Entry
4660
{
4661
std::vector<TokenType> tokens;
4662
std::vector<TokenSequenceValue> values;
4663
int result;
4664
};
4665
4666
std::vector<Entry> entries;
4667
};
4668
4669
// file: Archs/MIPS/MipsElfRelocator.cpp
4670
4671
int MipsElfRelocator::expectedMachine() const
4672
{
4673
return EM_MIPS;
4674
}
4675
4676
bool MipsElfRelocator::processHi16Entries(uint32_t lo16Opcode, int64_t lo16RelocationBase, std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors)
4677
{
4678
bool result = true;
4679
4680
for (const Hi16Entry &hi16: hi16Entries)
4681
{
4682
if (hi16.relocationBase != lo16RelocationBase)
4683
{
4684
errors.push_back(formatString(L"Mismatched R_MIPS_HI16 with R_MIPS_LO16 of a different symbol"));
4685
result = false;
4686
continue;
4687
}
4688
4689
int32_t addend = (int32_t)((hi16.opcode & 0xFFFF) << 16) + (int16_t)(lo16Opcode & 0xFFFF);
4690
int64_t fullPosition = addend + hi16.relocationBase;
4691
uint32_t opcode = (hi16.opcode & 0xffff0000) | (((fullPosition >> 16) + ((fullPosition & 0x8000) != 0)) & 0xFFFF);
4692
actions.emplace_back(hi16.offset, opcode);
4693
}
4694
4695
hi16Entries.clear();
4696
return result;
4697
}
4698
4699
bool MipsElfRelocator::relocateOpcode(int type, const RelocationData& data, std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors)
4700
{
4701
unsigned int op = data.opcode;
4702
bool result = true;
4703
4704
switch (type)
4705
{
4706
case R_MIPS_26: //j, jal
4707
op = (op & 0xFC000000) | (((op&0x03FFFFFF)+(data.relocationBase>>2))&0x03FFFFFF);
4708
break;
4709
case R_MIPS_32:
4710
op += (int) data.relocationBase;
4711
break;
4712
case R_MIPS_HI16:
4713
hi16Entries.emplace_back(data.opcodeOffset, data.relocationBase, data.opcode);
4714
break;
4715
case R_MIPS_LO16:
4716
if (!processHi16Entries(op, data.relocationBase, actions, errors))
4717
result = false;
4718
op = (op&0xffff0000) | (((op&0xffff)+data.relocationBase)&0xffff);
4719
break;
4720
default:
4721
errors.emplace_back(formatString(L"Unknown MIPS relocation type %d",type));
4722
return false;
4723
}
4724
4725
actions.emplace_back(data.opcodeOffset, op);
4726
return result;
4727
}
4728
4729
bool MipsElfRelocator::finish(std::vector<RelocationAction>& actions, std::vector<std::wstring>& errors)
4730
{
4731
// This shouldn't happen. If it does, relocate as if there was no lo16 opcode
4732
if (!hi16Entries.empty())
4733
return processHi16Entries(0, hi16Entries.front().relocationBase, actions, errors);
4734
return true;
4735
}
4736
4737
void MipsElfRelocator::setSymbolAddress(RelocationData& data, int64_t symbolAddress, int symbolType)
4738
{
4739
data.symbolAddress = symbolAddress;
4740
data.targetSymbolType = symbolType;
4741
}
4742
4743
const wchar_t* mipsCtorTemplate = LR"(
4744
addiu sp,-32
4745
sw ra,0(sp)
4746
sw s0,4(sp)
4747
sw s1,8(sp)
4748
sw s2,12(sp)
4749
sw s3,16(sp)
4750
li s0,%ctorTable%
4751
li s1,%ctorTable%+%ctorTableSize%
4752
%outerLoopLabel%:
4753
lw s2,(s0)
4754
lw s3,4(s0)
4755
addiu s0,8
4756
%innerLoopLabel%:
4757
lw a0,(s2)
4758
jalr a0
4759
addiu s2,4h
4760
bne s2,s3,%innerLoopLabel%
4761
nop
4762
bne s0,s1,%outerLoopLabel%
4763
nop
4764
lw ra,0(sp)
4765
lw s0,4(sp)
4766
lw s1,8(sp)
4767
lw s2,12(sp)
4768
lw s3,16(sp)
4769
jr ra
4770
addiu sp,32
4771
%ctorTable%:
4772
.word %ctorContent%
4773
)";
4774
4775
std::unique_ptr<CAssemblerCommand> MipsElfRelocator::generateCtorStub(std::vector<ElfRelocatorCtor>& ctors)
4776
{
4777
Parser parser;
4778
if (ctors.size() != 0)
4779
{
4780
// create constructor table
4781
std::wstring table;
4782
for (size_t i = 0; i < ctors.size(); i++)
4783
{
4784
if (i != 0)
4785
table += ',';
4786
table += formatString(L"%s,%s+0x%08X",ctors[i].symbolName,ctors[i].symbolName,ctors[i].size);
4787
}
4788
4789
return parser.parseTemplate(mipsCtorTemplate,{
4790
{ L"%ctorTable%", Global.symbolTable.getUniqueLabelName() },
4791
{ L"%ctorTableSize%", formatString(L"%d",ctors.size()*8) },
4792
{ L"%outerLoopLabel%", Global.symbolTable.getUniqueLabelName() },
4793
{ L"%innerLoopLabel%", Global.symbolTable.getUniqueLabelName() },
4794
{ L"%ctorContent%", table },
4795
});
4796
} else {
4797
return parser.parseTemplate(L"jr ra :: nop");
4798
}
4799
}
4800
4801
// file: Archs/MIPS/MipsExpressionFunctions.cpp
4802
4803
#define GET_PARAM(params,index,dest) \
4804
if (getExpFuncParameter(params,index,dest,funcName,false) == false) \
4805
return ExpressionValue();
4806
4807
ExpressionValue expFuncHi(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
4808
{
4809
int64_t value;
4810
4811
GET_PARAM(parameters,0,value);
4812
4813
return ExpressionValue((int64_t)((value >> 16) + ((value & 0x8000) != 0)) & 0xFFFF);
4814
}
4815
4816
ExpressionValue expFuncLo(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
4817
{
4818
int64_t value;
4819
4820
GET_PARAM(parameters,0,value);
4821
4822
return ExpressionValue((int64_t)(int16_t)(value & 0xFFFF));
4823
}
4824
4825
const ExpressionFunctionMap mipsExpressionFunctions = {
4826
{ L"lo", { &expFuncLo, 1, 1, ExpFuncSafety::Safe } },
4827
{ L"hi", { &expFuncHi, 1, 1, ExpFuncSafety::Safe } },
4828
};
4829
4830
// file: Archs/MIPS/MipsMacros.cpp
4831
4832
MipsMacroCommand::MipsMacroCommand(std::unique_ptr<CAssemblerCommand> content, int macroFlags)
4833
{
4834
this->content = std::move(content);
4835
this->macroFlags = macroFlags;
4836
IgnoreLoadDelay = Mips.GetIgnoreDelay();
4837
}
4838
4839
bool MipsMacroCommand::Validate()
4840
{
4841
int64_t memoryPos = g_fileManager->getVirtualAddress();
4842
content->applyFileInfo();
4843
bool result = content->Validate();
4844
int64_t newMemoryPos = g_fileManager->getVirtualAddress();
4845
4846
applyFileInfo();
4847
4848
if (IgnoreLoadDelay == false && Mips.GetDelaySlot() == true && (newMemoryPos-memoryPos) > 4
4849
&& (macroFlags & MIPSM_DONTWARNDELAYSLOT) == 0)
4850
{
4851
Logger::queueError(Logger::Warning,L"Macro with multiple opcodes used inside a delay slot");
4852
}
4853
4854
if (newMemoryPos == memoryPos)
4855
Logger::queueError(Logger::Warning,L"Empty macro content");
4856
4857
return result;
4858
}
4859
4860
void MipsMacroCommand::Encode() const
4861
{
4862
content->Encode();
4863
}
4864
4865
void MipsMacroCommand::writeTempData(TempData& tempData) const
4866
{
4867
content->applyFileInfo();
4868
content->writeTempData(tempData);
4869
}
4870
4871
std::wstring preprocessMacro(const wchar_t* text, MipsImmediateData& immediates)
4872
{
4873
// A macro is turned into a sequence of opcodes that are parsed seperately.
4874
// Any expressions used in the macro may be evaluated at a different memory
4875
// position, so the '.' operator needs to be replaced by a label at the start
4876
// of the macro
4877
std::wstring labelName = Global.symbolTable.getUniqueLabelName(true);
4878
immediates.primary.expression.replaceMemoryPos(labelName);
4879
immediates.secondary.expression.replaceMemoryPos(labelName);
4880
4881
return formatString(L"%s: %s",labelName,text);
4882
}
4883
4884
std::unique_ptr<CAssemblerCommand> createMacro(Parser& parser, const std::wstring& text, int flags, std::initializer_list<AssemblyTemplateArgument> variables)
4885
{
4886
std::unique_ptr<CAssemblerCommand> content = parser.parseTemplate(text,variables);
4887
return ::make_unique<MipsMacroCommand>(std::move(content),flags);
4888
}
4889
4890
std::unique_ptr<CAssemblerCommand> generateMipsMacroAbs(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
4891
{
4892
const wchar_t* templateAbs = LR"(
4893
%sraop% r1,%rs%,31
4894
xor %rd%,%rs%,r1
4895
%subop% %rd%,%rd%,r1
4896
)";
4897
4898
std::wstring sraop, subop;
4899
4900
switch (flags & MIPSM_ACCESSMASK)
4901
{
4902
case MIPSM_W: sraop = L"sra"; subop = L"subu"; break;
4903
case MIPSM_DW: sraop = L"dsra32"; subop = L"dsubu"; break;
4904
default: return nullptr;
4905
}
4906
4907
std::wstring macroText = preprocessMacro(templateAbs,immediates);
4908
return createMacro(parser,macroText,flags, {
4909
{ L"%rd%", registers.grd.name },
4910
{ L"%rs%", registers.grs.name },
4911
{ L"%sraop%", sraop },
4912
{ L"%subop%", subop },
4913
});
4914
}
4915
4916
std::unique_ptr<CAssemblerCommand> generateMipsMacroLiFloat(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
4917
{
4918
const wchar_t* templateLiFloat = LR"(
4919
li r1,float(%imm%)
4920
mtc1 r1,%rs%
4921
)";
4922
4923
std::wstring sraop, subop;
4924
4925
std::wstring macroText = preprocessMacro(templateLiFloat,immediates);
4926
return createMacro(parser,macroText,flags, {
4927
{ L"%imm%", immediates.secondary.expression.toString() },
4928
{ L"%rs%", registers.frs.name },
4929
});
4930
}
4931
4932
std::unique_ptr<CAssemblerCommand> generateMipsMacroLi(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
4933
{
4934
const wchar_t* templateLi = LR"(
4935
.if abs(%imm%) > 0xFFFFFFFF
4936
.error "Immediate value too big"
4937
.elseif %imm% & ~0xFFFF
4938
.if (%imm% & 0xFFFF8000) == 0xFFFF8000
4939
.if %lower%
4940
addiu %rs%,r0, lo(%imm%)
4941
.endif
4942
.elseif (%imm% & 0xFFFF) == 0
4943
.if %upper%
4944
lui %rs%, hi(%imm%)
4945
.elseif %lower%
4946
nop
4947
.endif
4948
.else
4949
.if %upper%
4950
lui %rs%, hi(%imm%)
4951
.endif
4952
.if %lower%
4953
addiu %rs%, lo(%imm%)
4954
.endif
4955
.endif
4956
.else
4957
.if %lower%
4958
ori %rs%,r0,%imm%
4959
.endif
4960
.endif
4961
)";
4962
4963
// floats need to be treated as integers, convert them
4964
if (immediates.secondary.expression.isConstExpression())
4965
{
4966
ExpressionValue value = immediates.secondary.expression.evaluate();
4967
if (value.isFloat())
4968
{
4969
int32_t newValue = getFloatBits((float)value.floatValue);
4970
immediates.secondary.expression = createConstExpression(newValue);
4971
}
4972
}
4973
4974
std::wstring macroText = preprocessMacro(templateLi,immediates);
4975
return createMacro(parser,macroText,flags, {
4976
{ L"%upper%", (flags & MIPSM_UPPER) ? L"1" : L"0" },
4977
{ L"%lower%", (flags & MIPSM_LOWER) ? L"1" : L"0" },
4978
{ L"%rs%", registers.grs.name },
4979
{ L"%imm%", immediates.secondary.expression.toString() },
4980
});
4981
}
4982
4983
std::unique_ptr<CAssemblerCommand> generateMipsMacroLoadStore(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
4984
{
4985
const wchar_t* templateLoadStore = LR"(
4986
.if %imm% & ~0xFFFFFFFF
4987
.error "Address too big"
4988
.elseif %imm% < 0x8000 || (%imm% & 0xFFFF8000) == 0xFFFF8000
4989
.if %lower%
4990
%op% %rs%, lo(%imm%)(r0)
4991
.elseif %upper%
4992
nop
4993
.endif
4994
.else
4995
.if %upper%
4996
lui %temp%, hi(%imm%)
4997
.endif
4998
.if %lower%
4999
%op% %rs%, lo(%imm%)(%temp%)
5000
.endif
5001
.endif
5002
)";
5003
5004
const wchar_t* op;
5005
bool isCop = false;
5006
switch (flags & (MIPSM_ACCESSMASK|MIPSM_LOAD|MIPSM_STORE))
5007
{
5008
case MIPSM_LOAD|MIPSM_B: op = L"lb"; break;
5009
case MIPSM_LOAD|MIPSM_BU: op = L"lbu"; break;
5010
case MIPSM_LOAD|MIPSM_HW: op = L"lh"; break;
5011
case MIPSM_LOAD|MIPSM_HWU: op = L"lhu"; break;
5012
case MIPSM_LOAD|MIPSM_W: op = L"lw"; break;
5013
case MIPSM_LOAD|MIPSM_WU: op = L"lwu"; break;
5014
case MIPSM_LOAD|MIPSM_DW: op = L"ld"; break;
5015
case MIPSM_LOAD|MIPSM_LLSCW: op = L"ll"; break;
5016
case MIPSM_LOAD|MIPSM_LLSCDW: op = L"lld"; break;
5017
case MIPSM_LOAD|MIPSM_COP1: op = L"lwc1"; isCop = true; break;
5018
case MIPSM_LOAD|MIPSM_COP2: op = L"lwc2"; isCop = true; break;
5019
case MIPSM_LOAD|MIPSM_DCOP1: op = L"ldc1"; isCop = true; break;
5020
case MIPSM_LOAD|MIPSM_DCOP2: op = L"ldc2"; isCop = true; break;
5021
case MIPSM_STORE|MIPSM_B: op = L"sb"; break;
5022
case MIPSM_STORE|MIPSM_HW: op = L"sh"; break;
5023
case MIPSM_STORE|MIPSM_W: op = L"sw"; break;
5024
case MIPSM_STORE|MIPSM_DW: op = L"sd"; break;
5025
case MIPSM_STORE|MIPSM_LLSCW: op = L"sc"; break;
5026
case MIPSM_STORE|MIPSM_LLSCDW: op = L"scd"; break;
5027
case MIPSM_STORE|MIPSM_COP1: op = L"swc1"; isCop = true; break;
5028
case MIPSM_STORE|MIPSM_COP2: op = L"swc2"; isCop = true; break;
5029
case MIPSM_STORE|MIPSM_DCOP1: op = L"sdc1"; isCop = true; break;
5030
case MIPSM_STORE|MIPSM_DCOP2: op = L"sdc2"; isCop = true; break;
5031
default: return nullptr;
5032
}
5033
5034
std::wstring macroText = preprocessMacro(templateLoadStore,immediates);
5035
5036
bool store = (flags & MIPSM_STORE) != 0;
5037
return createMacro(parser,macroText,flags, {
5038
{ L"%upper%", (flags & MIPSM_UPPER) ? L"1" : L"0" },
5039
{ L"%lower%", (flags & MIPSM_LOWER) ? L"1" : L"0" },
5040
{ L"%rs%", isCop ? registers.frs.name : registers.grs.name },
5041
{ L"%temp%", isCop || store ? L"r1" : registers.grs.name },
5042
{ L"%imm%", immediates.secondary.expression.toString() },
5043
{ L"%op%", op },
5044
});
5045
}
5046
5047
std::unique_ptr<CAssemblerCommand> generateMipsMacroLoadUnaligned(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
5048
{
5049
const wchar_t* selectedTemplate;
5050
5051
std::wstring op, size;
5052
int type = flags & MIPSM_ACCESSMASK;
5053
if (type == MIPSM_HW || type == MIPSM_HWU)
5054
{
5055
const wchar_t* templateHalfword = LR"(
5056
.if (%off% < 0x8000) && ((%off%+1) >= 0x8000)
5057
.error "Immediate offset too big"
5058
.else
5059
%op% r1,%off%+1(%rs%)
5060
%op% %rd%,%off%(%rs%)
5061
sll r1,8
5062
or %rd%,r1
5063
.endif
5064
)";
5065
5066
op = type == MIPSM_HWU ? L"lbu" : L"lb";
5067
selectedTemplate = templateHalfword;
5068
} else if (type == MIPSM_W || type == MIPSM_DW)
5069
{
5070
const wchar_t* templateWord = LR"(
5071
.if (%off% < 0x8000) && ((%off%+%size%-1) >= 0x8000)
5072
.error "Immediate offset too big"
5073
.else
5074
%op%l %rd%,%off%+%size%-1(%rs%)
5075
%op%r %rd%,%off%(%rs%)
5076
.endif
5077
)";
5078
5079
if (registers.grs.num == registers.grd.num)
5080
{
5081
Logger::printError(Logger::Error,L"Cannot use same register as source and destination");
5082
return ::make_unique<DummyCommand>();
5083
}
5084
5085
op = type == MIPSM_W ? L"lw" : L"ld";
5086
size = type == MIPSM_W ? L"4" : L"8";
5087
selectedTemplate = templateWord;
5088
} else {
5089
return nullptr;
5090
}
5091
5092
std::wstring macroText = preprocessMacro(selectedTemplate,immediates);
5093
return createMacro(parser,macroText,flags, {
5094
{ L"%rs%", registers.grs.name },
5095
{ L"%rd%", registers.grd.name },
5096
{ L"%off%", immediates.primary.expression.toString() },
5097
{ L"%op%", op },
5098
{ L"%size%", size },
5099
});
5100
}
5101
5102
std::unique_ptr<CAssemblerCommand> generateMipsMacroStoreUnaligned(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
5103
{
5104
const wchar_t* selectedTemplate;
5105
5106
std::wstring op, size;
5107
int type = flags & MIPSM_ACCESSMASK;
5108
if (type == MIPSM_HW)
5109
{
5110
const wchar_t* templateHalfword = LR"(
5111
.if (%off% < 0x8000) && ((%off%+1) >= 0x8000)
5112
.error "Immediate offset too big"
5113
.else
5114
sb %rd%,%off%(%rs%)
5115
srl r1,%rd%,8
5116
sb r1,%off%+1(%rs%)
5117
.endif
5118
)";
5119
5120
selectedTemplate = templateHalfword;
5121
} else if (type == MIPSM_W || type == MIPSM_DW)
5122
{
5123
const wchar_t* templateWord = LR"(
5124
.if (%off% < 0x8000) && ((%off%+%size%-1) >= 0x8000)
5125
.error "Immediate offset too big"
5126
.else
5127
%op%l %rd%,%off%+%size%-1(%rs%)
5128
%op%r %rd%,%off%(%rs%)
5129
.endif
5130
)";
5131
5132
if (registers.grs.num == registers.grd.num)
5133
{
5134
Logger::printError(Logger::Error,L"Cannot use same register as source and destination");
5135
return ::make_unique<DummyCommand>();
5136
}
5137
5138
op = type == MIPSM_W ? L"sw" : L"sd";
5139
size = type == MIPSM_W ? L"4" : L"8";
5140
selectedTemplate = templateWord;
5141
} else {
5142
return nullptr;
5143
}
5144
5145
std::wstring macroText = preprocessMacro(selectedTemplate,immediates);
5146
return createMacro(parser,macroText,flags, {
5147
{ L"%rs%", registers.grs.name },
5148
{ L"%rd%", registers.grd.name },
5149
{ L"%off%", immediates.primary.expression.toString() },
5150
{ L"%op%", op },
5151
{ L"%size%", size },
5152
});
5153
}
5154
5155
std::unique_ptr<CAssemblerCommand> generateMipsMacroBranch(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
5156
{
5157
const wchar_t* selectedTemplate;
5158
5159
int type = flags & MIPSM_CONDITIONMASK;
5160
5161
bool bne = type == MIPSM_NE;
5162
bool beq = type == MIPSM_EQ;
5163
bool beqz = type == MIPSM_GE || type == MIPSM_GEU;
5164
bool bnez = type == MIPSM_LT || type == MIPSM_LTU;
5165
bool unsigned_ = type == MIPSM_GEU || type == MIPSM_LTU;
5166
bool immediate = (flags & MIPSM_IMM) != 0;
5167
bool likely = (flags & MIPSM_LIKELY) != 0;
5168
bool revcmp = (flags & MIPSM_REVCMP) != 0;
5169
5170
std::wstring op;
5171
if (bne || beq)
5172
{
5173
const wchar_t* templateNeEq = LR"(
5174
.if %imm% == 0
5175
%op% %rs%,r0,%dest%
5176
.else
5177
li r1,%imm%
5178
%op% %rs%,r1,%dest%
5179
.endif
5180
)";
5181
5182
selectedTemplate = templateNeEq;
5183
if(likely)
5184
op = bne ? L"bnel" : L"beql";
5185
else
5186
op = bne ? L"bne" : L"beq";
5187
} else if (immediate && (beqz || bnez))
5188
{
5189
const wchar_t* templateImmediate = LR"(
5190
.if %revcmp% && %imm% == 0
5191
slt%u% r1,r0,%rs%
5192
.elseif %revcmp%
5193
li r1,%imm%
5194
slt%u% r1,r1,%rs%
5195
.elseif (%imm% < -0x8000) || (%imm% >= 0x8000)
5196
li r1,%imm%
5197
slt%u% r1,%rs%,r1
5198
.else
5199
slti%u% r1,%rs%,%imm%
5200
.endif
5201
%op% r1,%dest%
5202
)";
5203
5204
selectedTemplate = templateImmediate;
5205
if(likely)
5206
op = bnez ? L"bnezl" : L"beqzl";
5207
else
5208
op = bnez ? L"bnez" : L"beqz";
5209
} else if (beqz || bnez)
5210
{
5211
const wchar_t* templateRegister = LR"(
5212
.if %revcmp%
5213
slt%u% r1,%rt%,%rs%
5214
.else
5215
slt%u% r1,%rs%,%rt%
5216
.endif
5217
%op% r1,%dest%
5218
)";
5219
5220
selectedTemplate = templateRegister;
5221
if(likely)
5222
op = bnez ? L"bnezl" : L"beqzl";
5223
else
5224
op = bnez ? L"bnez" : L"beqz";
5225
} else {
5226
return nullptr;
5227
}
5228
5229
std::wstring macroText = preprocessMacro(selectedTemplate,immediates);
5230
return createMacro(parser,macroText,flags, {
5231
{ L"%op%", op },
5232
{ L"%u%", unsigned_ ? L"u" : L""},
5233
{ L"%revcmp%", revcmp ? L"1" : L"0"},
5234
{ L"%rs%", registers.grs.name },
5235
{ L"%rt%", registers.grt.name },
5236
{ L"%imm%", immediates.primary.expression.toString() },
5237
{ L"%dest%", immediates.secondary.expression.toString() },
5238
});
5239
}
5240
5241
std::unique_ptr<CAssemblerCommand> generateMipsMacroSet(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
5242
{
5243
const wchar_t* selectedTemplate;
5244
5245
int type = flags & MIPSM_CONDITIONMASK;
5246
5247
bool ne = type == MIPSM_NE;
5248
bool eq = type == MIPSM_EQ;
5249
bool ge = type == MIPSM_GE || type == MIPSM_GEU;
5250
bool lt = type == MIPSM_LT || type == MIPSM_LTU;
5251
bool unsigned_ = type == MIPSM_GEU || type == MIPSM_LTU;
5252
bool immediate = (flags & MIPSM_IMM) != 0;
5253
bool revcmp = (flags & MIPSM_REVCMP) != 0;
5254
5255
if (immediate && (ne || eq))
5256
{
5257
const wchar_t* templateImmediateEqNe = LR"(
5258
.if %imm% & ~0xFFFF
5259
li %rd%,%imm%
5260
xor %rd%,%rs%,%rd%
5261
.else
5262
xori %rd%,%rs%,%imm%
5263
.endif
5264
.if %eq%
5265
sltiu %rd%,%rd%,1
5266
.else
5267
sltu %rd%,r0,%rd%
5268
.endif
5269
)";
5270
5271
selectedTemplate = templateImmediateEqNe;
5272
} else if (ne || eq)
5273
{
5274
const wchar_t* templateEqNe = LR"(
5275
xor %rd%,%rs%,%rt%
5276
.if %eq%
5277
sltiu %rd%,%rd%,1
5278
.else
5279
sltu %rd%,r0,%rd%
5280
.endif
5281
)";
5282
5283
selectedTemplate = templateEqNe;
5284
} else if (immediate && (ge || lt))
5285
{
5286
const wchar_t* templateImmediateGeLt = LR"(
5287
.if %revcmp% && %imm% == 0
5288
slt%u% %rd%,r0,%rs%
5289
.elseif %revcmp%
5290
li %rd%,%imm%
5291
slt%u% %rd%,%rd%,%rs%
5292
.elseif (%imm% < -0x8000) || (%imm% >= 0x8000)
5293
li %rd%,%imm%
5294
slt%u% %rd%,%rs%,%rd%
5295
.else
5296
slti%u% %rd%,%rs%,%imm%
5297
.endif
5298
.if %ge%
5299
xori %rd%,%rd%,1
5300
.endif
5301
)";
5302
5303
selectedTemplate = templateImmediateGeLt;
5304
} else if (ge)
5305
{
5306
const wchar_t* templateGe = LR"(
5307
.if %revcmp%
5308
slt%u% %rd%,%rt%,%rs%
5309
.else
5310
slt%u% %rd%,%rs%,%rt%
5311
.endif
5312
xori %rd%,%rd%,1
5313
)";
5314
5315
selectedTemplate = templateGe;
5316
} else
5317
{
5318
return nullptr;
5319
}
5320
5321
std::wstring macroText = preprocessMacro(selectedTemplate,immediates);
5322
return createMacro(parser,macroText,flags, {
5323
{ L"%u%", unsigned_ ? L"u" : L""},
5324
{ L"%eq%", eq ? L"1" : L"0" },
5325
{ L"%ge%", ge ? L"1" : L"0" },
5326
{ L"%revcmp%", revcmp ? L"1" : L"0" },
5327
{ L"%rd%", registers.grd.name },
5328
{ L"%rs%", registers.grs.name },
5329
{ L"%rt%", registers.grt.name },
5330
{ L"%imm%", immediates.secondary.expression.toString() },
5331
});
5332
}
5333
5334
std::unique_ptr<CAssemblerCommand> generateMipsMacroRotate(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
5335
{
5336
bool left = (flags & MIPSM_LEFT) != 0;
5337
bool immediate = (flags & MIPSM_IMM) != 0;
5338
bool psp = Mips.GetVersion() == MARCH_PSP;
5339
5340
const wchar_t* selectedTemplate;
5341
if (psp && immediate)
5342
{
5343
const wchar_t* templatePspImmediate = LR"(
5344
.if %amount% != 0
5345
.if %left%
5346
rotr %rd%,%rs%,-%amount%&31
5347
.else
5348
rotr %rd%,%rs%,%amount%
5349
.endif
5350
.else
5351
move %rd%,%rs%
5352
.endif
5353
)";
5354
5355
selectedTemplate = templatePspImmediate;
5356
} else if (psp)
5357
{
5358
const wchar_t* templatePspRegister = LR"(
5359
.if %left%
5360
negu r1,%rt%
5361
rotrv %rd%,%rs%,r1
5362
.else
5363
rotrv %rd%,%rs%,%rt%
5364
.endif
5365
)";
5366
5367
selectedTemplate = templatePspRegister;
5368
} else if (immediate)
5369
{
5370
const wchar_t* templateImmediate = LR"(
5371
.if %amount% != 0
5372
.if %left%
5373
srl r1,%rs%,-%amount%&31
5374
sll %rd%,%rs%,%amount%
5375
.else
5376
sll r1,%rs%,-%amount%&31
5377
srl %rd%,%rs%,%amount%
5378
.endif
5379
or %rd%,%rd%,r1
5380
.else
5381
move %rd%,%rs%
5382
.endif
5383
)";
5384
5385
selectedTemplate = templateImmediate;
5386
} else {
5387
const wchar_t* templateRegister = LR"(
5388
negu r1,%rt%
5389
.if %left%
5390
srlv r1,%rs%,r1
5391
sllv %rd%,%rs%,%rt%
5392
.else
5393
sllv r1,%rs%,r1
5394
srlv %rd%,%rs%,%rt%
5395
.endif
5396
or %rd%,%rd%,r1
5397
)";
5398
5399
selectedTemplate = templateRegister;
5400
}
5401
5402
std::wstring macroText = preprocessMacro(selectedTemplate,immediates);
5403
return createMacro(parser,macroText,flags, {
5404
{ L"%left%", left ? L"1" : L"0" },
5405
{ L"%rd%", registers.grd.name },
5406
{ L"%rs%", registers.grs.name },
5407
{ L"%rt%", registers.grt.name },
5408
{ L"%amount%", immediates.primary.expression.toString() },
5409
});
5410
}
5411
5412
/* Placeholders
5413
i = i1 = 16 bit immediate
5414
I = i2 = 32 bit immediate
5415
s,t,d = registers */
5416
const MipsMacroDefinition mipsMacros[] = {
5417
{ L"abs", L"d,s", &generateMipsMacroAbs, MIPSM_W },
5418
{ L"dabs", L"d,s", &generateMipsMacroAbs, MIPSM_DW },
5419
5420
{ L"li", L"s,I", &generateMipsMacroLi, MIPSM_IMM|MIPSM_UPPER|MIPSM_LOWER },
5421
{ L"li.u", L"s,I", &generateMipsMacroLi, MIPSM_IMM|MIPSM_UPPER },
5422
{ L"li.l", L"s,I", &generateMipsMacroLi, MIPSM_IMM|MIPSM_LOWER },
5423
{ L"la", L"s,I", &generateMipsMacroLi, MIPSM_IMM|MIPSM_UPPER|MIPSM_LOWER },
5424
{ L"la.u", L"s,I", &generateMipsMacroLi, MIPSM_IMM|MIPSM_UPPER },
5425
{ L"la.l", L"s,I", &generateMipsMacroLi, MIPSM_IMM|MIPSM_LOWER },
5426
5427
{ L"li.s", L"S,I", &generateMipsMacroLiFloat, MIPSM_IMM },
5428
5429
{ L"lb", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_B|MIPSM_UPPER|MIPSM_LOWER },
5430
{ L"lbu", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_BU|MIPSM_UPPER|MIPSM_LOWER },
5431
{ L"lh", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_HW|MIPSM_UPPER|MIPSM_LOWER },
5432
{ L"lhu", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_HWU|MIPSM_UPPER|MIPSM_LOWER },
5433
{ L"lw", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_W|MIPSM_UPPER|MIPSM_LOWER },
5434
{ L"lwu", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_WU|MIPSM_UPPER|MIPSM_LOWER },
5435
{ L"ld", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DW|MIPSM_UPPER|MIPSM_LOWER },
5436
{ L"ll", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_LLSCW|MIPSM_UPPER|MIPSM_LOWER },
5437
{ L"lld", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_LLSCDW|MIPSM_UPPER|MIPSM_LOWER },
5438
{ L"lwc1", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP1|MIPSM_UPPER|MIPSM_LOWER },
5439
{ L"l.s", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP1|MIPSM_UPPER|MIPSM_LOWER },
5440
{ L"lwc2", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP2|MIPSM_UPPER|MIPSM_LOWER },
5441
{ L"ldc1", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP1|MIPSM_UPPER|MIPSM_LOWER },
5442
{ L"l.d", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP1|MIPSM_UPPER|MIPSM_LOWER },
5443
{ L"ldc2", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP2|MIPSM_UPPER|MIPSM_LOWER },
5444
5445
{ L"lb.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_B|MIPSM_UPPER },
5446
{ L"lbu.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_BU|MIPSM_UPPER },
5447
{ L"lh.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_HW|MIPSM_UPPER },
5448
{ L"lhu.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_HWU|MIPSM_UPPER },
5449
{ L"lw.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_W|MIPSM_UPPER },
5450
{ L"lwu.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_WU|MIPSM_UPPER },
5451
{ L"ld.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DW|MIPSM_UPPER },
5452
{ L"ll.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_LLSCW|MIPSM_UPPER },
5453
{ L"lld.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_LLSCDW|MIPSM_UPPER },
5454
{ L"lwc1.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP1|MIPSM_UPPER },
5455
{ L"l.s.u", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP1|MIPSM_UPPER },
5456
{ L"lwc2.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP2|MIPSM_UPPER },
5457
{ L"ldc1.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP1|MIPSM_UPPER },
5458
{ L"l.d.u", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP1|MIPSM_UPPER },
5459
{ L"ldc2.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP2|MIPSM_UPPER },
5460
5461
{ L"lb.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_B|MIPSM_LOWER },
5462
{ L"lbu.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_BU|MIPSM_LOWER },
5463
{ L"lh.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_HW|MIPSM_LOWER },
5464
{ L"lhu.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_HWU|MIPSM_LOWER },
5465
{ L"lw.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_W|MIPSM_LOWER },
5466
{ L"lwu.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_WU|MIPSM_LOWER },
5467
{ L"ld.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DW|MIPSM_LOWER },
5468
{ L"ll.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_LLSCW|MIPSM_LOWER },
5469
{ L"lld.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_LLSCDW|MIPSM_LOWER },
5470
{ L"lwc1.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP1|MIPSM_LOWER },
5471
{ L"l.s.l", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP1|MIPSM_LOWER },
5472
{ L"lwc2.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_COP2|MIPSM_LOWER },
5473
{ L"ldc1.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP1|MIPSM_LOWER },
5474
{ L"l.d.l", L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP1|MIPSM_LOWER },
5475
{ L"ldc2.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_LOAD|MIPSM_DCOP2|MIPSM_LOWER },
5476
5477
{ L"ulh", L"d,i(s)", &generateMipsMacroLoadUnaligned, MIPSM_HW|MIPSM_IMM },
5478
{ L"ulh", L"d,(s)", &generateMipsMacroLoadUnaligned, MIPSM_HW },
5479
{ L"ulhu", L"d,i(s)", &generateMipsMacroLoadUnaligned, MIPSM_HWU|MIPSM_IMM },
5480
{ L"ulhu", L"d,(s)", &generateMipsMacroLoadUnaligned, MIPSM_HWU },
5481
{ L"ulw", L"d,i(s)", &generateMipsMacroLoadUnaligned, MIPSM_W|MIPSM_IMM },
5482
{ L"ulw", L"d,(s)", &generateMipsMacroLoadUnaligned, MIPSM_W },
5483
{ L"uld", L"d,i(s)", &generateMipsMacroLoadUnaligned, MIPSM_DW|MIPSM_IMM },
5484
{ L"uld", L"d,(s)", &generateMipsMacroLoadUnaligned, MIPSM_DW },
5485
5486
{ L"sb", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_B|MIPSM_UPPER|MIPSM_LOWER },
5487
{ L"sh", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_HW|MIPSM_UPPER|MIPSM_LOWER },
5488
{ L"sw", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_W|MIPSM_UPPER|MIPSM_LOWER },
5489
{ L"sd", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DW|MIPSM_UPPER|MIPSM_LOWER },
5490
{ L"sc", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_LLSCW|MIPSM_UPPER|MIPSM_LOWER },
5491
{ L"scd", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_LLSCDW|MIPSM_UPPER|MIPSM_LOWER },
5492
{ L"swc1", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP1|MIPSM_UPPER|MIPSM_LOWER },
5493
{ L"s.s", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP1|MIPSM_UPPER|MIPSM_LOWER },
5494
{ L"swc2", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP2|MIPSM_UPPER|MIPSM_LOWER },
5495
{ L"sdc1", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP1|MIPSM_UPPER|MIPSM_LOWER },
5496
{ L"s.d", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP1|MIPSM_UPPER|MIPSM_LOWER },
5497
{ L"sdc2", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP2|MIPSM_UPPER|MIPSM_LOWER },
5498
5499
{ L"sb.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_B|MIPSM_UPPER },
5500
{ L"sh.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_HW|MIPSM_UPPER },
5501
{ L"sw.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_W|MIPSM_UPPER },
5502
{ L"sd.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DW|MIPSM_UPPER },
5503
{ L"sc.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_LLSCW|MIPSM_UPPER },
5504
{ L"scd.u", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_LLSCDW|MIPSM_UPPER },
5505
{ L"swc1.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP1|MIPSM_UPPER },
5506
{ L"s.s.u", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP1|MIPSM_UPPER },
5507
{ L"swc2.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP2|MIPSM_UPPER },
5508
{ L"sdc1.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP1|MIPSM_UPPER },
5509
{ L"s.d.u", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP1|MIPSM_UPPER },
5510
{ L"sdc2.u",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP2|MIPSM_UPPER },
5511
5512
{ L"sb.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_B|MIPSM_LOWER },
5513
{ L"sh.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_HW|MIPSM_LOWER },
5514
{ L"sw.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_W|MIPSM_LOWER },
5515
{ L"sd.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DW|MIPSM_LOWER },
5516
{ L"sc.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_LLSCW|MIPSM_LOWER },
5517
{ L"scd.l", L"s,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_LLSCDW|MIPSM_LOWER },
5518
{ L"swc1.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP1|MIPSM_LOWER },
5519
{ L"s.s.l", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP1|MIPSM_LOWER },
5520
{ L"swc2.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_COP2|MIPSM_LOWER },
5521
{ L"sdc1.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP1|MIPSM_LOWER },
5522
{ L"s.d.l", L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP1|MIPSM_LOWER },
5523
{ L"sdc2.l",L"S,I", &generateMipsMacroLoadStore, MIPSM_STORE|MIPSM_DCOP2|MIPSM_LOWER },
5524
5525
{ L"ush", L"d,i(s)", &generateMipsMacroStoreUnaligned, MIPSM_HW|MIPSM_IMM },
5526
{ L"ush", L"d,(s)", &generateMipsMacroStoreUnaligned, MIPSM_HW },
5527
{ L"usw", L"d,i(s)", &generateMipsMacroStoreUnaligned, MIPSM_W|MIPSM_IMM },
5528
{ L"usw", L"d,(s)", &generateMipsMacroStoreUnaligned, MIPSM_W },
5529
{ L"usd", L"d,i(s)", &generateMipsMacroStoreUnaligned, MIPSM_DW|MIPSM_IMM },
5530
{ L"usd", L"d,(s)", &generateMipsMacroStoreUnaligned, MIPSM_DW },
5531
5532
{ L"blt", L"s,t,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_DONTWARNDELAYSLOT },
5533
{ L"blt", L"s,i,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT },
5534
{ L"bgt", L"s,t,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5535
{ L"bgt", L"s,i,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5536
{ L"bltu", L"s,t,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_DONTWARNDELAYSLOT },
5537
{ L"bltu", L"s,i,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT },
5538
{ L"bgtu", L"s,t,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5539
{ L"bgtu", L"s,i,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5540
{ L"bge", L"s,t,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_DONTWARNDELAYSLOT },
5541
{ L"bge", L"s,i,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT },
5542
{ L"ble", L"s,t,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5543
{ L"ble", L"s,i,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5544
{ L"bgeu", L"s,t,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_DONTWARNDELAYSLOT },
5545
{ L"bgeu", L"s,i,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT },
5546
{ L"bleu", L"s,t,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5547
{ L"bleu", L"s,i,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT },
5548
{ L"bne", L"s,i,I", &generateMipsMacroBranch, MIPSM_NE|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT },
5549
{ L"beq", L"s,i,I", &generateMipsMacroBranch, MIPSM_EQ|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT },
5550
{ L"bltl", L"s,t,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5551
{ L"bltl", L"s,i,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5552
{ L"bgtl", L"s,t,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5553
{ L"bgtl", L"s,i,I", &generateMipsMacroBranch, MIPSM_LT|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5554
{ L"bltul", L"s,t,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5555
{ L"bltul", L"s,i,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5556
{ L"bgtul", L"s,t,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5557
{ L"bgtul", L"s,i,I", &generateMipsMacroBranch, MIPSM_LTU|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5558
{ L"bgel", L"s,t,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5559
{ L"bgel", L"s,i,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5560
{ L"blel", L"s,t,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5561
{ L"blel", L"s,i,I", &generateMipsMacroBranch, MIPSM_GE|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5562
{ L"bgeul", L"s,t,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5563
{ L"bgeul", L"s,i,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5564
{ L"bleul", L"s,t,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5565
{ L"bleul", L"s,i,I", &generateMipsMacroBranch, MIPSM_GEU|MIPSM_IMM|MIPSM_REVCMP|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5566
{ L"bnel", L"s,i,I", &generateMipsMacroBranch, MIPSM_NE|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5567
{ L"beql", L"s,i,I", &generateMipsMacroBranch, MIPSM_EQ|MIPSM_IMM|MIPSM_DONTWARNDELAYSLOT|MIPSM_LIKELY },
5568
5569
{ L"slt", L"d,s,I", &generateMipsMacroSet, MIPSM_LT|MIPSM_IMM },
5570
{ L"sltu", L"d,s,I", &generateMipsMacroSet, MIPSM_LTU|MIPSM_IMM },
5571
{ L"sgt", L"d,s,I", &generateMipsMacroSet, MIPSM_LT|MIPSM_IMM|MIPSM_REVCMP },
5572
{ L"sgtu", L"d,s,I", &generateMipsMacroSet, MIPSM_LTU|MIPSM_IMM|MIPSM_REVCMP },
5573
{ L"sge", L"d,s,t", &generateMipsMacroSet, MIPSM_GE },
5574
{ L"sge", L"d,s,I", &generateMipsMacroSet, MIPSM_GE|MIPSM_IMM },
5575
{ L"sle", L"d,s,t", &generateMipsMacroSet, MIPSM_GE|MIPSM_REVCMP },
5576
{ L"sle", L"d,s,I", &generateMipsMacroSet, MIPSM_GE|MIPSM_IMM|MIPSM_REVCMP },
5577
{ L"sgeu", L"d,s,t", &generateMipsMacroSet, MIPSM_GEU },
5578
{ L"sgeu", L"d,s,I", &generateMipsMacroSet, MIPSM_GEU|MIPSM_IMM },
5579
{ L"sleu", L"d,s,t", &generateMipsMacroSet, MIPSM_GEU|MIPSM_REVCMP },
5580
{ L"sleu", L"d,s,I", &generateMipsMacroSet, MIPSM_GEU|MIPSM_IMM|MIPSM_REVCMP },
5581
{ L"sne", L"d,s,t", &generateMipsMacroSet, MIPSM_NE },
5582
{ L"sne", L"d,s,I", &generateMipsMacroSet, MIPSM_NE|MIPSM_IMM },
5583
{ L"seq", L"d,s,t", &generateMipsMacroSet, MIPSM_EQ },
5584
{ L"seq", L"d,s,I", &generateMipsMacroSet, MIPSM_EQ|MIPSM_IMM },
5585
5586
{ L"rol", L"d,s,t", &generateMipsMacroRotate, MIPSM_LEFT },
5587
{ L"rol", L"d,s,i", &generateMipsMacroRotate, MIPSM_LEFT|MIPSM_IMM },
5588
{ L"ror", L"d,s,t", &generateMipsMacroRotate, MIPSM_RIGHT },
5589
{ L"ror", L"d,s,i", &generateMipsMacroRotate, MIPSM_RIGHT|MIPSM_IMM },
5590
5591
{ nullptr, nullptr, nullptr, 0 }
5592
};
5593
5594
// file: Archs/MIPS/MipsOpcodes.cpp
5595
5596
const tMipsOpcode MipsOpcodes[] = {
5597
// 31---------26---------------------------------------------------0
5598
// | opcode | |
5599
// ------6----------------------------------------------------------
5600
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5601
// 000 | *1 | *2 | J | JAL | BEQ | BNE | BLEZ | BGTZ | 00..07
5602
// 001 | ADDI | ADDIU | SLTI | SLTIU | ANDI | ORI | XORI | LUI | 08..0F
5603
// 010 | *3 | *4 | *5 | --- | BEQL | BNEL | BLEZL | BGTZL | 10..17
5604
// 011 | DADDI | DADDIU| LDL | LDR | --- | --- | LQ | SQ | 18..1F
5605
// 100 | LB | LH | LWL | LW | LBU | LHU | LWR | LWU | 20..27
5606
// 101 | SB | SH | SWL | SW | SDL | SDR | SWR | CACHE | 28..2F
5607
// 110 | LL | LWC1 | LV.S | --- | LLD | ULV.Q | LV.Q | LD | 30..37
5608
// 111 | SC | SWC1 | SV.S | --- | SCD | USV.Q | SV.Q | SD | 38..3F
5609
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5610
// *1 = SPECIAL *2 = REGIMM *3 = COP0 *4 = COP1 *5 = COP2
5611
{ "j", "i26", MIPS_OP(0x02), MA_MIPS1, MO_IPCA|MO_DELAY|MO_NODELAYSLOT },
5612
{ "jal", "i26", MIPS_OP(0x03), MA_MIPS1, MO_IPCA|MO_DELAY|MO_NODELAYSLOT },
5613
{ "beq", "s,t,i16", MIPS_OP(0x04), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5614
{ "beqz", "s,i16", MIPS_OP(0x04), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5615
{ "b", "i16", MIPS_OP(0x04), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5616
{ "bne", "s,t,i16", MIPS_OP(0x05), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5617
{ "bnez", "s,i16", MIPS_OP(0x05), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5618
{ "blez", "s,i16", MIPS_OP(0x06), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5619
{ "bgtz", "s,i16", MIPS_OP(0x07), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5620
{ "addi", "t,s,i16", MIPS_OP(0x08), MA_MIPS1, MO_IGNORERTD },
5621
{ "addi", "s,i16", MIPS_OP(0x08), MA_MIPS1, MO_RST },
5622
{ "subi", "t,s,i16", MIPS_OP(0x08), MA_MIPS1, MO_IGNORERTD|MO_NEGIMM },
5623
{ "subi", "s,i16", MIPS_OP(0x08), MA_MIPS1, MO_RST|MO_NEGIMM },
5624
{ "addiu", "t,s,i16", MIPS_OP(0x09), MA_MIPS1, MO_IGNORERTD },
5625
{ "addiu", "s,i16", MIPS_OP(0x09), MA_MIPS1, MO_RST },
5626
{ "subiu", "t,s,i16", MIPS_OP(0x09), MA_MIPS1, MO_IGNORERTD|MO_NEGIMM },
5627
{ "subiu", "s,i16", MIPS_OP(0x09), MA_MIPS1, MO_RST|MO_NEGIMM },
5628
{ "slti", "t,s,i16", MIPS_OP(0x0A), MA_MIPS1, MO_IGNORERTD },
5629
{ "slti", "s,i16", MIPS_OP(0x0A), MA_MIPS1, MO_RST },
5630
{ "sltiu", "t,s,i16", MIPS_OP(0x0B), MA_MIPS1, MO_IGNORERTD },
5631
{ "sltiu", "s,i16", MIPS_OP(0x0B), MA_MIPS1, MO_RST },
5632
{ "andi", "t,s,i16", MIPS_OP(0x0C), MA_MIPS1, MO_IGNORERTD },
5633
{ "andi", "s,i16", MIPS_OP(0x0C), MA_MIPS1, MO_RST },
5634
{ "ori", "t,s,i16", MIPS_OP(0x0D), MA_MIPS1, MO_IGNORERTD },
5635
{ "ori", "s,i16", MIPS_OP(0x0D), MA_MIPS1, MO_RST },
5636
{ "xori", "t,s,i16", MIPS_OP(0x0E), MA_MIPS1, MO_IGNORERTD },
5637
{ "xori", "s,i16", MIPS_OP(0x0E), MA_MIPS1, MO_RST },
5638
{ "lui", "t,i16", MIPS_OP(0x0F), MA_MIPS1, MO_IGNORERTD },
5639
{ "cop2", "i25", MIPS_OP(0x12)|(1<<25), MA_PSX, 0 },
5640
{ "beql", "s,t,i16", MIPS_OP(0x14), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5641
{ "beqzl", "s,i16", MIPS_OP(0x14), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5642
{ "bnel", "s,t,i16", MIPS_OP(0x15), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5643
{ "bnezl", "s,i16", MIPS_OP(0x15), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5644
{ "blezl", "s,i16", MIPS_OP(0x16), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5645
{ "bgtzl", "s,i16", MIPS_OP(0x17), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5646
{ "daddi", "t,s,i16", MIPS_OP(0x18), MA_MIPS3, MO_64BIT },
5647
{ "daddi", "s,i16", MIPS_OP(0x18), MA_MIPS3, MO_64BIT|MO_RST },
5648
{ "dsubi", "t,s,i16", MIPS_OP(0x18), MA_MIPS3, MO_64BIT|MO_NEGIMM },
5649
{ "dsubi", "s,i16", MIPS_OP(0x18), MA_MIPS3, MO_64BIT|MO_RST|MO_NEGIMM },
5650
{ "daddiu", "t,s,i16", MIPS_OP(0x19), MA_MIPS3, MO_64BIT },
5651
{ "daddiu", "s,i16", MIPS_OP(0x19), MA_MIPS3, MO_64BIT|MO_RST },
5652
{ "dsubiu", "t,s,i16", MIPS_OP(0x19), MA_MIPS3, MO_64BIT|MO_NEGIMM },
5653
{ "dsubiu", "s,i16", MIPS_OP(0x19), MA_MIPS3, MO_64BIT|MO_RST|MO_NEGIMM },
5654
{ "ldl", "t,i16(s)", MIPS_OP(0x1A), MA_MIPS3, MO_64BIT|MO_DELAYRT|MO_IGNORERTD },
5655
{ "ldl", "t,(s)", MIPS_OP(0x1A), MA_MIPS3, MO_64BIT|MO_DELAYRT|MO_IGNORERTD },
5656
{ "ldr", "t,i16(s)", MIPS_OP(0x1B), MA_MIPS3, MO_64BIT|MO_DELAYRT|MO_IGNORERTD },
5657
{ "ldr", "t,(s)", MIPS_OP(0x1B), MA_MIPS3, MO_64BIT|MO_DELAYRT|MO_IGNORERTD },
5658
{ "lq", "t,i16(s)", MIPS_OP(0x1E), MA_PS2, MO_DELAYRT|MO_IGNORERTD },
5659
{ "lq", "t,(s)", MIPS_OP(0x1E), MA_PS2, MO_DELAYRT|MO_IGNORERTD },
5660
{ "sq", "t,i16(s)", MIPS_OP(0x1F), MA_PS2, MO_DELAYRT|MO_IGNORERTD },
5661
{ "sq", "t,(s)", MIPS_OP(0x1F), MA_PS2, MO_DELAYRT|MO_IGNORERTD },
5662
{ "lb", "t,i16(s)", MIPS_OP(0x20), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5663
{ "lb", "t,(s)", MIPS_OP(0x20), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5664
{ "lh", "t,i16(s)", MIPS_OP(0x21), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5665
{ "lh", "t,(s)", MIPS_OP(0x21), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5666
{ "lwl", "t,i16(s)", MIPS_OP(0x22), MA_MIPS1|MA_EXRSP, MO_DELAYRT|MO_IGNORERTD },
5667
{ "lwl", "t,(s)", MIPS_OP(0x22), MA_MIPS1|MA_EXRSP, MO_DELAYRT|MO_IGNORERTD },
5668
{ "lw", "t,i16(s)", MIPS_OP(0x23), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5669
{ "lw", "t,(s)", MIPS_OP(0x23), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5670
{ "lbu", "t,i16(s)", MIPS_OP(0x24), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5671
{ "lbu", "t,(s)", MIPS_OP(0x24), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5672
{ "lhu", "t,i16(s)", MIPS_OP(0x25), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5673
{ "lhu", "t,(s)", MIPS_OP(0x25), MA_MIPS1, MO_DELAYRT|MO_IGNORERTD },
5674
{ "lwr", "t,i16(s)", MIPS_OP(0x26), MA_MIPS1|MA_EXRSP, MO_DELAYRT|MO_IGNORERTD },
5675
{ "lwr", "t,(s)", MIPS_OP(0x26), MA_MIPS1|MA_EXRSP, MO_DELAYRT|MO_IGNORERTD },
5676
{ "lwu", "t,i16(s)", MIPS_OP(0x27), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5677
{ "lwu", "t,(s)", MIPS_OP(0x27), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5678
{ "sb", "t,i16(s)", MIPS_OP(0x28), MA_MIPS1, 0 },
5679
{ "sb", "t,(s)", MIPS_OP(0x28), MA_MIPS1, 0 },
5680
{ "sh", "t,i16(s)", MIPS_OP(0x29), MA_MIPS1, 0 },
5681
{ "sh", "t,(s)", MIPS_OP(0x29), MA_MIPS1, 0 },
5682
{ "swl", "t,i16(s)", MIPS_OP(0x2A), MA_MIPS1|MA_EXRSP, 0 },
5683
{ "swl", "t,(s)", MIPS_OP(0x2A), MA_MIPS1|MA_EXRSP, 0 },
5684
{ "sw", "t,i16(s)", MIPS_OP(0x2B), MA_MIPS1, 0 },
5685
{ "sw", "t,(s)", MIPS_OP(0x2B), MA_MIPS1, 0 },
5686
{ "sdl", "t,i16(s)", MIPS_OP(0x2C), MA_MIPS3, MO_64BIT },
5687
{ "sdl", "t,(s)", MIPS_OP(0x2C), MA_MIPS3, MO_64BIT },
5688
{ "sdr", "t,i16(s)", MIPS_OP(0x2D), MA_MIPS3, MO_64BIT|MO_IGNORERTD },
5689
{ "sdr", "t,(s)", MIPS_OP(0x2D), MA_MIPS3, MO_64BIT|MO_IGNORERTD },
5690
{ "swr", "t,i16(s)", MIPS_OP(0x2E), MA_MIPS1|MA_EXRSP, 0 },
5691
{ "swr", "t,(s)", MIPS_OP(0x2E), MA_MIPS1|MA_EXRSP, 0 },
5692
{ "cache", "jc,i16(s)", MIPS_OP(0x2F), MA_MIPS2, 0 },
5693
{ "cache", "jc,(s)", MIPS_OP(0x2F), MA_MIPS2, 0 },
5694
{ "ll", "t,i16(s)", MIPS_OP(0x30), MA_MIPS2, MO_DELAYRT|MO_IGNORERTD },
5695
{ "ll", "t,(s)", MIPS_OP(0x30), MA_MIPS2, MO_DELAYRT|MO_IGNORERTD },
5696
{ "lwc1", "T,i16(s)", MIPS_OP(0x31), MA_MIPS1, MO_FPU },
5697
{ "lwc1", "T,(s)", MIPS_OP(0x31), MA_MIPS1, MO_FPU },
5698
{ "l.s", "T,i16(s)", MIPS_OP(0x31), MA_MIPS1, MO_FPU },
5699
{ "l.s", "T,(s)", MIPS_OP(0x31), MA_MIPS1, MO_FPU },
5700
{ "lwc2", "gt,i16(s)", MIPS_OP(0x32), MA_PSX, 0 },
5701
{ "lwc2", "gt,(s)", MIPS_OP(0x32), MA_PSX, 0 },
5702
{ "lv.s", "vt,i16(s)", MIPS_OP(0x32), MA_PSP, MO_VFPU_SINGLE|MO_VFPU_MIXED|MO_IMMALIGNED },
5703
{ "lv.s", "vt,(s)", MIPS_OP(0x32), MA_PSP, MO_VFPU_SINGLE|MO_VFPU_MIXED },
5704
{ "lld", "t,i16(s)", MIPS_OP(0x34), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5705
{ "lld", "t,(s)", MIPS_OP(0x34), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5706
{ "ldc1", "T,i16(s)", MIPS_OP(0x35), MA_MIPS2, MO_DFPU },
5707
{ "ldc1", "T,(s)", MIPS_OP(0x35), MA_MIPS2, MO_DFPU },
5708
{ "l.d", "T,i16(s)", MIPS_OP(0x35), MA_MIPS2, MO_DFPU },
5709
{ "l.d", "T,(s)", MIPS_OP(0x35), MA_MIPS2, MO_DFPU },
5710
{ "ulv.q", "vt,i16(s)", MIPS_OP(0x35), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_IMMALIGNED },
5711
{ "ulv.q", "vt,(s)", MIPS_OP(0x35), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED },
5712
{ "lvl.q", "vt,i16(s)", MIPS_OP(0x35), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5713
{ "lvl.q", "vt,(s)", MIPS_OP(0x35), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5714
{ "lvr.q", "vt,i16(s)", MIPS_OP(0x35)|0x02, MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5715
{ "lvr.q", "vt,(s)", MIPS_OP(0x35)|0x02, MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5716
{ "lv.q", "vt,i16(s)", MIPS_OP(0x36), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5717
{ "lv.q", "vt,(s)", MIPS_OP(0x36), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5718
{ "lqc2", "Vt,i16(s)", MIPS_OP(0x36), MA_PS2, MO_DELAYRT },
5719
{ "ld", "t,i16(s)", MIPS_OP(0x37), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5720
{ "ld", "t,(s)", MIPS_OP(0x37), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5721
{ "sc", "t,i16(s)", MIPS_OP(0x38), MA_MIPS2, 0 },
5722
{ "sc", "t,(s)", MIPS_OP(0x38), MA_MIPS2, 0 },
5723
{ "swc1", "T,i16(s)", MIPS_OP(0x39), MA_MIPS1, MO_FPU },
5724
{ "swc1", "T,(s)", MIPS_OP(0x39), MA_MIPS1, MO_FPU },
5725
{ "s.s", "T,i16(s)", MIPS_OP(0x39), MA_MIPS1, MO_FPU },
5726
{ "s.s", "T,(s)", MIPS_OP(0x39), MA_MIPS1, MO_FPU },
5727
{ "swc2", "gt,i16(s)", MIPS_OP(0x3A), MA_PSX, 0 },
5728
{ "swc2", "gt,(s)", MIPS_OP(0x3A), MA_PSX, 0 },
5729
{ "sv.s", "vt,i16(s)", MIPS_OP(0x3A), MA_PSP, MO_VFPU_SINGLE|MO_VFPU_MIXED|MO_IMMALIGNED },
5730
{ "sv.s", "vt,(s)", MIPS_OP(0x3A), MA_PSP, MO_VFPU_SINGLE|MO_VFPU_MIXED },
5731
{ "scd", "t,i16(s)", MIPS_OP(0x3C), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5732
{ "scd", "t,(s)", MIPS_OP(0x3C), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5733
{ "sdc1", "T,i16(s)", MIPS_OP(0x3D), MA_MIPS2, MO_DFPU },
5734
{ "sdc1", "T,(s)", MIPS_OP(0x3D), MA_MIPS2, MO_DFPU },
5735
{ "s.d", "T,i16(s)", MIPS_OP(0x3D), MA_MIPS2, MO_DFPU },
5736
{ "s.d", "T,(s)", MIPS_OP(0x3D), MA_MIPS2, MO_DFPU },
5737
{ "usv.q", "vt,i16(s)", MIPS_OP(0x3D), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_IMMALIGNED },
5738
{ "usv.q", "vt,(s)", MIPS_OP(0x3D), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED },
5739
{ "svl.q", "vt,i16(s)", MIPS_OP(0x3D), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5740
{ "svl.q", "vt,(s)", MIPS_OP(0x3D), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5741
{ "svr.q", "vt,i16(s)", MIPS_OP(0x3D)|0x02, MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5742
{ "svr.q", "vt,(s)", MIPS_OP(0x3D)|0x02, MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5743
{ "sv.q", "vt,i16(s),w", MIPS_OP(0x3E)|0x02, MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5744
{ "sv.q", "vt,(s),w", MIPS_OP(0x3E)|0x02, MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5745
{ "sv.q", "vt,i16(s)", MIPS_OP(0x3E), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT|MO_IMMALIGNED },
5746
{ "sv.q", "vt,(s)", MIPS_OP(0x3E), MA_PSP, MO_VFPU_QUAD|MO_VFPU_MIXED|MO_VFPU_6BIT },
5747
{ "sqc2", "Vt,i16(s)", MIPS_OP(0x3E), MA_PS2, MO_DELAYRT },
5748
{ "sd", "t,i16(s)", MIPS_OP(0x3F), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5749
{ "sd", "t,(s)", MIPS_OP(0x3F), MA_MIPS3, MO_64BIT|MO_DELAYRT },
5750
5751
// 31---------26------------------------------------------5--------0
5752
// |= SPECIAL| | function|
5753
// ------6----------------------------------------------------6-----
5754
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5755
// 000 | SLL | --- | SRL*1 | SRA | SLLV | --- | SRLV*2| SRAV | 00..07
5756
// 001 | JR | JALR | MOVZ | MOVN |SYSCALL| BREAK | --- | SYNC | 08..0F
5757
// 010 | MFHI | MTHI | MFLO | MTLO | DSLLV | --- | *3 | *4 | 10..17
5758
// 011 | MULT | MULTU | DIV | DIVU | MADD | MADDU | ---- | ----- | 18..1F
5759
// 100 | ADD | ADDU | SUB | SUBU | AND | OR | XOR | NOR | 20..27
5760
// 101 | mfsa | mtsa | SLT | SLTU | *5 | *6 | *7 | *8 | 28..2F
5761
// 110 | TGE | TGEU | TLT | TLTU | TEQ | --- | TNE | --- | 30..37
5762
// 111 | dsll | --- | dsrl | dsra |dsll32 | --- |dsrl32 |dsra32 | 38..3F
5763
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5764
// *1: rotr when rs = 1 (PSP only) *2: rotrv when sa = 1 (PSP only)
5765
// *3: dsrlv on PS2, clz on PSP *4: dsrav on PS2, clo on PSP
5766
// *5: dadd on PS2, max on PSP *6: daddu on PS2, min on PSP
5767
// *7: dsub on PS2, msub on PSP *8: dsubu on PS2, msubu on PSP
5768
{ "sll", "d,t,i5", MIPS_SPECIAL(0x00), MA_MIPS1, 0 },
5769
{ "sll", "d,i5", MIPS_SPECIAL(0x00), MA_MIPS1, MO_RDT },
5770
{ "nop", "", MIPS_SPECIAL(0x00), MA_MIPS1, 0 },
5771
{ "srl", "d,t,i5", MIPS_SPECIAL(0x02), MA_MIPS1, 0 },
5772
{ "srl", "d,i5", MIPS_SPECIAL(0x02), MA_MIPS1, MO_RDT },
5773
{ "rotr", "d,t,i5", MIPS_SPECIAL(0x02)|MIPS_RS(1), MA_PSP, 0 },
5774
{ "rotr", "d,i5", MIPS_SPECIAL(0x02)|MIPS_RS(1), MA_PSP, MO_RDT },
5775
{ "sra", "d,t,i5", MIPS_SPECIAL(0x03), MA_MIPS1, 0 },
5776
{ "sra", "d,i5", MIPS_SPECIAL(0x03), MA_MIPS1, MO_RDT },
5777
{ "sllv", "d,t,s", MIPS_SPECIAL(0x04), MA_MIPS1, 0 },
5778
{ "sllv", "d,s", MIPS_SPECIAL(0x04), MA_MIPS1, MO_RDT },
5779
{ "srlv", "d,t,s", MIPS_SPECIAL(0x06), MA_MIPS1, 0 },
5780
{ "srlv", "d,s", MIPS_SPECIAL(0x06), MA_MIPS1, MO_RDT },
5781
{ "rotrv", "d,t,s", MIPS_SPECIAL(0x06)|MIPS_SA(1), MA_PSP, 0 },
5782
{ "rotrv", "d,s", MIPS_SPECIAL(0x06)|MIPS_SA(1), MA_PSP, MO_RDT },
5783
{ "srav", "d,t,s", MIPS_SPECIAL(0x07), MA_MIPS1, 0 },
5784
{ "srav", "d,s", MIPS_SPECIAL(0x07), MA_MIPS1, MO_RDT },
5785
{ "jr", "s", MIPS_SPECIAL(0x08), MA_MIPS1, MO_DELAY|MO_NODELAYSLOT },
5786
{ "jalr", "s,d", MIPS_SPECIAL(0x09), MA_MIPS1, MO_DELAY|MO_NODELAYSLOT },
5787
{ "jalr", "s", MIPS_SPECIAL(0x09)|MIPS_RD(31), MA_MIPS1, MO_DELAY|MO_NODELAYSLOT },
5788
{ "movz", "d,s,t", MIPS_SPECIAL(0x0A), MA_MIPS4|MA_PS2|MA_PSP, 0 },
5789
{ "movn", "d,s,t", MIPS_SPECIAL(0x0B), MA_MIPS4|MA_PS2|MA_PSP, 0 },
5790
{ "syscall","i20", MIPS_SPECIAL(0x0C), MA_MIPS1|MA_EXRSP, MO_NODELAYSLOT },
5791
{ "syscall","", MIPS_SPECIAL(0x0C), MA_MIPS1|MA_EXRSP, MO_NODELAYSLOT },
5792
{ "break", "i20", MIPS_SPECIAL(0x0D), MA_MIPS1, MO_NODELAYSLOT },
5793
{ "break", "", MIPS_SPECIAL(0x0D), MA_MIPS1, MO_NODELAYSLOT },
5794
{ "sync", "", MIPS_SPECIAL(0x0F), MA_MIPS2, 0 },
5795
{ "mfhi", "d", MIPS_SPECIAL(0x10), MA_MIPS1|MA_EXRSP, 0 },
5796
{ "mthi", "s", MIPS_SPECIAL(0x11), MA_MIPS1|MA_EXRSP, 0 },
5797
{ "mflo", "d", MIPS_SPECIAL(0x12), MA_MIPS1|MA_EXRSP, 0 },
5798
{ "mtlo", "s", MIPS_SPECIAL(0x13), MA_MIPS1|MA_EXRSP, 0 },
5799
{ "dsllv", "d,t,s", MIPS_SPECIAL(0x14), MA_MIPS3, MO_64BIT },
5800
{ "dsllv", "d,s", MIPS_SPECIAL(0x14), MA_MIPS3, MO_64BIT|MO_RDT },
5801
{ "dsrlv", "d,t,s", MIPS_SPECIAL(0x16), MA_MIPS3, MO_64BIT },
5802
{ "dsrlv", "d,s", MIPS_SPECIAL(0x16), MA_MIPS3, MO_64BIT|MO_RDT },
5803
{ "clz", "d,s", MIPS_SPECIAL(0x16), MA_PSP, 0 },
5804
{ "dsrav", "d,t,s", MIPS_SPECIAL(0x17), MA_MIPS3, MO_64BIT },
5805
{ "dsrav", "d,s", MIPS_SPECIAL(0x17), MA_MIPS3, MO_64BIT|MO_RDT },
5806
{ "clo", "d,s", MIPS_SPECIAL(0x17), MA_PSP, 0 },
5807
{ "mult", "d,s,t", MIPS_SPECIAL(0x18), MA_PS2, 0 },
5808
{ "multu", "d,s,t", MIPS_SPECIAL(0x19), MA_PS2, 0 },
5809
{ "mult", "s,t", MIPS_SPECIAL(0x18), MA_MIPS1|MA_EXRSP, 0 },
5810
{ "mult", "r\x0,s,t", MIPS_SPECIAL(0x18), MA_MIPS1|MA_EXRSP, 0 },
5811
{ "multu", "s,t", MIPS_SPECIAL(0x19), MA_MIPS1|MA_EXRSP, 0 },
5812
{ "multu", "r\x0,s,t", MIPS_SPECIAL(0x19), MA_MIPS1|MA_EXRSP, 0 },
5813
{ "div", "s,t", MIPS_SPECIAL(0x1A), MA_MIPS1|MA_EXRSP, 0 },
5814
{ "div", "r\x0,s,t", MIPS_SPECIAL(0x1A), MA_MIPS1|MA_EXRSP, 0 },
5815
{ "divu", "s,t", MIPS_SPECIAL(0x1B), MA_MIPS1|MA_EXRSP, 0 },
5816
{ "divu", "r\x0,s,t", MIPS_SPECIAL(0x1B), MA_MIPS1|MA_EXRSP, 0 },
5817
{ "dmult", "s,t", MIPS_SPECIAL(0x1C), MA_MIPS3|MA_EXPS2, MO_64BIT },
5818
{ "dmult", "r\x0,s,t", MIPS_SPECIAL(0x1C), MA_MIPS3|MA_EXPS2, MO_64BIT },
5819
{ "madd", "s,t", MIPS_SPECIAL(0x1C), MA_PSP, 0 },
5820
{ "dmultu", "s,t", MIPS_SPECIAL(0x1D), MA_MIPS3|MA_EXPS2, MO_64BIT },
5821
{ "dmultu", "r\x0,s,t", MIPS_SPECIAL(0x1D), MA_MIPS3|MA_EXPS2, MO_64BIT },
5822
{ "maddu", "s,t", MIPS_SPECIAL(0x1D), MA_PSP, 0 },
5823
{ "ddiv", "s,t", MIPS_SPECIAL(0x1E), MA_MIPS3|MA_EXPS2, MO_64BIT },
5824
{ "ddiv", "r\x0,s,t", MIPS_SPECIAL(0x1E), MA_MIPS3|MA_EXPS2, MO_64BIT },
5825
{ "ddivu", "s,t", MIPS_SPECIAL(0x1F), MA_MIPS3|MA_EXPS2, MO_64BIT },
5826
{ "ddivu", "r\x0,s,t", MIPS_SPECIAL(0x1F), MA_MIPS3|MA_EXPS2, MO_64BIT },
5827
{ "add", "d,s,t", MIPS_SPECIAL(0x20), MA_MIPS1, 0 },
5828
{ "add", "s,t", MIPS_SPECIAL(0x20), MA_MIPS1, MO_RSD },
5829
{ "addu", "d,s,t", MIPS_SPECIAL(0x21), MA_MIPS1, 0 },
5830
{ "addu", "s,t", MIPS_SPECIAL(0x21), MA_MIPS1, MO_RSD },
5831
{ "move", "d,s", MIPS_SPECIAL(0x21), MA_MIPS1, 0 },
5832
{ "clear", "d", MIPS_SPECIAL(0x21), MA_MIPS1, 0 },
5833
{ "sub", "d,s,t", MIPS_SPECIAL(0x22), MA_MIPS1, 0 },
5834
{ "sub", "s,t", MIPS_SPECIAL(0x22), MA_MIPS1, MO_RSD },
5835
{ "neg", "d,t", MIPS_SPECIAL(0x22), MA_MIPS1, 0 },
5836
{ "subu", "d,s,t", MIPS_SPECIAL(0x23), MA_MIPS1, 0 },
5837
{ "subu", "s,t", MIPS_SPECIAL(0x23), MA_MIPS1, MO_RSD },
5838
{ "negu", "d,t", MIPS_SPECIAL(0x23), MA_MIPS1, 0 },
5839
{ "and", "d,s,t", MIPS_SPECIAL(0x24), MA_MIPS1, 0 },
5840
{ "and", "s,t", MIPS_SPECIAL(0x24), MA_MIPS1, MO_RSD },
5841
{ "or", "d,s,t", MIPS_SPECIAL(0x25), MA_MIPS1, 0 },
5842
{ "or", "s,t", MIPS_SPECIAL(0x25), MA_MIPS1, MO_RSD },
5843
{ "xor", "d,s,t", MIPS_SPECIAL(0x26), MA_MIPS1, 0 },
5844
{ "eor", "d,s,t", MIPS_SPECIAL(0x26), MA_MIPS1, 0 },
5845
{ "xor", "s,t", MIPS_SPECIAL(0x26), MA_MIPS1, MO_RSD },
5846
{ "eor", "s,t", MIPS_SPECIAL(0x26), MA_MIPS1, MO_RSD },
5847
{ "nor", "d,s,t", MIPS_SPECIAL(0x27), MA_MIPS1, 0 },
5848
{ "nor", "s,t", MIPS_SPECIAL(0x27), MA_MIPS1, MO_RSD },
5849
{ "not", "d,s", MIPS_SPECIAL(0x27), MA_MIPS1, 0 },
5850
{ "mfsa", "d", MIPS_SPECIAL(0x28), MA_PS2, 0 },
5851
{ "mtsa", "s", MIPS_SPECIAL(0x29), MA_PS2, 0 },
5852
{ "slt", "d,s,t", MIPS_SPECIAL(0x2A), MA_MIPS1, 0 },
5853
{ "slt", "s,t", MIPS_SPECIAL(0x2A), MA_MIPS1, MO_RSD},
5854
{ "sgt", "d,t,s", MIPS_SPECIAL(0x2A), MA_MIPS1, 0 },
5855
{ "sgt", "d,s", MIPS_SPECIAL(0x2A), MA_MIPS1, MO_RDT},
5856
{ "sltu", "d,s,t", MIPS_SPECIAL(0x2B), MA_MIPS1, 0 },
5857
{ "sltu", "s,t", MIPS_SPECIAL(0x2B), MA_MIPS1, MO_RSD },
5858
{ "sgtu", "d,t,s", MIPS_SPECIAL(0x2B), MA_MIPS1, 0 },
5859
{ "sgtu", "d,s", MIPS_SPECIAL(0x2B), MA_MIPS1, MO_RDT},
5860
{ "dadd", "d,s,t", MIPS_SPECIAL(0x2C), MA_MIPS3, MO_64BIT },
5861
{ "dadd", "s,t", MIPS_SPECIAL(0x2C), MA_MIPS3, MO_64BIT|MO_RSD },
5862
{ "max", "d,s,t", MIPS_SPECIAL(0x2C), MA_PSP, 0 },
5863
{ "daddu", "d,s,t", MIPS_SPECIAL(0x2D), MA_MIPS3, MO_64BIT },
5864
{ "daddu", "s,t", MIPS_SPECIAL(0x2D), MA_MIPS3, MO_64BIT|MO_RSD },
5865
{ "dmove", "d,s", MIPS_SPECIAL(0x2D), MA_MIPS3, MO_64BIT },
5866
{ "min", "d,s,t", MIPS_SPECIAL(0x2D), MA_PSP, 0 },
5867
{ "dsub", "d,s,t", MIPS_SPECIAL(0x2E), MA_MIPS3, MO_64BIT },
5868
{ "dsub", "s,t", MIPS_SPECIAL(0x2E), MA_MIPS3, MO_64BIT|MO_RSD },
5869
{ "dneg", "d,t", MIPS_SPECIAL(0x2E), MA_MIPS3, MO_64BIT },
5870
{ "msub", "s,t", MIPS_SPECIAL(0x2E), MA_PSP, 0 },
5871
{ "dsubu", "d,s,t", MIPS_SPECIAL(0x2F), MA_MIPS3, MO_64BIT },
5872
{ "dsubu", "s,t", MIPS_SPECIAL(0x2F), MA_MIPS3, MO_64BIT|MO_RSD },
5873
{ "dnegu", "d,t", MIPS_SPECIAL(0x2F), MA_MIPS3, MO_64BIT },
5874
{ "msubu", "s,t", MIPS_SPECIAL(0x2F), MA_PSP, 0 },
5875
{ "tge", "s,t,i10", MIPS_SPECIAL(0x30), MA_MIPS2, 0 },
5876
{ "tge", "s,t", MIPS_SPECIAL(0x30), MA_MIPS2, 0 },
5877
{ "tgeu", "s,t,i10", MIPS_SPECIAL(0x31), MA_MIPS2, 0 },
5878
{ "tgeu", "s,t", MIPS_SPECIAL(0x31), MA_MIPS2, 0 },
5879
{ "tlt", "s,t,i10", MIPS_SPECIAL(0x32), MA_MIPS2, 0 },
5880
{ "tlt", "s,t", MIPS_SPECIAL(0x32), MA_MIPS2, 0 },
5881
{ "tltu", "s,t,i10", MIPS_SPECIAL(0x33), MA_MIPS2, 0 },
5882
{ "tltu", "s,t", MIPS_SPECIAL(0x33), MA_MIPS2, 0 },
5883
{ "teq", "s,t,i10", MIPS_SPECIAL(0x34), MA_MIPS2, 0 },
5884
{ "teq", "s,t", MIPS_SPECIAL(0x34), MA_MIPS2, 0 },
5885
{ "tne", "s,t,i10", MIPS_SPECIAL(0x36), MA_MIPS2, 0 },
5886
{ "tne", "s,t", MIPS_SPECIAL(0x36), MA_MIPS2, 0 },
5887
{ "dsll", "d,t,i5", MIPS_SPECIAL(0x38), MA_MIPS3, MO_64BIT },
5888
{ "dsll", "d,i5", MIPS_SPECIAL(0x38), MA_MIPS3, MO_64BIT|MO_RDT },
5889
{ "dsrl", "d,t,i5", MIPS_SPECIAL(0x3A), MA_MIPS3, MO_64BIT },
5890
{ "dsrl", "d,i5", MIPS_SPECIAL(0x3A), MA_MIPS3, MO_64BIT|MO_RDT },
5891
{ "dsra", "d,t,i5", MIPS_SPECIAL(0x3B), MA_MIPS3, MO_64BIT },
5892
{ "dsra", "d,i5", MIPS_SPECIAL(0x3B), MA_MIPS3, MO_64BIT|MO_RDT },
5893
{ "dsll32", "d,t,i5", MIPS_SPECIAL(0x3C), MA_MIPS3, MO_64BIT },
5894
{ "dsll32", "d,i5", MIPS_SPECIAL(0x3C), MA_MIPS3, MO_64BIT|MO_RDT },
5895
{ "dsrl32", "d,t,i5", MIPS_SPECIAL(0x3E), MA_MIPS3, MO_64BIT },
5896
{ "dsrl32", "d,i5", MIPS_SPECIAL(0x3E), MA_MIPS3, MO_64BIT|MO_RDT },
5897
{ "dsra32", "d,t,i5", MIPS_SPECIAL(0x3F), MA_MIPS3, MO_64BIT },
5898
{ "dsra32", "d,i5", MIPS_SPECIAL(0x3F), MA_MIPS3, MO_64BIT|MO_RDT },
5899
5900
// REGIMM: encoded by the rt field when opcode field = REGIMM.
5901
// 31---------26----------20-------16------------------------------0
5902
// |= REGIMM| | rt | |
5903
// ------6---------------------5------------------------------------
5904
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5905
// 00 | BLTZ | BGEZ | BLTZL | BGEZL | --- | --- | --- | --- | 00-07
5906
// 01 | tgei | tgeiu | tlti | tltiu | teqi | --- | tnei | --- | 08-0F
5907
// 10 | BLTZAL| BGEZAL|BLTZALL|BGEZALL| --- | --- | --- | --- | 10-17
5908
// 11 | mtsab | mtsah | --- | --- | --- | --- | --- | --- | 18-1F
5909
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5910
{ "bltz", "s,i16", MIPS_REGIMM(0x00), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5911
{ "bgez", "s,i16", MIPS_REGIMM(0x01), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5912
{ "bltzl", "s,i16", MIPS_REGIMM(0x02), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5913
{ "bgezl", "s,i16", MIPS_REGIMM(0x03), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5914
{ "tgei", "s,i16", MIPS_REGIMM(0x08), MA_MIPS2, 0 },
5915
{ "tgeiu", "s,i16", MIPS_REGIMM(0x09), MA_MIPS2, 0 },
5916
{ "tlti", "s,i16", MIPS_REGIMM(0x0A), MA_MIPS2, 0 },
5917
{ "tltiu", "s,i16", MIPS_REGIMM(0x0B), MA_MIPS2, 0 },
5918
{ "teqi", "s,i16", MIPS_REGIMM(0x0C), MA_MIPS2, 0 },
5919
{ "tnei", "s,i16", MIPS_REGIMM(0x0E), MA_MIPS2, 0 },
5920
{ "bltzal", "s,i16", MIPS_REGIMM(0x10), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5921
{ "bgezal", "s,i16", MIPS_REGIMM(0x11), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5922
{ "bal", "i16", MIPS_REGIMM(0x11), MA_MIPS1, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5923
{ "bltzall","s,i16", MIPS_REGIMM(0x12), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5924
{ "bgezall","s,i16", MIPS_REGIMM(0x13), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5925
{ "mtsab", "s,i16", MIPS_REGIMM(0x18), MA_PS2, 0 },
5926
{ "mtsah", "s,i16", MIPS_REGIMM(0x19), MA_PS2, 0 },
5927
5928
// 31---------26---------21----------------------------------------0
5929
// |= COP0| rs | |
5930
// -----6-------5---------------------------------------------------
5931
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5932
// 00 | MFC0 | DMFC0 | --- | --- | MTC0 | DMTC0 | --- | --- | 00..07
5933
// 01 | --- | --- | --- | --- | --- | --- | --- | --- | 08..0F
5934
// 10 |FUNCT* | --- | --- | --- | --- | --- | --- | --- | 10..17
5935
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
5936
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5937
{ "mfc0", "t,z", MIPS_COP0(0x00), MA_MIPS1|MA_EXRSP, 0 },
5938
{ "mfc0", "t,Rz", MIPS_COP0(0x00), MA_RSP, 0 },
5939
{ "dmfc0", "t,z", MIPS_COP0(0x01), MA_MIPS3, MO_64BIT },
5940
{ "mtc0", "t,z", MIPS_COP0(0x04), MA_MIPS1|MA_EXRSP, 0 },
5941
{ "mtc0", "t,Rz", MIPS_COP0(0x04), MA_RSP, 0 },
5942
{ "dmtc0", "t,z", MIPS_COP0(0x05), MA_MIPS3, MO_64BIT },
5943
5944
// 31--------------------21-------------------------------5--------0
5945
// |= COP0FUNCT| | function|
5946
// -----11----------------------------------------------------6-----
5947
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5948
// 000 | --- | TLBR | TLBWI | --- | --- | --- | TLBWR | --- | 00..07
5949
// 001 | TLBP | --- | --- | --- | --- | --- | --- | --- | 08..0F
5950
// 010 | RFE | --- | --- | --- | --- | --- | --- | --- | 10..17
5951
// 011 | ERET | --- | --- | --- | --- | --- | --- | --- | 18..1F
5952
// 100 | --- | --- | --- | --- | --- | --- | --- | --- | 20..27
5953
// 101 | --- | --- | --- | --- | --- | --- | --- | --- | 28..2F
5954
// 110 | --- | --- | --- | --- | --- | --- | --- | --- | 30..37
5955
// 110 | --- | --- | --- | --- | --- | --- | --- | --- | 38..3F
5956
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5957
{ "tlbr", "", MIPS_COP0FUNCT(0x01), MA_MIPS1|MA_EXRSP, 0 },
5958
{ "tlbwi", "", MIPS_COP0FUNCT(0x02), MA_MIPS1|MA_EXRSP, 0 },
5959
{ "tlbwr", "", MIPS_COP0FUNCT(0x06), MA_MIPS1|MA_EXRSP, 0 },
5960
{ "tlbp", "", MIPS_COP0FUNCT(0x08), MA_MIPS1|MA_EXRSP, 0 },
5961
{ "rfe", "", MIPS_COP0FUNCT(0x10), MA_PSX, 0 },
5962
{ "eret", "", MIPS_COP0FUNCT(0x18), MA_MIPS3, 0 },
5963
5964
// 31---------26---------21----------------------------------------0
5965
// |= COP1| rs | |
5966
// -----6-------5---------------------------------------------------
5967
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5968
// 00 | MFC1 | DMFC1 | CFC1 | --- | MTC1 | DMTC1 | CTC1 | --- | 00..07
5969
// 01 | BC* | --- | --- | --- | --- | --- | --- | --- | 08..0F
5970
// 10 | S* | --- | --- | --- | W* | --- | --- | --- | 10..17
5971
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
5972
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5973
5974
{ "mfc1", "t,S", MIPS_COP1(0x00), MA_MIPS1, MO_FPU },
5975
{ "dmfc1", "t,S", MIPS_COP1(0x01), MA_MIPS3, MO_DFPU|MO_64BIT },
5976
{ "cfc1", "t,f", MIPS_COP1(0x02), MA_MIPS1, MO_FPU },
5977
{ "mtc1", "t,S", MIPS_COP1(0x04), MA_MIPS1, MO_FPU },
5978
{ "dmtc1", "t,S", MIPS_COP1(0x05), MA_MIPS3, MO_DFPU|MO_64BIT },
5979
{ "ctc1", "t,f", MIPS_COP1(0x06), MA_MIPS1, MO_FPU },
5980
5981
// 31---------26----------20-------16------------------------------0
5982
// |= COP1BC| | rt | |
5983
// ------11--------------5------------------------------------------
5984
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5985
// 00 | BC1F | BC1T | BC1FL | BC1TL | --- | --- | --- | --- | 00..07
5986
// 01 | --- | --- | --- | --- | --- | --- | --- | --- | 08..0F
5987
// 10 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
5988
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
5989
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
5990
{ "bc1f", "i16", MIPS_COP1BC(0x00), MA_MIPS1, MO_FPU|MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5991
{ "bc1t", "i16", MIPS_COP1BC(0x01), MA_MIPS1, MO_FPU|MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5992
{ "bc1fl", "i16", MIPS_COP1BC(0x02), MA_MIPS2, MO_FPU|MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5993
{ "bc1tl", "i16", MIPS_COP1BC(0x03), MA_MIPS2, MO_FPU|MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
5994
5995
// 31--------------------21-------------------------------5--------0
5996
// |= COP1S| | function|
5997
// -----11----------------------------------------------------6-----
5998
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
5999
// 000 | add | sub | mul | div | sqrt | abs | mov | neg | 00..07
6000
// 001 |round.l|trunc.l|ceil.l |floor.l|round.w|trunc.w|ceil.w |floor.w| 08..0F
6001
// 010 | --- | --- | --- | --- | --- | --- | rsqrt | --- | 10..17
6002
// 011 | adda | suba | mula | --- | madd | msub | madda | msuba | 18..1F
6003
// 100 | --- | cvt.d | --- | --- | cvt.w | cvt.l | --- | --- | 20..27
6004
// 101 | max | min | --- | --- | --- | --- | --- | --- | 28..2F
6005
// 110 | c.f | c.un | c.eq | c.ueq |c.(o)lt| c.ult |c.(o)le| c.ule | 30..37
6006
// 110 | c.sf | c.ngle| c.seq | c.ngl | c.lt | c.nge | c.le | c.ngt | 38..3F
6007
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6008
{ "add.s", "D,S,T", MIPS_COP1S(0x00), MA_MIPS1, MO_FPU },
6009
{ "add.s", "S,T", MIPS_COP1S(0x00), MA_MIPS1, MO_FPU|MO_FRSD },
6010
{ "sub.s", "D,S,T", MIPS_COP1S(0x01), MA_MIPS1, MO_FPU },
6011
{ "sub.s", "S,T", MIPS_COP1S(0x01), MA_MIPS1, MO_FPU|MO_FRSD },
6012
{ "mul.s", "D,S,T", MIPS_COP1S(0x02), MA_MIPS1, MO_FPU },
6013
{ "mul.s", "S,T", MIPS_COP1S(0x02), MA_MIPS1, MO_FPU|MO_FRSD },
6014
{ "div.s", "D,S,T", MIPS_COP1S(0x03), MA_MIPS1, MO_FPU },
6015
{ "div.s", "S,T", MIPS_COP1S(0x03), MA_MIPS1, MO_FPU|MO_FRSD },
6016
{ "sqrt.s", "D,S", MIPS_COP1S(0x04), MA_MIPS2, MO_FPU },
6017
{ "abs.s", "D,S", MIPS_COP1S(0x05), MA_MIPS1, MO_FPU },
6018
{ "mov.s", "D,S", MIPS_COP1S(0x06), MA_MIPS1, MO_FPU },
6019
{ "neg.s", "D,S", MIPS_COP1S(0x07), MA_MIPS1, MO_FPU },
6020
{ "round.l.s", "D,S", MIPS_COP1S(0x08), MA_MIPS3, MO_DFPU },
6021
{ "trunc.l.s", "D,S", MIPS_COP1S(0x09), MA_MIPS3, MO_DFPU },
6022
{ "ceil.l.s", "D,S", MIPS_COP1S(0x0A), MA_MIPS3, MO_DFPU },
6023
{ "floor.l.s", "D,S", MIPS_COP1S(0x0B), MA_MIPS3, MO_DFPU },
6024
{ "round.w.s", "D,S", MIPS_COP1S(0x0C), MA_MIPS2|MA_EXPS2, MO_FPU },
6025
{ "trunc.w.s", "D,S", MIPS_COP1S(0x0D), MA_MIPS1|MA_EXPS2, MO_FPU },
6026
{ "ceil.w.s", "D,S", MIPS_COP1S(0x0E), MA_MIPS2|MA_EXPS2, MO_FPU },
6027
{ "floor.w.s", "D,S", MIPS_COP1S(0x0F), MA_MIPS2|MA_EXPS2, MO_FPU },
6028
{ "rsqrt.w.s", "D,S", MIPS_COP1S(0x16), MA_PS2, 0 },
6029
{ "adda.s", "S,T", MIPS_COP1S(0x18), MA_PS2, 0 },
6030
{ "suba.s", "S,T", MIPS_COP1S(0x19), MA_PS2, 0 },
6031
{ "mula.s", "S,T", MIPS_COP1S(0x1A), MA_PS2, 0 },
6032
{ "madd.s", "D,S,T", MIPS_COP1S(0x1C), MA_PS2, 0 },
6033
{ "madd.s", "S,T", MIPS_COP1S(0x1C), MA_PS2, MO_FRSD },
6034
{ "msub.s", "D,S,T", MIPS_COP1S(0x1D), MA_PS2, 0 },
6035
{ "msub.s", "S,T", MIPS_COP1S(0x1D), MA_PS2, MO_FRSD },
6036
{ "madda.s", "S,T", MIPS_COP1S(0x1E), MA_PS2, 0 },
6037
{ "msuba.s", "S,T", MIPS_COP1S(0x1F), MA_PS2, 0 },
6038
{ "cvt.d.s", "D,S", MIPS_COP1S(0x21), MA_MIPS1, MO_DFPU },
6039
{ "cvt.w.s", "D,S", MIPS_COP1S(0x24), MA_MIPS1, MO_FPU },
6040
{ "cvt.l.s", "D,S", MIPS_COP1S(0x25), MA_MIPS3, MO_DFPU },
6041
{ "max.s", "D,S,T", MIPS_COP1S(0x28), MA_PS2, 0 },
6042
{ "min.s", "D,S,T", MIPS_COP1S(0x29), MA_PS2, 0 },
6043
{ "c.f.s", "S,T", MIPS_COP1S(0x30), MA_MIPS1, MO_FPU },
6044
{ "c.un.s", "S,T", MIPS_COP1S(0x31), MA_MIPS1|MA_EXPS2, MO_FPU },
6045
{ "c.eq.s", "S,T", MIPS_COP1S(0x32), MA_MIPS1, MO_FPU },
6046
{ "c.ueq.s", "S,T", MIPS_COP1S(0x33), MA_MIPS1|MA_EXPS2, MO_FPU },
6047
{ "c.olt.s", "S,T", MIPS_COP1S(0x34), MA_MIPS1|MA_EXPS2, MO_FPU },
6048
{ "c.lt.s", "S,T", MIPS_COP1S(0x34), MA_PS2, 0 },
6049
{ "c.ult.s", "S,T", MIPS_COP1S(0x35), MA_MIPS1|MA_EXPS2, MO_FPU },
6050
{ "c.ole.s", "S,T", MIPS_COP1S(0x36), MA_MIPS1|MA_EXPS2, MO_FPU },
6051
{ "c.le.s", "S,T", MIPS_COP1S(0x36), MA_PS2, 0 },
6052
{ "c.ule.s", "S,T", MIPS_COP1S(0x37), MA_MIPS1|MA_EXPS2, MO_FPU },
6053
{ "c.sf.s", "S,T", MIPS_COP1S(0x38), MA_MIPS1|MA_EXPS2, MO_FPU },
6054
{ "c.ngle.s", "S,T", MIPS_COP1S(0x39), MA_MIPS1|MA_EXPS2, MO_FPU },
6055
{ "c.seq.s", "S,T", MIPS_COP1S(0x3A), MA_MIPS1|MA_EXPS2, MO_FPU },
6056
{ "c.ngl.s", "S,T", MIPS_COP1S(0x3B), MA_MIPS1|MA_EXPS2, MO_FPU },
6057
{ "c.lt.s", "S,T", MIPS_COP1S(0x3C), MA_MIPS1|MA_EXPS2, MO_FPU },
6058
{ "c.nge.s", "S,T", MIPS_COP1S(0x3D), MA_MIPS1|MA_EXPS2, MO_FPU },
6059
{ "c.le.s", "S,T", MIPS_COP1S(0x3E), MA_MIPS1|MA_EXPS2, MO_FPU },
6060
{ "c.ngt.s", "S,T", MIPS_COP1S(0x3F), MA_MIPS1|MA_EXPS2, MO_FPU },
6061
6062
// 31--------------------21-------------------------------5--------0
6063
// |= COP1D| | function|
6064
// -----11----------------------------------------------------6-----
6065
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6066
// 000 | add | sub | mul | div | sqrt | abs | mov | neg | 00..07
6067
// 001 |round.l|trunc.l|ceil.l |floor.l|round.w|trunc.w|ceil.w |floor.w| 08..0F
6068
// 010 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
6069
// 011 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
6070
// 100 | cvt.s | --- | --- | --- | cvt.w | cvt.l | --- | --- | 20..27
6071
// 101 | --- | --- | --- | --- | --- | --- | --- | --- | 28..2F
6072
// 110 | c.f | c.un | c.eq | c.ueq | c.olt | c.ult | c.ole | c.ule | 30..37
6073
// 110 | c.sf | c.ngle| c.seq | c.ngl | c.lt | c.nge | c.le | c.ngt | 38..3F
6074
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6075
{ "add.d", "D,S,T", MIPS_COP1D(0x00), MA_MIPS1, MO_DFPU },
6076
{ "add.d", "S,T", MIPS_COP1D(0x00), MA_MIPS1, MO_DFPU|MO_FRSD },
6077
{ "sub.d", "D,S,T", MIPS_COP1D(0x01), MA_MIPS1, MO_DFPU },
6078
{ "sub.d", "S,T", MIPS_COP1D(0x01), MA_MIPS1, MO_DFPU|MO_FRSD },
6079
{ "mul.d", "D,S,T", MIPS_COP1D(0x02), MA_MIPS1, MO_DFPU },
6080
{ "mul.d", "S,T", MIPS_COP1D(0x02), MA_MIPS1, MO_DFPU|MO_FRSD },
6081
{ "div.d", "D,S,T", MIPS_COP1D(0x03), MA_MIPS1, MO_DFPU },
6082
{ "div.d", "S,T", MIPS_COP1D(0x03), MA_MIPS1, MO_DFPU|MO_FRSD },
6083
{ "sqrt.d", "D,S", MIPS_COP1D(0x04), MA_MIPS2, MO_DFPU },
6084
{ "abs.d", "D,S", MIPS_COP1D(0x05), MA_MIPS1, MO_DFPU },
6085
{ "mov.d", "D,S", MIPS_COP1D(0x06), MA_MIPS1, MO_DFPU },
6086
{ "neg.d", "D,S", MIPS_COP1D(0x07), MA_MIPS1, MO_DFPU },
6087
{ "round.l.d", "D,S", MIPS_COP1D(0x08), MA_MIPS3, MO_DFPU },
6088
{ "trunc.l.d", "D,S", MIPS_COP1D(0x09), MA_MIPS3, MO_DFPU },
6089
{ "ceil.l.d", "D,S", MIPS_COP1D(0x0A), MA_MIPS3, MO_DFPU },
6090
{ "floor.l.d", "D,S", MIPS_COP1D(0x0B), MA_MIPS3, MO_DFPU },
6091
{ "round.w.d", "D,S", MIPS_COP1D(0x0C), MA_MIPS2, MO_DFPU },
6092
{ "trunc.w.d", "D,S", MIPS_COP1D(0x0D), MA_MIPS1, MO_DFPU },
6093
{ "ceil.w.d", "D,S", MIPS_COP1D(0x0E), MA_MIPS2, MO_DFPU },
6094
{ "floor.w.d", "D,S", MIPS_COP1D(0x0F), MA_MIPS2, MO_DFPU },
6095
{ "cvt.s.d", "D,S", MIPS_COP1D(0x20), MA_MIPS1, MO_DFPU },
6096
{ "cvt.w.d", "D,S", MIPS_COP1D(0x24), MA_MIPS1, MO_DFPU },
6097
{ "cvt.l.d", "D,S", MIPS_COP1D(0x25), MA_MIPS3, MO_DFPU },
6098
{ "c.f.d", "S,T", MIPS_COP1D(0x30), MA_MIPS1, MO_DFPU },
6099
{ "c.un.d", "S,T", MIPS_COP1D(0x31), MA_MIPS1, MO_DFPU },
6100
{ "c.eq.d", "S,T", MIPS_COP1D(0x32), MA_MIPS1, MO_DFPU },
6101
{ "c.ueq.d", "S,T", MIPS_COP1D(0x33), MA_MIPS1, MO_DFPU },
6102
{ "c.olt.d", "S,T", MIPS_COP1D(0x34), MA_MIPS1, MO_DFPU },
6103
{ "c.ult.d", "S,T", MIPS_COP1D(0x35), MA_MIPS1, MO_DFPU },
6104
{ "c.ole.d", "S,T", MIPS_COP1D(0x36), MA_MIPS1, MO_DFPU },
6105
{ "c.ule.d", "S,T", MIPS_COP1D(0x37), MA_MIPS1, MO_DFPU },
6106
{ "c.sf.d", "S,T", MIPS_COP1D(0x38), MA_MIPS1, MO_DFPU },
6107
{ "c.ngle.d", "S,T", MIPS_COP1D(0x39), MA_MIPS1, MO_DFPU },
6108
{ "c.seq.d", "S,T", MIPS_COP1D(0x3A), MA_MIPS1, MO_DFPU },
6109
{ "c.ngl.d", "S,T", MIPS_COP1D(0x3B), MA_MIPS1, MO_DFPU },
6110
{ "c.lt.d", "S,T", MIPS_COP1D(0x3C), MA_MIPS1, MO_DFPU },
6111
{ "c.nge.d", "S,T", MIPS_COP1D(0x3D), MA_MIPS1, MO_DFPU },
6112
{ "c.le.d", "S,T", MIPS_COP1D(0x3E), MA_MIPS1, MO_DFPU },
6113
{ "c.ngt.d", "S,T", MIPS_COP1D(0x3F), MA_MIPS1, MO_DFPU },
6114
6115
// 31--------------------21-------------------------------5--------0
6116
// |= COP1W| | function|
6117
// -----11----------------------------------------------------6-----
6118
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6119
// 000 | --- | --- | --- | --- | --- | --- | --- | --- | 00..07
6120
// 001 | --- | --- | --- | --- | --- | --- | --- | --- | 08..0F
6121
// 010 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
6122
// 011 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
6123
// 100 | cvt.s | cvt.d | --- | --- | --- | --- | --- | --- | 20..27
6124
// 101 | --- | --- | --- | --- | --- | --- | --- | --- | 28..2F
6125
// 110 | --- | --- | --- | --- | --- | --- | --- | --- | 30..37
6126
// 110 | --- | --- | --- | --- | --- | --- | --- | --- | 38..3F
6127
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6128
{ "cvt.s.w", "D,S", MIPS_COP1W(0x20), MA_MIPS1, MO_FPU },
6129
{ "cvt.d.w", "D,S", MIPS_COP1W(0x21), MA_MIPS1, MO_DFPU },
6130
6131
// 31--------------------21-------------------------------5--------0
6132
// |= COP1L| | function|
6133
// -----11----------------------------------------------------6-----
6134
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6135
// 000 | --- | --- | --- | --- | --- | --- | --- | --- | 00..07
6136
// 001 | --- | --- | --- | --- | --- | --- | --- | --- | 08..0F
6137
// 010 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
6138
// 011 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
6139
// 100 | cvt.s | cvt.d | --- | --- | --- | --- | --- | --- | 20..27
6140
// 101 | --- | --- | --- | --- | --- | --- | --- | --- | 28..2F
6141
// 110 | --- | --- | --- | --- | --- | --- | --- | --- | 30..37
6142
// 110 | --- | --- | --- | --- | --- | --- | --- | --- | 38..3F
6143
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6144
{ "cvt.s.l", "D,S", MIPS_COP1L(0x20), MA_MIPS3, MO_DFPU },
6145
{ "cvt.d.l", "D,S", MIPS_COP1L(0x21), MA_MIPS3, MO_DFPU },
6146
6147
// 31---------26---------21----------------------------------------0
6148
// |= COP2| rs | |
6149
// -----6-------5---------------------------------------------------
6150
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6151
// 00 | MFC2 | --- | CFC2 | MFV | MTC2 | --- | CTC2 | MTV |
6152
// 01 | BC* | --- | --- | --- | --- | --- | --- | --- |
6153
// 10 | --- | --- | --- | --- | --- | --- | --- | --- |
6154
// 11 | --- | --- | --- | --- | --- | --- | --- | --- |
6155
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6156
6157
{ "mfc2", "t,gs", MIPS_COP2(0x00), MA_PSX, 0 },
6158
{ "mfc2", "t,RsRo", MIPS_COP2(0x00), MA_RSP, 0 },
6159
{ "cfc2", "t,gc", MIPS_COP2(0x02), MA_PSX, 0 },
6160
{ "cfc2", "t,Rc", MIPS_COP2(0x02), MA_RSP, 0 },
6161
{ "mtc2", "t,gs", MIPS_COP2(0x04), MA_PSX, 0 },
6162
{ "mtc2", "t,RsRo", MIPS_COP2(0x04), MA_RSP, 0 },
6163
{ "ctc2", "t,gc", MIPS_COP2(0x06), MA_PSX, 0 },
6164
{ "ctc2", "t,Rc", MIPS_COP2(0x06), MA_RSP, 0 },
6165
// VVVVVV VVVVV ttttt -------- C DDDDDDD
6166
{ "mfv", "t,vd", MIPS_COP2(0x03), MA_PSP, MO_VFPU|MO_VFPU_SINGLE },
6167
{ "mfvc", "t,vc", MIPS_COP2(0x03)|0x80, MA_PSP, MO_VFPU },
6168
{ "mtv", "t,vd", MIPS_COP2(0x07), MA_PSP, MO_VFPU|MO_VFPU_SINGLE },
6169
{ "mtvc", "t,vc", MIPS_COP2(0x07)|0x80, MA_PSP, MO_VFPU },
6170
6171
6172
// COP2BC: ? indicates any, * indicates all
6173
// 31---------26----------20-------16------------------------------0
6174
// |= COP2BC| | rt | |
6175
// ------11---------5-----------------------------------------------
6176
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6177
// 00 | BVFx | BVTx | BVFLx | BVTLx | BVFy | BVTy | BVFLy | BVTLy |
6178
// 01 | BVFz | BVTz | BVFLz | BVTLz | BVFw | BVTw | BVFLw | BVTLw |
6179
// 10 | BVF? | BVT? | BVFL? | BVTL? | BVF* | BVT* | BVFL* | BVTL* |
6180
// 11 | --- | --- | --- | --- | --- | --- | --- | --- |
6181
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6182
{ "bvf", "jb,i16", MIPS_COP2BC(0x00), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6183
{ "bvf.B", "i16", MIPS_COP2BC(0x00), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6184
{ "bvt", "jb,i16", MIPS_COP2BC(0x01), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6185
{ "bvt.B", "i16", MIPS_COP2BC(0x01), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6186
{ "bvfl", "jb,i16", MIPS_COP2BC(0x02), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6187
{ "bvfl.B", "i16", MIPS_COP2BC(0x02), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6188
{ "bvtl", "jb,i16", MIPS_COP2BC(0x03), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6189
{ "bvtl.B", "i16", MIPS_COP2BC(0x03), MA_PSP, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
6190
6191
// 31---------26-----23--------------------------------------------0
6192
// |= VFPU0| VOP | |
6193
// ------6--------3-------------------------------------------------
6194
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
6195
// 000 | VADD | VSUB | VSBN | --- | --- | --- | --- | VDIV | 00..07
6196
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6197
{ "vadd.S", "vd,vs,vt", MIPS_VFPU0(0x00), MA_PSP, MO_VFPU },
6198
{ "vsub.S", "vd,vs,vt", MIPS_VFPU0(0x01), MA_PSP, MO_VFPU },
6199
{ "vsbn.S", "vd,vs,vt", MIPS_VFPU0(0x02), MA_PSP, MO_VFPU },
6200
{ "vdiv.S", "vd,vs,vt", MIPS_VFPU0(0x07), MA_PSP, MO_VFPU },
6201
6202
// 31-------26-----23----------------------------------------------0
6203
// |= VFPU1| f | |
6204
// -----6-------3---------------------------------------------------
6205
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
6206
// | VMUL | VDOT | VSCL | --- | VHDP | VDET | VCRS | --- |
6207
// |-------|-------|-------|-------|-------|-------|-------|-------|
6208
{ "vmul.S", "vd,vs,vt", MIPS_VFPU1(0), MA_PSP, MO_VFPU },
6209
{ "vdot.S", "vd,vs,vt", MIPS_VFPU1(1), MA_PSP, MO_VFPU },
6210
{ "vscl.S", "vd,vs,vt", MIPS_VFPU1(2), MA_PSP, MO_VFPU },
6211
{ "vhdp.S", "vd,vs,vt", MIPS_VFPU1(4), MA_PSP, MO_VFPU },
6212
{ "vdet.S", "vd,vs,vt", MIPS_VFPU1(5), MA_PSP, MO_VFPU },
6213
{ "vcrs.S", "vd,vs,vt", MIPS_VFPU1(6), MA_PSP, MO_VFPU },
6214
6215
// 31-------26-----23----------------------------------------------0
6216
// |= VFPU3| f | |
6217
// -----6-------3---------------------------------------------------
6218
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
6219
// | VCMP | --- | VMIN | VMAX | --- | VSCMP | VSGE | VSLT |
6220
// |-------|-------|-------|-------|-------|-------|-------|-------|
6221
// VVVVVV VVV TTTTTTT z SSSSSSS z --- CCCC
6222
{ "vcmp.S", "C,vs,vt", MIPS_VFPU3(0), MA_PSP, MO_VFPU },
6223
{ "vmin.S", "vd,vs,vt", MIPS_VFPU3(2), MA_PSP, MO_VFPU },
6224
{ "vmax.S", "vd,vs,vt", MIPS_VFPU3(3), MA_PSP, MO_VFPU },
6225
{ "vscmp.S", "vd,vs,vt", MIPS_VFPU3(5), MA_PSP, MO_VFPU },
6226
{ "vsge.S", "vd,vs,vt", MIPS_VFPU3(6), MA_PSP, MO_VFPU },
6227
{ "vslt.S", "vd,vs,vt", MIPS_VFPU3(7), MA_PSP, MO_VFPU },
6228
6229
// 31-------26--------------------------------------------5--------0
6230
// |=SPECIAL3| | function|
6231
// -----11----------------------------------------------------6-----
6232
// -----6-------5---------------------------------------------------
6233
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6234
// 000 | EXT | --- | --- | --- | INS | --- | --- | --- |
6235
// 001 | --- | --- | --- | --- | --- | --- | --- | --- |
6236
// 010 | --- | --- | --- | --- | --- | --- | --- | --- |
6237
// 011 | --- | --- | --- | --- | --- | --- | --- | --- |
6238
// 100 |ALLEGRE| --- | --- | --- | --- | --- | --- | --- |
6239
// 101 | --- | --- | --- | --- | --- | --- | --- | --- |
6240
// 110 | --- | --- | --- | --- | --- | --- | --- | --- |
6241
// 110 | --- | --- | --- | --- | --- | --- | --- | --- |
6242
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6243
{ "ext", "t,s,i5,je", MIPS_SPECIAL3(0), MA_PSP, 0 },
6244
{ "ins", "t,s,i5,ji", MIPS_SPECIAL3(4), MA_PSP, 0 },
6245
6246
// 31-------26----------------------------------10--------5--------0
6247
// |=SPECIAL3| | secfunc |ALLEGREX0|
6248
// ------11---------5-------------------------------5---------6-----
6249
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6250
// 00 | --- | --- | WSBH | WSBW | --- | --- | --- | --- |
6251
// 01 | --- | --- | --- | --- | --- | --- | --- | --- |
6252
// 10 | SEB | --- | --- | --- |BITREV | --- | --- | --- |
6253
// 11 | SEH | --- | --- | --- | --- | --- | --- | --- |
6254
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6255
// VVVVVV ----- ttttt ddddd VVVVV VVVVVV
6256
{ "wsbh", "d,t", MIPS_ALLEGREX0(0x02), MA_PSP, 0 },
6257
{ "wsbh", "d", MIPS_ALLEGREX0(0x02), MA_PSP, 0 },
6258
{ "wsbw", "d,t", MIPS_ALLEGREX0(0x03), MA_PSP, 0 },
6259
{ "wsbw", "d", MIPS_ALLEGREX0(0x03), MA_PSP, 0 },
6260
{ "seb", "d,t", MIPS_ALLEGREX0(0x10), MA_PSP, 0 },
6261
{ "seb", "d", MIPS_ALLEGREX0(0x10), MA_PSP, 0 },
6262
{ "bitrev", "d,t", MIPS_ALLEGREX0(0x14), MA_PSP, 0 },
6263
{ "bitrev", "d", MIPS_ALLEGREX0(0x14), MA_PSP, 0 },
6264
{ "seh", "d,t", MIPS_ALLEGREX0(0x18), MA_PSP, 0 },
6265
{ "seh", "d", MIPS_ALLEGREX0(0x18), MA_PSP, 0 },
6266
6267
6268
// VFPU4: This one is a bit messy.
6269
// 31-------26------21---------------------------------------------0
6270
// |= VFPU4| rs | |
6271
// -----6-------5---------------------------------------------------
6272
// hi |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6273
// 00 |VF4-1.1|VF4-1.2|VF4-1.3| VCST | --- | --- | --- | --- |
6274
// 01 | --- | --- | --- | --- | --- | --- | --- | --- |
6275
// 10 | VF2IN | VF2IZ | VF2IU | VF2ID | VI2F | VCMOV | --- | --- |
6276
// 11 | VWBN | VWBN | VWBN | VWBN | VWBN | VWBN | VWBN | VWBN |
6277
// |-------|-------|-------|-------|-------|-------|-------|-------|
6278
// VVVVVV VVVVV iiiii z ------- z DDDDDDD
6279
// Technically these also have names (as the second arg.)
6280
{ "vcst.S", "vd,Wc", MIPS_VFPU4(0x03), MA_PSP, MO_VFPU },
6281
{ "vf2in.S", "vd,vs,i5", MIPS_VFPU4(0x10), MA_PSP, MO_VFPU },
6282
{ "vf2iz.S", "vd,vs,i5", MIPS_VFPU4(0x11), MA_PSP, MO_VFPU },
6283
{ "vf2iu.S", "vd,vs,i5", MIPS_VFPU4(0x12), MA_PSP, MO_VFPU },
6284
{ "vf2id.S", "vd,vs,i5", MIPS_VFPU4(0x13), MA_PSP, MO_VFPU },
6285
{ "vi2f.S", "vd,vs,i5", MIPS_VFPU4(0x14), MA_PSP, MO_VFPU },
6286
{ "vcmovt.S", "vd,vs,i5", MIPS_VFPU4(0x15)|0, MA_PSP, MO_VFPU },
6287
{ "vcmovf.S", "vd,vs,i5", MIPS_VFPU4(0x15)|(1<<19), MA_PSP, MO_VFPU },
6288
{ "vwbn.S", "vd,vs,i5", MIPS_VFPU4(0x18), MA_PSP, MO_VFPU },
6289
6290
// 31-------------21-------16--------------------------------------0
6291
// |= VF4-1.1 | rt | |
6292
// --------11----------5--------------------------------------------
6293
// hi |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6294
// 00 | VMOV | VABS | VNEG | VIDT | vsAT0 | vsAT1 | VZERO | VONE |
6295
// 01 | --- | --- | --- | --- | --- | --- | --- | --- |
6296
// 10 | VRCP | VRSQ | vsIN | VCOS | VEXP2 | VLOG2 | vsQRT | VASIN |
6297
// 11 | VNRCP | --- | VNSIN | --- |VREXP2 | --- | --- | --- |
6298
// |-------|-------|-------|-------|-------|-------|-------|-------|
6299
{ "vmov.S", "vd,vs", MIPS_VFPU4_11(0x00), MA_PSP, MO_VFPU },
6300
{ "vabs.S", "vd,vs", MIPS_VFPU4_11(0x01), MA_PSP, MO_VFPU },
6301
{ "vneg.S", "vd,vs", MIPS_VFPU4_11(0x02), MA_PSP, MO_VFPU },
6302
{ "vidt.S", "vd", MIPS_VFPU4_11(0x03), MA_PSP, MO_VFPU },
6303
{ "vsat0.S", "vd,vs", MIPS_VFPU4_11(0x04), MA_PSP, MO_VFPU },
6304
{ "vsat1.S", "vd,vs", MIPS_VFPU4_11(0x05), MA_PSP, MO_VFPU },
6305
{ "vzero.S", "vd", MIPS_VFPU4_11(0x06), MA_PSP, MO_VFPU },
6306
{ "vone.S", "vd", MIPS_VFPU4_11(0x07), MA_PSP, MO_VFPU },
6307
{ "vrcp.S", "vd,vs", MIPS_VFPU4_11(0x10), MA_PSP, MO_VFPU },
6308
{ "vrsq.S", "vd,vs", MIPS_VFPU4_11(0x11), MA_PSP, MO_VFPU },
6309
{ "vsin.S", "vd,vs", MIPS_VFPU4_11(0x12), MA_PSP, MO_VFPU },
6310
{ "vcos.S", "vd,vs", MIPS_VFPU4_11(0x13), MA_PSP, MO_VFPU },
6311
{ "vexp2.S", "vd,vs", MIPS_VFPU4_11(0x14), MA_PSP, MO_VFPU },
6312
{ "vlog2.S", "vd,vs", MIPS_VFPU4_11(0x15), MA_PSP, MO_VFPU },
6313
{ "vsqrt.S", "vd,vs", MIPS_VFPU4_11(0x16), MA_PSP, MO_VFPU },
6314
{ "vasin.S", "vd,vs", MIPS_VFPU4_11(0x17), MA_PSP, MO_VFPU },
6315
{ "vnrcp.S", "vd,vs", MIPS_VFPU4_11(0x18), MA_PSP, MO_VFPU },
6316
{ "vnsin.S", "vd,vs", MIPS_VFPU4_11(0x1a), MA_PSP, MO_VFPU },
6317
{ "vrexp2.S", "vd,vs", MIPS_VFPU4_11(0x1c), MA_PSP, MO_VFPU },
6318
6319
// VFPU4 1.2: TODO: Unsure where vsBZ goes, no one uses it.
6320
// 31-------------21-------16--------------------------------------0
6321
// |= VF4-1.2 | rt | |
6322
// --------11----------5--------------------------------------------
6323
// hi |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6324
// 00 | VRNDS | VRNDI |VRNDF1 |VRNDF2 | --- | --- | --- | --- |
6325
// 01 | --- | --- | --- | --- | vsBZ? | --- | --- | --- |
6326
// 10 | --- | --- | VF2H | VH2F | --- | --- | vsBZ? | VLGB |
6327
// 11 | VUC2I | VC2I | VUS2I | vs2I | VI2UC | VI2C | VI2US | VI2S |
6328
// |-------|-------|-------|-------|-------|-------|-------|-------|
6329
{ "vrnds.S", "vd", MIPS_VFPU4_12(0x00), MA_PSP, MO_VFPU },
6330
{ "vrndi.S", "vd", MIPS_VFPU4_12(0x01), MA_PSP, MO_VFPU },
6331
{ "vrndf1.S", "vd", MIPS_VFPU4_12(0x02), MA_PSP, MO_VFPU },
6332
{ "vrndf2.S", "vd", MIPS_VFPU4_12(0x03), MA_PSP, MO_VFPU },
6333
// TODO: vsBZ?
6334
{ "vf2h.S", "vd,vs", MIPS_VFPU4_12(0x12), MA_PSP, MO_VFPU },
6335
{ "vh2f.S", "vd,vs", MIPS_VFPU4_12(0x13), MA_PSP, MO_VFPU },
6336
// TODO: vsBZ?
6337
{ "vlgb.S", "vd,vs", MIPS_VFPU4_12(0x17), MA_PSP, MO_VFPU },
6338
{ "vuc2i.S", "vd,vs", MIPS_VFPU4_12(0x18), MA_PSP, MO_VFPU },
6339
{ "vc2i.S", "vd,vs", MIPS_VFPU4_12(0x19), MA_PSP, MO_VFPU },
6340
{ "vus2i.S", "vd,vs", MIPS_VFPU4_12(0x1a), MA_PSP, MO_VFPU },
6341
{ "vs2i.S", "vd,vs", MIPS_VFPU4_12(0x1b), MA_PSP, MO_VFPU },
6342
{ "vi2uc.S", "vd,vs", MIPS_VFPU4_12(0x1c), MA_PSP, MO_VFPU },
6343
{ "vi2c.S", "vd,vs", MIPS_VFPU4_12(0x1d), MA_PSP, MO_VFPU },
6344
{ "vi2us.S", "vd,vs", MIPS_VFPU4_12(0x1e), MA_PSP, MO_VFPU },
6345
{ "vi2s.S", "vd,vs", MIPS_VFPU4_12(0x1f), MA_PSP, MO_VFPU },
6346
6347
// 31--------------21------16--------------------------------------0
6348
// |= VF4-1.3 | rt | |
6349
// --------11----------5--------------------------------------------
6350
// hi |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6351
// 00 | vsRT1 | vsRT2 | VBFY1 | VBFY2 | VOCP | vsOCP | VFAD | VAVG |
6352
// 01 | vsRT3 | vsRT4 | vsGN | --- | --- | --- | --- | --- |
6353
// 10 | VMFVC | VMTVC | --- | --- | --- | --- | --- | --- |
6354
// 11 | --- |VT4444 |VT5551 |VT5650 | --- | --- | --- | --- |
6355
// |-------|-------|-------|-------|-------|-------|-------|-------|
6356
{ "vsrt1.S", "vd,vs", MIPS_VFPU4_13(0x00), MA_PSP, MO_VFPU },
6357
{ "vsrt2.S", "vd,vs", MIPS_VFPU4_13(0x01), MA_PSP, MO_VFPU },
6358
{ "vbfy1.S", "vd,vs", MIPS_VFPU4_13(0x02), MA_PSP, MO_VFPU },
6359
{ "vbfy2.S", "vd,vs", MIPS_VFPU4_13(0x03), MA_PSP, MO_VFPU },
6360
{ "vocp.S", "vd,vs", MIPS_VFPU4_13(0x04), MA_PSP, MO_VFPU },
6361
{ "vsocp.S", "vd,vs", MIPS_VFPU4_13(0x05), MA_PSP, MO_VFPU },
6362
{ "vfad.S", "vd,vs", MIPS_VFPU4_13(0x06), MA_PSP, MO_VFPU },
6363
{ "vavg.S", "vd,vs", MIPS_VFPU4_13(0x07), MA_PSP, MO_VFPU },
6364
{ "vsrt3.S", "vd,vs", MIPS_VFPU4_13(0x08), MA_PSP, MO_VFPU },
6365
{ "vsrt4.S", "vd,vs", MIPS_VFPU4_13(0x09), MA_PSP, MO_VFPU },
6366
{ "vsgn.S", "vd,vs", MIPS_VFPU4_13(0x0a), MA_PSP, MO_VFPU },
6367
{ "vmfv.S", "vs,i7", MIPS_VFPU4_13(0x10)|0x00, MA_PSP, MO_VFPU },
6368
{ "vmtv.S", "vs,i7", MIPS_VFPU4_13(0x11)|0x00, MA_PSP, MO_VFPU },
6369
{ "vmfvc.S", "vs,i7", MIPS_VFPU4_13(0x10)|0x80, MA_PSP, MO_VFPU },
6370
{ "vmtvc.S", "vs,i7", MIPS_VFPU4_13(0x11)|0x80, MA_PSP, MO_VFPU },
6371
{ "vt4444.S", "vd,vs", MIPS_VFPU4_13(0x19), MA_PSP, MO_VFPU },
6372
{ "vt5551.S", "vd,vs", MIPS_VFPU4_13(0x1a), MA_PSP, MO_VFPU },
6373
{ "vt5650.S", "vd,vs", MIPS_VFPU4_13(0x1b), MA_PSP, MO_VFPU },
6374
6375
// 31-------26-----23----------------------------------------------0
6376
// |= VFPU5| f | |
6377
// -----6-------3---------------------------------------------------
6378
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6379
// | VPFXS | VPFXS | VPFXT | VPFXT | VPFXD | VPFXD | VIIM | VFIM |
6380
// |-------|-------|-------|-------|-------|-------|-------|-------|
6381
{ "vpfxs", "Ws", MIPS_VFPU5(0), MA_PSP, 0 },
6382
{ "vpfxt", "Ws", MIPS_VFPU5(2), MA_PSP, 0 },
6383
{ "vpfxd", "Wd", MIPS_VFPU5(4), MA_PSP, 0 },
6384
{ "viim.s", "vt,i16", MIPS_VFPU5(6), MA_PSP, MO_VFPU_SINGLE },
6385
{ "vfim.s", "vt,ih", MIPS_VFPU5(7), MA_PSP, MO_VFPU_SINGLE },
6386
6387
// 31-------26-----23----------------------------------------------0
6388
// |= VFPU6| f | |
6389
// -----6-------3---------------------------------------------------
6390
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6391
// | VMMUL | V(H)TFM2/3/4 | VMSCL | *1 | --- |VF6-1.1|
6392
// |-------|-------|-------|-------|-------|-------|-------|-------|
6393
// *1: vcrsp.t/vqmul.q
6394
{ "vmmul.S", "md,ms,mt", MIPS_VFPU6(0), MA_PSP, MO_VFPU|MO_TRANSPOSE_VS },
6395
{ "vtfm2.p", "vd,ms,vt", MIPS_VFPU6(1)|MIPS_VFPUSIZE(1), MA_PSP, MO_VFPU|MO_VFPU_PAIR },
6396
{ "vhtfm2.p", "vd,ms,vt", MIPS_VFPU6(2)|MIPS_VFPUSIZE(1), MA_PSP, MO_VFPU|MO_VFPU_PAIR },
6397
{ "vtfm3.t", "vd,ms,vt", MIPS_VFPU6(2)|MIPS_VFPUSIZE(2), MA_PSP, MO_VFPU|MO_VFPU_TRIPLE },
6398
{ "vhtfm3.t", "vd,ms,vt", MIPS_VFPU6(3)|MIPS_VFPUSIZE(2), MA_PSP, MO_VFPU|MO_VFPU_TRIPLE },
6399
{ "vtfm4.q", "vd,ms,vt", MIPS_VFPU6(3)|MIPS_VFPUSIZE(3), MA_PSP, MO_VFPU|MO_VFPU_QUAD },
6400
{ "vmscl.S", "md,ms,vSt", MIPS_VFPU6(4), MA_PSP, MO_VFPU },
6401
{ "vcrsp.t", "vd,vs,vt", MIPS_VFPU6(5)|MIPS_VFPUSIZE(2), MA_PSP, MO_VFPU|MO_VFPU_TRIPLE },
6402
{ "vqmul.q", "vd,vs,vt", MIPS_VFPU6(5)|MIPS_VFPUSIZE(3), MA_PSP, MO_VFPU|MO_VFPU_QUAD },
6403
6404
// 31--------23----20----------------------------------------------0
6405
// |= VF6-1.1 | f | |
6406
// -----9-------3---------------------------------------------------
6407
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6408
// |VF6-1.2| --- | VROT | --- | --- | --- | --- |
6409
// |-------|-------|-------|-------|-------|-------|-------|-------|
6410
// VVVVVVVVVVV iiiii z SSSSSSS z DDDDDDD
6411
{ "vrot.S", "vd,vSs,Wr", MIPS_VFPU6_1VROT(), MA_PSP, MO_VFPU },
6412
6413
// 31--------20----16----------------------------------------------0
6414
// |= VF6-1.2 | f | |
6415
// -----6-------4---------------------------------------------------
6416
// hi |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6417
// 0 | VMMOV | --- | --- | VMIDT | --- | --- |VMZERO | VMONE |
6418
// 1 | --- | --- | --- | --- | --- | --- | --- | --- |
6419
// |-------|-------|-------|-------|-------|-------|-------|-------|
6420
// VVVVVVVVVVVVVVVV z SSSSSSS z DDDDDDD
6421
{ "vmmov.S", "md,ms", MIPS_VFPU6_2(0), MA_PSP, MO_VFPU },
6422
// VVVVVVVVVVVVVVVV z ------- z DDDDDDD
6423
{ "vmidt.S", "md", MIPS_VFPU6_2(3), MA_PSP, MO_VFPU },
6424
{ "vmzero.S", "md", MIPS_VFPU6_2(6), MA_PSP, MO_VFPU },
6425
{ "vmone.S", "md", MIPS_VFPU6_2(7), MA_PSP, MO_VFPU },
6426
6427
// 31---------26------------------------------------------5--------0
6428
// |= RSP| | function|
6429
// ------6----------------------------------------------------6-----
6430
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6431
// 000 | VMULF | VMULU | VRNDP | VMULQ | VMUDL | VMUDM | VMUDN | VMUDH | 00..07
6432
// 001 | VMACF | VMACU | VRNDN | VMACQ | VMADL | VMADH | VMADN | VMADH | 08..0F
6433
// 010 | VADD | VSUB | VSUT | VABS | VADDC | VSUBC | VADDB | VSUBB | 10..17
6434
// 011 | VACCB | VSUCB | VSAD | VSAC | VSUM | VSAR | VACC | VSUC | 18..1F
6435
// 100 | VLT | VEQ | VNE | VGE | VCL | VCH | VCR | VMRG | 20..27
6436
// 101 | VAND | VNAND | VOR | VNOR | VXOR | VNXOR | --- | --- | 28..2F
6437
// 110 | VRCP | VRCPL | VRCPH | VMOV | VRSQ | VRSQL | VRSQH | VNOP | 30..37
6438
// 111 | VEXTT | VEXTQ | VEXTN | --- | VINST | VINSQ | VINSN | VNULL | 38..3F
6439
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6440
{ "vmulf", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x00), MA_RSP, 0 },
6441
{ "vmulf", "Rs,RtRe", MIPS_RSP_COP2(0x00), MA_RSP, MO_RSPVRSD },
6442
{ "vmulu", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x01), MA_RSP, 0 },
6443
{ "vmulu", "Rs,RtRe", MIPS_RSP_COP2(0x01), MA_RSP, MO_RSPVRSD },
6444
{ "vrndp", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x02), MA_RSP, 0 },
6445
{ "vrndp", "Rs,RtRe", MIPS_RSP_COP2(0x02), MA_RSP, MO_RSPVRSD },
6446
{ "vmulq", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x03), MA_RSP, 0 },
6447
{ "vmulq", "Rs,RtRe", MIPS_RSP_COP2(0x03), MA_RSP, MO_RSPVRSD },
6448
{ "vmudl", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x04), MA_RSP, 0 },
6449
{ "vmudl", "Rs,RtRe", MIPS_RSP_COP2(0x04), MA_RSP, MO_RSPVRSD },
6450
{ "vmudm", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x05), MA_RSP, 0 },
6451
{ "vmudm", "Rs,RtRe", MIPS_RSP_COP2(0x05), MA_RSP, MO_RSPVRSD },
6452
{ "vmudn", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x06), MA_RSP, 0 },
6453
{ "vmudn", "Rs,RtRe", MIPS_RSP_COP2(0x06), MA_RSP, MO_RSPVRSD },
6454
{ "vmudh", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x07), MA_RSP, 0 },
6455
{ "vmudh", "Rs,RtRe", MIPS_RSP_COP2(0x07), MA_RSP, MO_RSPVRSD },
6456
{ "vmacf", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x08), MA_RSP, 0 },
6457
{ "vmacf", "Rs,RtRe", MIPS_RSP_COP2(0x08), MA_RSP, MO_RSPVRSD },
6458
{ "vmacu", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x09), MA_RSP, 0 },
6459
{ "vmacu", "Rs,RtRe", MIPS_RSP_COP2(0x09), MA_RSP, MO_RSPVRSD },
6460
{ "vrndn", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x0a), MA_RSP, 0 },
6461
{ "vrndn", "Rs,RtRe", MIPS_RSP_COP2(0x0a), MA_RSP, MO_RSPVRSD },
6462
{ "vmacq", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x0b), MA_RSP, 0 },
6463
{ "vmacq", "Rs,RtRe", MIPS_RSP_COP2(0x0b), MA_RSP, MO_RSPVRSD },
6464
{ "vmadl", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x0c), MA_RSP, 0 },
6465
{ "vmadl", "Rs,RtRe", MIPS_RSP_COP2(0x0c), MA_RSP, MO_RSPVRSD },
6466
{ "vmadm", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x0d), MA_RSP, 0 },
6467
{ "vmadm", "Rs,RtRe", MIPS_RSP_COP2(0x0d), MA_RSP, MO_RSPVRSD },
6468
{ "vmadn", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x0e), MA_RSP, 0 },
6469
{ "vmadn", "Rs,RtRe", MIPS_RSP_COP2(0x0e), MA_RSP, MO_RSPVRSD },
6470
{ "vmadh", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x0f), MA_RSP, 0 },
6471
{ "vmadh", "Rs,RtRe", MIPS_RSP_COP2(0x0f), MA_RSP, MO_RSPVRSD },
6472
{ "vadd", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x10), MA_RSP, 0 },
6473
{ "vadd", "Rs,RtRe", MIPS_RSP_COP2(0x10), MA_RSP, MO_RSPVRSD },
6474
{ "vsub", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x11), MA_RSP, 0 },
6475
{ "vsub", "Rs,RtRe", MIPS_RSP_COP2(0x11), MA_RSP, MO_RSPVRSD },
6476
{ "vsut", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x12), MA_RSP, 0 },
6477
{ "vsut", "Rs,RtRe", MIPS_RSP_COP2(0x12), MA_RSP, MO_RSPVRSD },
6478
{ "vabs", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x13), MA_RSP, 0 },
6479
{ "vabs", "Rs,RtRe", MIPS_RSP_COP2(0x13), MA_RSP, MO_RSPVRSD },
6480
{ "vaddc", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x14), MA_RSP, 0 },
6481
{ "vaddc", "Rs,RtRe", MIPS_RSP_COP2(0x14), MA_RSP, MO_RSPVRSD },
6482
{ "vsubc", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x15), MA_RSP, 0 },
6483
{ "vsubc", "Rs,RtRe", MIPS_RSP_COP2(0x15), MA_RSP, MO_RSPVRSD },
6484
{ "vaddb", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x16), MA_RSP, 0 },
6485
{ "vaddb", "Rs,RtRe", MIPS_RSP_COP2(0x16), MA_RSP, MO_RSPVRSD },
6486
{ "vsubb", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x17), MA_RSP, 0 },
6487
{ "vsubb", "Rs,RtRe", MIPS_RSP_COP2(0x17), MA_RSP, MO_RSPVRSD },
6488
{ "vaccb", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x18), MA_RSP, 0 },
6489
{ "vaccb", "Rs,RtRe", MIPS_RSP_COP2(0x18), MA_RSP, MO_RSPVRSD },
6490
{ "vsucb", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x19), MA_RSP, 0 },
6491
{ "vsucb", "Rs,RtRe", MIPS_RSP_COP2(0x19), MA_RSP, MO_RSPVRSD },
6492
{ "vsad", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x1a), MA_RSP, 0 },
6493
{ "vsad", "Rs,RtRe", MIPS_RSP_COP2(0x1a), MA_RSP, MO_RSPVRSD },
6494
{ "vsac", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x1b), MA_RSP, 0 },
6495
{ "vsac", "Rs,RtRe", MIPS_RSP_COP2(0x1b), MA_RSP, MO_RSPVRSD },
6496
{ "vsum", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x1c), MA_RSP, 0 },
6497
{ "vsum", "Rs,RtRe", MIPS_RSP_COP2(0x1c), MA_RSP, MO_RSPVRSD },
6498
{ "vsar", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x1d), MA_RSP, 0 },
6499
{ "vsar", "Rs,RtRe", MIPS_RSP_COP2(0x1d), MA_RSP, MO_RSPVRSD },
6500
{ "vacc", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x1e), MA_RSP, 0 },
6501
{ "vacc", "Rs,RtRe", MIPS_RSP_COP2(0x1e), MA_RSP, MO_RSPVRSD },
6502
{ "vsuc", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x1f), MA_RSP, 0 },
6503
{ "vsuc", "Rs,RtRe", MIPS_RSP_COP2(0x1f), MA_RSP, MO_RSPVRSD },
6504
{ "vlt", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x20), MA_RSP, 0 },
6505
{ "vlt", "Rs,RtRe", MIPS_RSP_COP2(0x20), MA_RSP, MO_RSPVRSD },
6506
{ "veq", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x21), MA_RSP, 0 },
6507
{ "veq", "Rs,RtRe", MIPS_RSP_COP2(0x21), MA_RSP, MO_RSPVRSD },
6508
{ "vne", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x22), MA_RSP, 0 },
6509
{ "vne", "Rs,RtRe", MIPS_RSP_COP2(0x22), MA_RSP, MO_RSPVRSD },
6510
{ "vge", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x23), MA_RSP, 0 },
6511
{ "vge", "Rs,RtRe", MIPS_RSP_COP2(0x23), MA_RSP, MO_RSPVRSD },
6512
{ "vcl", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x24), MA_RSP, 0 },
6513
{ "vcl", "Rs,RtRe", MIPS_RSP_COP2(0x24), MA_RSP, MO_RSPVRSD },
6514
{ "vch", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x25), MA_RSP, 0 },
6515
{ "vch", "Rs,RtRe", MIPS_RSP_COP2(0x25), MA_RSP, MO_RSPVRSD },
6516
{ "vcr", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x26), MA_RSP, 0 },
6517
{ "vcr", "Rs,RtRe", MIPS_RSP_COP2(0x26), MA_RSP, MO_RSPVRSD },
6518
{ "vmrg", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x27), MA_RSP, 0 },
6519
{ "vmrg", "Rs,RtRe", MIPS_RSP_COP2(0x27), MA_RSP, MO_RSPVRSD },
6520
{ "vand", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x28), MA_RSP, 0 },
6521
{ "vand", "Rs,RtRe", MIPS_RSP_COP2(0x28), MA_RSP, MO_RSPVRSD },
6522
{ "vnand", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x29), MA_RSP, 0 },
6523
{ "vnand", "Rs,RtRe", MIPS_RSP_COP2(0x29), MA_RSP, MO_RSPVRSD },
6524
{ "vor", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x2a), MA_RSP, 0 },
6525
{ "vor", "Rs,RtRe", MIPS_RSP_COP2(0x2a), MA_RSP, MO_RSPVRSD },
6526
{ "vnor", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x2b), MA_RSP, 0 },
6527
{ "vnor", "Rs,RtRe", MIPS_RSP_COP2(0x2b), MA_RSP, MO_RSPVRSD },
6528
{ "vxor", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x2c), MA_RSP, 0 },
6529
{ "vxor", "Rs,RtRe", MIPS_RSP_COP2(0x2c), MA_RSP, MO_RSPVRSD },
6530
{ "vnxor", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x2d), MA_RSP, 0 },
6531
{ "vnxor", "Rs,RtRe", MIPS_RSP_COP2(0x2d), MA_RSP, MO_RSPVRSD },
6532
{ "vrcp", "RdRm,RtRl", MIPS_RSP_COP2(0x30), MA_RSP, 0 },
6533
{ "vrcpl", "RdRm,RtRl", MIPS_RSP_COP2(0x31), MA_RSP, 0 },
6534
{ "vrcph", "RdRm,RtRl", MIPS_RSP_COP2(0x32), MA_RSP, 0 },
6535
{ "vmov", "RdRm,RtRl", MIPS_RSP_COP2(0x33), MA_RSP, 0 },
6536
{ "vrsq", "RdRm,RtRl", MIPS_RSP_COP2(0x34), MA_RSP, 0 },
6537
{ "vrsql", "RdRm,RtRl", MIPS_RSP_COP2(0x35), MA_RSP, 0 },
6538
{ "vrsqh", "RdRm,RtRl", MIPS_RSP_COP2(0x36), MA_RSP, 0 },
6539
{ "vnop", "", MIPS_RSP_COP2(0x37), MA_RSP, 0 },
6540
{ "vextt", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x38), MA_RSP, 0 },
6541
{ "vextt", "Rs,RtRe", MIPS_RSP_COP2(0x38), MA_RSP, MO_RSPVRSD },
6542
{ "vextq", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x39), MA_RSP, 0 },
6543
{ "vextq", "Rs,RtRe", MIPS_RSP_COP2(0x39), MA_RSP, MO_RSPVRSD },
6544
{ "vextn", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x3a), MA_RSP, 0 },
6545
{ "vextn", "Rs,RtRe", MIPS_RSP_COP2(0x3a), MA_RSP, MO_RSPVRSD },
6546
{ "vinst", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x3c), MA_RSP, 0 },
6547
{ "vinst", "Rs,RtRe", MIPS_RSP_COP2(0x3c), MA_RSP, MO_RSPVRSD },
6548
{ "vinsq", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x3d), MA_RSP, 0 },
6549
{ "vinsq", "Rs,RtRe", MIPS_RSP_COP2(0x3d), MA_RSP, MO_RSPVRSD },
6550
{ "vinsn", "Rd,Rs,RtRe", MIPS_RSP_COP2(0x3e), MA_RSP, 0 },
6551
{ "vinsn", "Rs,RtRe", MIPS_RSP_COP2(0x3e), MA_RSP, MO_RSPVRSD },
6552
{ "vnull", "", MIPS_RSP_COP2(0x3f), MA_RSP, 0 },
6553
6554
// 31---------26--------------------15-------11--------------------0
6555
// |= LWC2| | rd | |
6556
// -----6----------------------5------------------------------------
6557
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6558
// 00 | LBV | LSV | LLV | LDV | LQV | LRV | LPV | LUV | 00..07
6559
// 01 | LHV | LFV | LWV | LTV | --- | --- | --- | --- | 08..0F
6560
// 10 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
6561
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
6562
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6563
{"lbv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x00), MA_RSP, 0 },
6564
{"lbv", "RtRo,(s)", MIPS_RSP_LWC2(0x00), MA_RSP, 0 },
6565
{"lsv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x01), MA_RSP, MO_RSP_HWOFFSET },
6566
{"lsv", "RtRo,(s)", MIPS_RSP_LWC2(0x01), MA_RSP, MO_RSP_HWOFFSET },
6567
{"llv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x02), MA_RSP, MO_RSP_WOFFSET },
6568
{"llv", "RtRo,(s)", MIPS_RSP_LWC2(0x02), MA_RSP, MO_RSP_WOFFSET },
6569
{"ldv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x03), MA_RSP, MO_RSP_DWOFFSET },
6570
{"ldv", "RtRo,(s)", MIPS_RSP_LWC2(0x03), MA_RSP, MO_RSP_DWOFFSET },
6571
{"lqv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x04), MA_RSP, MO_RSP_QWOFFSET },
6572
{"lqv", "RtRo,(s)", MIPS_RSP_LWC2(0x04), MA_RSP, MO_RSP_QWOFFSET },
6573
{"lrv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x05), MA_RSP, MO_RSP_QWOFFSET },
6574
{"lrv", "RtRo,(s)", MIPS_RSP_LWC2(0x05), MA_RSP, MO_RSP_QWOFFSET },
6575
{"lpv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x06), MA_RSP, MO_RSP_DWOFFSET },
6576
{"lpv", "RtRo,(s)", MIPS_RSP_LWC2(0x06), MA_RSP, MO_RSP_DWOFFSET },
6577
{"luv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x07), MA_RSP, MO_RSP_DWOFFSET },
6578
{"luv", "RtRo,(s)", MIPS_RSP_LWC2(0x07), MA_RSP, MO_RSP_DWOFFSET },
6579
{"lhv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x08), MA_RSP, MO_RSP_QWOFFSET },
6580
{"lhv", "RtRo,(s)", MIPS_RSP_LWC2(0x08), MA_RSP, MO_RSP_QWOFFSET },
6581
{"lfv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x09), MA_RSP, MO_RSP_QWOFFSET },
6582
{"lfv", "RtRo,(s)", MIPS_RSP_LWC2(0x09), MA_RSP, MO_RSP_QWOFFSET },
6583
{"lwv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x0a), MA_RSP, MO_RSP_QWOFFSET },
6584
{"lwv", "RtRo,(s)", MIPS_RSP_LWC2(0x0a), MA_RSP, MO_RSP_QWOFFSET },
6585
{"ltv", "RtRo,i7(s)", MIPS_RSP_LWC2(0x0b), MA_RSP, MO_RSP_QWOFFSET },
6586
{"ltv", "RtRo,(s)", MIPS_RSP_LWC2(0x0b), MA_RSP, MO_RSP_QWOFFSET },
6587
6588
// 31---------26--------------------15-------11--------------------0
6589
// |= SWC2| | rd | |
6590
// -----6----------------------5------------------------------------
6591
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
6592
// 00 | SBV | SSV | SLV | SDV | SQV | SRV | SPV | SUV | 00..07
6593
// 01 | SHV | SFV | SWV | STV | --- | --- | --- | --- | 08..0F
6594
// 10 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
6595
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
6596
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
6597
{"sbv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x00), MA_RSP, 0 },
6598
{"sbv", "RtRo,(s)", MIPS_RSP_SWC2(0x00), MA_RSP, 0 },
6599
{"ssv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x01), MA_RSP, MO_RSP_HWOFFSET },
6600
{"ssv", "RtRo,(s)", MIPS_RSP_SWC2(0x01), MA_RSP, MO_RSP_HWOFFSET },
6601
{"slv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x02), MA_RSP, MO_RSP_WOFFSET },
6602
{"slv", "RtRo,(s)", MIPS_RSP_SWC2(0x02), MA_RSP, MO_RSP_WOFFSET },
6603
{"sdv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x03), MA_RSP, MO_RSP_DWOFFSET },
6604
{"sdv", "RtRo,(s)", MIPS_RSP_SWC2(0x03), MA_RSP, MO_RSP_DWOFFSET },
6605
{"sqv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x04), MA_RSP, MO_RSP_QWOFFSET },
6606
{"sqv", "RtRo,(s)", MIPS_RSP_SWC2(0x04), MA_RSP, MO_RSP_QWOFFSET },
6607
{"srv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x05), MA_RSP, MO_RSP_QWOFFSET },
6608
{"srv", "RtRo,(s)", MIPS_RSP_SWC2(0x05), MA_RSP, MO_RSP_QWOFFSET },
6609
{"spv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x06), MA_RSP, MO_RSP_DWOFFSET },
6610
{"spv", "RtRo,(s)", MIPS_RSP_SWC2(0x06), MA_RSP, MO_RSP_DWOFFSET },
6611
{"suv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x07), MA_RSP, MO_RSP_DWOFFSET },
6612
{"suv", "RtRo,(s)", MIPS_RSP_SWC2(0x07), MA_RSP, MO_RSP_DWOFFSET },
6613
{"shv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x08), MA_RSP, MO_RSP_QWOFFSET },
6614
{"shv", "RtRo,(s)", MIPS_RSP_SWC2(0x08), MA_RSP, MO_RSP_QWOFFSET },
6615
{"sfv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x09), MA_RSP, MO_RSP_QWOFFSET },
6616
{"sfv", "RtRo,(s)", MIPS_RSP_SWC2(0x09), MA_RSP, MO_RSP_QWOFFSET },
6617
{"swv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x0a), MA_RSP, MO_RSP_QWOFFSET },
6618
{"swv", "RtRo,(s)", MIPS_RSP_SWC2(0x0a), MA_RSP, MO_RSP_QWOFFSET },
6619
{"stv", "RtRo,i7(s)", MIPS_RSP_SWC2(0x0b), MA_RSP, MO_RSP_QWOFFSET },
6620
{"stv", "RtRo,(s)", MIPS_RSP_SWC2(0x0b), MA_RSP, MO_RSP_QWOFFSET },
6621
// END
6622
{ nullptr, nullptr, 0, 0, 0 },
6623
};
6624
6625
const MipsArchDefinition mipsArchs[] = {
6626
// MARCH_PSX
6627
{ "PSX", MA_MIPS1|MA_PSX, MA_EXPSX, 0 },
6628
// MARCH_N64
6629
{ "N64", MA_MIPS1|MA_MIPS2|MA_MIPS3, MA_EXN64, MO_64BIT|MO_FPU|MO_DFPU },
6630
// MARCH_PS2
6631
{ "PS2", MA_MIPS1|MA_MIPS2|MA_MIPS3|MA_PS2, MA_EXPS2, MO_64BIT|MO_FPU },
6632
// MARCH_PSP
6633
{ "PSP", MA_MIPS1|MA_MIPS2|MA_MIPS3|MA_PSP, MA_EXPSP, MO_FPU },
6634
// MARCH_RSP
6635
{ "RSP", MA_MIPS1|MA_RSP, MA_EXRSP, 0 },
6636
// MARCH_INVALID
6637
{ "Invalid", 0, 0, 0 },
6638
};
6639
6640
// file: Parser/ExpressionParser.h
6641
6642
Expression parseExpression(Tokenizer& tokenizer, bool inUnknownOrFalseBlock);
6643
void allowFunctionCallExpression(bool allow);
6644
6645
// file: Archs/MIPS/PsxRelocator.h
6646
6647
enum class PsxRelocationType { WordLiteral, UpperImmediate, LowerImmediate, FunctionCall };
6648
enum class PsxRelocationRefType { SymblId, SegmentOffset };
6649
6650
struct PsxRelocation
6651
{
6652
PsxRelocationType type;
6653
PsxRelocationRefType refType;
6654
int segmentOffset;
6655
int referenceId;
6656
int referencePos;
6657
int relativeOffset;
6658
int filePos;
6659
};
6660
6661
struct PsxSegment
6662
{
6663
std::wstring name;
6664
int id;
6665
ByteArray data;
6666
std::vector<PsxRelocation> relocations;
6667
};
6668
6669
6670
enum class PsxSymbolType { Internal, InternalID, External, BSS, Function };
6671
6672
struct PsxSymbol
6673
{
6674
PsxSymbolType type;
6675
std::wstring name;
6676
int segment;
6677
int offset;
6678
int id;
6679
int size;
6680
std::shared_ptr<Label> label;
6681
};
6682
6683
struct PsxRelocatorFile
6684
{
6685
std::wstring name;
6686
std::vector<PsxSegment> segments;
6687
std::vector<PsxSymbol> symbols;
6688
};
6689
6690
class PsxRelocator
6691
{
6692
public:
6693
bool init(const std::wstring& inputName);
6694
bool relocate(int& memoryAddress);
6695
bool hasDataChanged() { return dataChanged; };
6696
const ByteArray& getData() const { return outputData; };
6697
void writeSymbols(SymbolData& symData) const;
6698
private:
6699
size_t loadString(ByteArray& data, size_t pos, std::wstring& dest);
6700
bool parseObject(ByteArray data, PsxRelocatorFile& dest);
6701
bool relocateFile(PsxRelocatorFile& file, int& relocationAddress);
6702
6703
ByteArray outputData;
6704
std::vector<PsxRelocatorFile> files;
6705
MipsElfRelocator* reloc;
6706
bool dataChanged;
6707
};
6708
6709
class DirectivePsxObjImport: public CAssemblerCommand
6710
{
6711
public:
6712
DirectivePsxObjImport(const std::wstring& fileName);
6713
~DirectivePsxObjImport() { };
6714
virtual bool Validate();
6715
virtual void Encode() const;
6716
virtual void writeTempData(TempData& tempData) const { };
6717
virtual void writeSymData(SymbolData& symData) const;
6718
private:
6719
PsxRelocator rel;
6720
};
6721
6722
// file: Commands/CDirectiveFile.h
6723
6724
class GenericAssemblerFile;
6725
6726
class CDirectiveFile: public CAssemblerCommand
6727
{
6728
public:
6729
enum class Type { Invalid, Open, Create, Copy, Close };
6730
6731
CDirectiveFile();
6732
void initOpen(const std::wstring& fileName, int64_t memory);
6733
void initCreate(const std::wstring& fileName, int64_t memory);
6734
void initCopy(const std::wstring& inputName, const std::wstring& outputName, int64_t memory);
6735
void initClose();
6736
6737
virtual bool Validate();
6738
virtual void Encode() const;
6739
virtual void writeTempData(TempData& tempData) const;
6740
virtual void writeSymData(SymbolData& symData) const;
6741
private:
6742
Type type;
6743
int64_t virtualAddress;
6744
std::shared_ptr<GenericAssemblerFile> file;
6745
std::shared_ptr<AssemblerFile> closeFile;
6746
};
6747
6748
class CDirectivePosition: public CAssemblerCommand
6749
{
6750
public:
6751
enum Type { Physical, Virtual };
6752
CDirectivePosition(Expression value, Type type);
6753
virtual bool Validate();
6754
virtual void Encode() const;
6755
virtual void writeTempData(TempData& tempData) const;
6756
virtual void writeSymData(SymbolData& symData) const { };
6757
private:
6758
void exec() const;
6759
Expression expression;
6760
Type type;
6761
int64_t position;
6762
int64_t virtualAddress;
6763
};
6764
6765
class CDirectiveIncbin: public CAssemblerCommand
6766
{
6767
public:
6768
CDirectiveIncbin(const std::wstring& fileName);
6769
void setStart(Expression& exp) { startExpression = exp; };
6770
void setSize(Expression& exp) { sizeExpression = exp; };
6771
6772
virtual bool Validate();
6773
virtual void Encode() const;
6774
virtual void writeTempData(TempData& tempData) const;
6775
virtual void writeSymData(SymbolData& symData) const;
6776
private:
6777
std::wstring fileName;
6778
int64_t fileSize;
6779
6780
Expression startExpression;
6781
Expression sizeExpression;
6782
int64_t size;
6783
int64_t start;
6784
int64_t virtualAddress;
6785
};
6786
6787
class CDirectiveAlignFill: public CAssemblerCommand
6788
{
6789
public:
6790
enum Mode { AlignPhysical, AlignVirtual, Fill };
6791
6792
CDirectiveAlignFill(int64_t value, Mode mode);
6793
CDirectiveAlignFill(Expression& value, Mode mode);
6794
CDirectiveAlignFill(Expression& value, Expression& fillValue, Mode mode);
6795
virtual bool Validate();
6796
virtual void Encode() const;
6797
virtual void writeTempData(TempData& tempData) const;
6798
virtual void writeSymData(SymbolData& symData) const;
6799
private:
6800
Mode mode;
6801
Expression valueExpression;
6802
Expression fillExpression;
6803
int64_t value;
6804
int64_t finalSize;
6805
int8_t fillByte;
6806
int64_t virtualAddress;
6807
};
6808
6809
class CDirectiveSkip: public CAssemblerCommand
6810
{
6811
public:
6812
CDirectiveSkip(Expression& value);
6813
virtual bool Validate();
6814
virtual void Encode() const;
6815
virtual void writeTempData(TempData& tempData) const;
6816
virtual void writeSymData(SymbolData& symData) const { };
6817
private:
6818
Expression expression;
6819
int64_t value;
6820
int64_t virtualAddress;
6821
};
6822
6823
class CDirectiveHeaderSize: public CAssemblerCommand
6824
{
6825
public:
6826
CDirectiveHeaderSize(Expression expression);
6827
virtual bool Validate();
6828
virtual void Encode() const;
6829
virtual void writeTempData(TempData& tempData) const;
6830
virtual void writeSymData(SymbolData& symData) const { };
6831
private:
6832
void exec() const;
6833
Expression expression;
6834
int64_t headerSize;
6835
int64_t virtualAddress;
6836
};
6837
6838
class DirectiveObjImport: public CAssemblerCommand
6839
{
6840
public:
6841
DirectiveObjImport(const std::wstring& inputName);
6842
DirectiveObjImport(const std::wstring& inputName, const std::wstring& ctorName);
6843
~DirectiveObjImport() { };
6844
virtual bool Validate();
6845
virtual void Encode() const;
6846
virtual void writeTempData(TempData& tempData) const;
6847
virtual void writeSymData(SymbolData& symData) const;
6848
private:
6849
ElfRelocator rel;
6850
std::unique_ptr<CAssemblerCommand> ctor;
6851
};
6852
6853
// file: Archs/MIPS/MipsParser.cpp
6854
6855
#define CHECK(exp) if (!(exp)) return false;
6856
6857
const MipsRegisterDescriptor mipsRegisters[] = {
6858
{ L"r0", 0 }, { L"zero", 0}, { L"at", 1 }, { L"r1", 1 },
6859
{ L"v0", 2 }, { L"r2", 2 }, { L"v1", 3 }, { L"r3", 3 },
6860
{ L"a0", 4 }, { L"r4", 4 }, { L"a1", 5 }, { L"r5", 5 },
6861
{ L"a2", 6 }, { L"r6", 6 }, { L"a3", 7 }, { L"r7", 7 },
6862
{ L"t0", 8 }, { L"r8", 8 }, { L"t1", 9 }, { L"r9", 9 },
6863
{ L"t2", 10 }, { L"r10", 10 }, { L"t3", 11 }, { L"r11", 11 },
6864
{ L"t4", 12 }, { L"r12", 12 }, { L"t5", 13 }, { L"r13", 13 },
6865
{ L"t6", 14 }, { L"r14", 14 }, { L"t7", 15 }, { L"r15", 15 },
6866
{ L"s0", 16 }, { L"r16", 16 }, { L"s1", 17 }, { L"r17", 17 },
6867
{ L"s2", 18 }, { L"r18", 18 }, { L"s3", 19 }, { L"r19", 19 },
6868
{ L"s4", 20 }, { L"r20", 20 }, { L"s5", 21 }, { L"r21", 21 },
6869
{ L"s6", 22 }, { L"r22", 22 }, { L"s7", 23 }, { L"r23", 23 },
6870
{ L"t8", 24 }, { L"r24", 24 }, { L"t9", 25 }, { L"r25", 25 },
6871
{ L"k0", 26 }, { L"r26", 26 }, { L"k1", 27 }, { L"r27", 27 },
6872
{ L"gp", 28 }, { L"r28", 28 }, { L"sp", 29 }, { L"r29", 29 },
6873
{ L"fp", 30 }, { L"r30", 30 }, { L"ra", 31 }, { L"r31", 31 },
6874
{ L"s8", 30 },
6875
};
6876
6877
const MipsRegisterDescriptor mipsFloatRegisters[] = {
6878
{ L"f0", 0 }, { L"f1", 1 }, { L"f2", 2 }, { L"f3", 3 },
6879
{ L"f4", 4 }, { L"f5", 5 }, { L"f6", 6 }, { L"f7", 7 },
6880
{ L"f8", 8 }, { L"f9", 9 }, { L"f00", 0 }, { L"f01", 1 },
6881
{ L"f02", 2 }, { L"f03", 3 }, { L"f04", 4 }, { L"f05", 5 },
6882
{ L"f06", 6 }, { L"f07", 7 }, { L"f08", 8 }, { L"f09", 9 },
6883
{ L"f10", 10 }, { L"f11", 11 }, { L"f12", 12 }, { L"f13", 13 },
6884
{ L"f14", 14 }, { L"f15", 15 }, { L"f16", 16 }, { L"f17", 17 },
6885
{ L"f18", 18 }, { L"f19", 19 }, { L"f20", 20 }, { L"f21", 21 },
6886
{ L"f22", 22 }, { L"f23", 23 }, { L"f24", 24 }, { L"f25", 25 },
6887
{ L"f26", 26 }, { L"f27", 27 }, { L"f28", 28 }, { L"f29", 29 },
6888
{ L"f30", 30 }, { L"f31", 31 },
6889
};
6890
6891
const MipsRegisterDescriptor mipsFpuControlRegisters[] = {
6892
{ L"fir", 0 }, { L"fcr0", 0 }, { L"fcsr", 31 }, { L"fcr31", 31 },
6893
};
6894
6895
const MipsRegisterDescriptor mipsCop0Registers[] = {
6896
{ L"index", 0}, { L"random", 1 }, { L"entrylo", 2 },
6897
{ L"entrylo0", 2 }, { L"entrylo1", 3 }, { L"context", 4 },
6898
{ L"pagemask", 5 }, { L"wired", 6 }, { L"badvaddr", 8 },
6899
{ L"count", 9 }, { L"entryhi", 10 }, { L"compare", 11 },
6900
{ L"status", 12 }, { L"sr", 12 }, { L"cause", 13 },
6901
{ L"epc", 14 }, { L"prid", 15 }, { L"config", 16 },
6902
{ L"lladdr", 17 }, { L"watchlo", 18 }, { L"watchhi", 19 },
6903
{ L"xcontext", 20 }, { L"badpaddr", 23 }, { L"ecc", 26 },
6904
{ L"perr", 26}, { L"cacheerr", 27 }, { L"taglo", 28 },
6905
{ L"taghi", 29 }, { L"errorepc", 30 },
6906
};
6907
6908
const MipsRegisterDescriptor mipsPs2Cop2FpRegisters[] = {
6909
{ L"vf0", 0 }, { L"vf1", 1 }, { L"vf2", 2 }, { L"vf3", 3 },
6910
{ L"vf4", 4 }, { L"vf5", 5 }, { L"vf6", 6 }, { L"vf7", 7 },
6911
{ L"vf8", 8 }, { L"vf9", 9 }, { L"vf00", 0 }, { L"vf01", 1 },
6912
{ L"vf02", 2 }, { L"vf03", 3 }, { L"vf04", 4 }, { L"vf05", 5 },
6913
{ L"vf06", 6 }, { L"vf07", 7 }, { L"vf08", 8 }, { L"vf09", 9 },
6914
{ L"vf10", 10 }, { L"vf11", 11 }, { L"vf12", 12 }, { L"vf13", 13 },
6915
{ L"vf14", 14 }, { L"vf15", 15 }, { L"vf16", 16 }, { L"vf17", 17 },
6916
{ L"vf18", 18 }, { L"vf19", 19 }, { L"vf20", 20 }, { L"vf21", 21 },
6917
{ L"vf22", 22 }, { L"vf23", 23 }, { L"vf24", 24 }, { L"vf25", 25 },
6918
{ L"vf26", 26 }, { L"vf27", 27 }, { L"vf28", 28 }, { L"vf29", 29 },
6919
{ L"vf30", 30 }, { L"vf31", 31 },
6920
};
6921
6922
const MipsRegisterDescriptor mipsPsxCop2DataRegisters[] = {
6923
{ L"vxy0", 0 }, { L"vz0", 1 }, { L"vxy1", 2 }, { L"vz1", 3 },
6924
{ L"vxy2", 4 }, { L"vz2", 5 }, { L"rgbc", 6 }, { L"otz", 7 },
6925
{ L"ir0", 8 }, { L"ir1", 9 }, { L"ir2", 10 }, { L"ir3", 11 },
6926
{ L"sxy0", 12 }, { L"sxy1", 13 }, { L"sxy2", 14 }, { L"sxyp", 15 },
6927
{ L"sz0", 16 }, { L"sz1", 17 }, { L"sz2", 18 }, { L"sz3", 19 },
6928
{ L"rgb0", 20 }, { L"rgb1", 21 }, { L"rgb2", 22 }, { L"res1", 23 },
6929
{ L"mac0", 24 }, { L"mac1", 25 }, { L"mac2", 26 }, { L"mac3", 27 },
6930
{ L"irgb", 28 }, { L"orgb", 29 }, { L"lzcs", 30 }, { L"lzcr", 31 },
6931
};
6932
6933
const MipsRegisterDescriptor mipsPsxCop2ControlRegisters[] = {
6934
{ L"rt0", 0 }, { L"rt1", 1 }, { L"rt2", 2 }, { L"rt3", 3 },
6935
{ L"rt4", 4 }, { L"trx", 5 }, { L"try", 6 }, { L"trz", 7 },
6936
{ L"llm0", 8 }, { L"llm1", 9 }, { L"llm2", 10 }, { L"llm3", 11 },
6937
{ L"llm4", 12 }, { L"rbk", 13 }, { L"gbk", 14 }, { L"bbk", 15 },
6938
{ L"lcm0", 16 }, { L"lcm1", 17 }, { L"lcm2", 18 }, { L"lcm3", 19 },
6939
{ L"lcm4", 20 }, { L"rfc", 21 }, { L"gfc", 22 }, { L"bfc", 23 },
6940
{ L"ofx", 24 }, { L"ofy", 25 }, { L"h", 26 }, { L"dqa", 27 },
6941
{ L"dqb", 28 }, { L"zsf3", 29 }, { L"zsf4", 30 }, { L"flag", 31 },
6942
};
6943
6944
const MipsRegisterDescriptor mipsRspCop0Registers[] = {
6945
{ L"sp_mem_addr", 0 }, { L"sp_dram_addr", 1 }, { L"sp_rd_len", 2 },
6946
{ L"sp_wr_len", 3 }, { L"sp_status", 4 }, { L"sp_dma_full", 5 },
6947
{ L"sp_dma_busy", 6 }, { L"sp_semaphore", 7 }, { L"dpc_start", 8 },
6948
{ L"dpc_end", 9 }, { L"dpc_current", 10 }, { L"dpc_status", 11 },
6949
{ L"dpc_clock", 12 }, { L"dpc_bufbusy", 13 }, { L"dpc_pipebusy", 14 },
6950
{ L"dpc_tmem", 15 },
6951
};
6952
6953
const MipsRegisterDescriptor mipsRspVectorControlRegisters[] = {
6954
{ L"vco", 0 }, { L"vcc", 1 }, { L"vce", 2 },
6955
};
6956
6957
const MipsRegisterDescriptor mipsRspVectorRegisters[] = {
6958
{ L"v0", 0 }, { L"v1", 1 }, { L"v2", 2 }, { L"v3", 3 },
6959
{ L"v4", 4 }, { L"v5", 5 }, { L"v6", 6 }, { L"v7", 7 },
6960
{ L"v8", 8 }, { L"v9", 9 }, { L"v00", 0 }, { L"v01", 1 },
6961
{ L"v02", 2 }, { L"v03", 3 }, { L"v04", 4 }, { L"v05", 5 },
6962
{ L"v06", 6 }, { L"v07", 7 }, { L"v08", 8 }, { L"v09", 9 },
6963
{ L"v10", 10 }, { L"v11", 11 }, { L"v12", 12 }, { L"v13", 13 },
6964
{ L"v14", 14 }, { L"v15", 15 }, { L"v16", 16 }, { L"v17", 17 },
6965
{ L"v18", 18 }, { L"v19", 19 }, { L"v20", 20 }, { L"v21", 21 },
6966
{ L"v22", 22 }, { L"v23", 23 }, { L"v24", 24 }, { L"v25", 25 },
6967
{ L"v26", 26 }, { L"v27", 27 }, { L"v28", 28 }, { L"v29", 29 },
6968
{ L"v30", 30 }, { L"v31", 31 },
6969
};
6970
6971
std::unique_ptr<CAssemblerCommand> parseDirectiveResetDelay(Parser& parser, int flags)
6972
{
6973
Mips.SetIgnoreDelay(true);
6974
return ::make_unique<DummyCommand>();
6975
}
6976
6977
std::unique_ptr<CAssemblerCommand> parseDirectiveFixLoadDelay(Parser& parser, int flags)
6978
{
6979
Mips.SetFixLoadDelay(true);
6980
return ::make_unique<DummyCommand>();
6981
}
6982
6983
std::unique_ptr<CAssemblerCommand> parseDirectiveLoadElf(Parser& parser, int flags)
6984
{
6985
std::vector<Expression> list;
6986
if (parser.parseExpressionList(list,1,2) == false)
6987
return nullptr;
6988
6989
std::wstring inputName, outputName;
6990
if (list[0].evaluateString(inputName,true) == false)
6991
return nullptr;
6992
6993
if (list.size() == 2)
6994
{
6995
if (list[1].evaluateString(outputName,true) == false)
6996
return nullptr;
6997
return ::make_unique<DirectiveLoadMipsElf>(inputName,outputName);
6998
} else {
6999
return ::make_unique<DirectiveLoadMipsElf>(inputName);
7000
}
7001
}
7002
7003
std::unique_ptr<CAssemblerCommand> parseDirectiveImportObj(Parser& parser, int flags)
7004
{
7005
const Token& start = parser.peekToken();
7006
7007
std::vector<Expression> list;
7008
if (parser.parseExpressionList(list,1,2) == false)
7009
return nullptr;
7010
7011
std::wstring inputName;
7012
if (list[0].evaluateString(inputName,true) == false)
7013
return nullptr;
7014
7015
if (list.size() == 2)
7016
{
7017
std::wstring ctorName;
7018
if (list[1].evaluateIdentifier(ctorName) == false)
7019
return nullptr;
7020
7021
if (Mips.GetVersion() == MARCH_PSX)
7022
{
7023
parser.printError(start,L"Constructor not supported for PSX libraries");
7024
return ::make_unique<InvalidCommand>();
7025
}
7026
7027
return ::make_unique<DirectiveObjImport>(inputName,ctorName);
7028
}
7029
7030
if (Mips.GetVersion() == MARCH_PSX)
7031
return ::make_unique<DirectivePsxObjImport>(inputName);
7032
else
7033
return ::make_unique<DirectiveObjImport>(inputName);
7034
}
7035
7036
const DirectiveMap mipsDirectives = {
7037
{ L".resetdelay", { &parseDirectiveResetDelay, 0 } },
7038
{ L".fixloaddelay", { &parseDirectiveFixLoadDelay, 0 } },
7039
{ L".loadelf", { &parseDirectiveLoadElf, 0 } },
7040
{ L".importobj", { &parseDirectiveImportObj, 0 } },
7041
{ L".importlib", { &parseDirectiveImportObj, 0 } },
7042
};
7043
7044
std::unique_ptr<CAssemblerCommand> MipsParser::parseDirective(Parser& parser)
7045
{
7046
return parser.parseDirective(mipsDirectives);
7047
}
7048
7049
bool MipsParser::parseRegisterNumber(Parser& parser, MipsRegisterValue& dest, int numValues)
7050
{
7051
// check for $0 and $1
7052
if (parser.peekToken().type == TokenType::Dollar)
7053
{
7054
const Token& number = parser.peekToken(1);
7055
if (number.type == TokenType::Integer && number.intValue < numValues)
7056
{
7057
dest.name = formatString(L"$%d", number.intValue);
7058
dest.num = (int) number.intValue;
7059
7060
parser.eatTokens(2);
7061
return true;
7062
}
7063
}
7064
7065
return false;
7066
}
7067
7068
bool MipsParser::parseRegisterTable(Parser& parser, MipsRegisterValue& dest, const MipsRegisterDescriptor* table, size_t count)
7069
{
7070
int offset = 0;
7071
bool hasDollar = parser.peekToken().type == TokenType::Dollar;
7072
if (hasDollar)
7073
offset = 1;
7074
7075
const Token &token = parser.peekToken(offset);
7076
7077
if (token.type != TokenType::Identifier)
7078
return false;
7079
7080
const std::wstring stringValue = token.getStringValue();
7081
for (size_t i = 0; i < count; i++)
7082
{
7083
if (stringValue == table[i].name)
7084
{
7085
dest.name = stringValue;
7086
dest.num = table[i].num;
7087
parser.eatTokens(hasDollar ? 2 : 1);
7088
return true;
7089
}
7090
}
7091
7092
return false;
7093
}
7094
7095
bool MipsParser::parseRegister(Parser& parser, MipsRegisterValue& dest)
7096
{
7097
dest.type = MipsRegisterType::Normal;
7098
7099
if (parseRegisterNumber(parser, dest, 32))
7100
return true;
7101
7102
return parseRegisterTable(parser,dest,mipsRegisters,ARRAY_SIZE(mipsRegisters));
7103
}
7104
7105
bool MipsParser::parseFpuRegister(Parser& parser, MipsRegisterValue& dest)
7106
{
7107
dest.type = MipsRegisterType::Float;
7108
7109
if (parseRegisterNumber(parser, dest, 32))
7110
return true;
7111
7112
return parseRegisterTable(parser,dest,mipsFloatRegisters,ARRAY_SIZE(mipsFloatRegisters));
7113
}
7114
7115
bool MipsParser::parseFpuControlRegister(Parser& parser, MipsRegisterValue& dest)
7116
{
7117
dest.type = MipsRegisterType::FpuControl;
7118
7119
if (parseRegisterNumber(parser, dest, 32))
7120
return true;
7121
7122
return parseRegisterTable(parser,dest,mipsFpuControlRegisters,ARRAY_SIZE(mipsFpuControlRegisters));
7123
}
7124
7125
bool MipsParser::parseCop0Register(Parser& parser, MipsRegisterValue& dest)
7126
{
7127
dest.type = MipsRegisterType::Cop0;
7128
7129
if (parseRegisterNumber(parser, dest, 32))
7130
return true;
7131
7132
return parseRegisterTable(parser,dest,mipsCop0Registers,ARRAY_SIZE(mipsCop0Registers));
7133
}
7134
7135
bool MipsParser::parsePs2Cop2Register(Parser& parser, MipsRegisterValue& dest)
7136
{
7137
dest.type = MipsRegisterType::Ps2Cop2;
7138
return parseRegisterTable(parser,dest,mipsPs2Cop2FpRegisters,ARRAY_SIZE(mipsPs2Cop2FpRegisters));
7139
}
7140
7141
bool MipsParser::parsePsxCop2DataRegister(Parser& parser, MipsRegisterValue& dest)
7142
{
7143
dest.type = MipsRegisterType::PsxCop2Data;
7144
7145
if (parseRegisterNumber(parser, dest, 32))
7146
return true;
7147
7148
return parseRegisterTable(parser,dest,mipsPsxCop2DataRegisters,ARRAY_SIZE(mipsPsxCop2DataRegisters));
7149
}
7150
7151
bool MipsParser::parsePsxCop2ControlRegister(Parser& parser, MipsRegisterValue& dest)
7152
{
7153
dest.type = MipsRegisterType::PsxCop2Control;
7154
7155
if (parseRegisterNumber(parser, dest, 32))
7156
return true;
7157
7158
return parseRegisterTable(parser,dest,mipsPsxCop2ControlRegisters,ARRAY_SIZE(mipsPsxCop2ControlRegisters));
7159
}
7160
7161
bool MipsParser::parseRspCop0Register(Parser& parser, MipsRegisterValue& dest)
7162
{
7163
dest.type = MipsRegisterType::RspCop0;
7164
7165
if (parseRegisterNumber(parser, dest, 32))
7166
return true;
7167
7168
return parseRegisterTable(parser,dest,mipsRspCop0Registers,ARRAY_SIZE(mipsRspCop0Registers));
7169
}
7170
7171
bool MipsParser::parseRspVectorControlRegister(Parser& parser, MipsRegisterValue& dest)
7172
{
7173
dest.type = MipsRegisterType::RspVectorControl;
7174
7175
if (parseRegisterNumber(parser, dest, 32))
7176
return true;
7177
7178
return parseRegisterTable(parser,dest,mipsRspVectorControlRegisters,ARRAY_SIZE(mipsRspVectorControlRegisters));
7179
}
7180
7181
bool MipsParser::parseRspVectorRegister(Parser& parser, MipsRegisterValue& dest)
7182
{
7183
dest.type = MipsRegisterType::RspVector;
7184
return parseRegisterTable(parser,dest,mipsRspVectorRegisters,ARRAY_SIZE(mipsRspVectorRegisters));
7185
}
7186
7187
bool MipsParser::parseRspVectorElement(Parser& parser, MipsRegisterValue& dest)
7188
{
7189
dest.type = MipsRegisterType::RspVectorElement;
7190
7191
if (parser.peekToken().type == TokenType::LBrack)
7192
{
7193
static const MipsRegisterDescriptor rspElementNames[] = {
7194
{ L"0q", 2 }, { L"1q", 3 }, { L"0h", 4 }, { L"1h", 5 },
7195
{ L"2h", 6 }, { L"3h", 7 }, { L"0w", 8 }, { L"0", 8 },
7196
{ L"1w", 9 }, { L"1", 9 }, { L"2w", 10 }, { L"2", 10 },
7197
{ L"3w", 11 }, { L"3", 11 }, { L"4w", 12 }, { L"4", 12 },
7198
{ L"5w", 13 }, { L"5", 13 }, { L"6w", 14 }, { L"6", 14 },
7199
{ L"7w", 15 }, { L"7", 15 },
7200
};
7201
7202
parser.eatToken();
7203
7204
if (parseRegisterNumber(parser, dest, 16))
7205
return parser.nextToken().type == TokenType::RBrack;
7206
7207
const Token& token = parser.nextToken();
7208
7209
if (token.type != TokenType::Integer && token.type != TokenType::NumberString)
7210
return false;
7211
7212
//ignore the numerical values, just use the original text as an identifier
7213
std::wstring stringValue = token.getOriginalText();
7214
if (std::any_of(stringValue.begin(), stringValue.end(), iswupper))
7215
{
7216
std::transform(stringValue.begin(), stringValue.end(), stringValue.begin(), towlower);
7217
}
7218
7219
for (size_t i = 0; i < ARRAY_SIZE(rspElementNames); i++)
7220
{
7221
if (stringValue == rspElementNames[i].name)
7222
{
7223
dest.num = rspElementNames[i].num;
7224
dest.name = rspElementNames[i].name;
7225
7226
return parser.nextToken().type == TokenType::RBrack;
7227
}
7228
}
7229
7230
return false;
7231
}
7232
7233
dest.num = 0;
7234
dest.name = L"";
7235
7236
return true;
7237
7238
}
7239
7240
bool MipsParser::parseRspScalarElement(Parser& parser, MipsRegisterValue& dest)
7241
{
7242
dest.type = MipsRegisterType::RspScalarElement;
7243
7244
if (parser.nextToken().type != TokenType::LBrack)
7245
return false;
7246
7247
const Token &token = parser.nextToken();
7248
7249
if (token.type != TokenType::Integer || token.intValue >= 8)
7250
return false;
7251
7252
dest.name = formatString(L"%d", token.intValue);
7253
dest.num = token.intValue + 8;
7254
7255
return parser.nextToken().type == TokenType::RBrack;
7256
}
7257
7258
bool MipsParser::parseRspOffsetElement(Parser& parser, MipsRegisterValue& dest)
7259
{
7260
dest.type = MipsRegisterType::RspOffsetElement;
7261
7262
if (parser.peekToken().type == TokenType::LBrack)
7263
{
7264
parser.eatToken();
7265
7266
const Token &token = parser.nextToken();
7267
7268
if (token.type != TokenType::Integer || token.intValue >= 16)
7269
return false;
7270
7271
dest.name = formatString(L"%d", token.intValue);
7272
dest.num = token.intValue;
7273
7274
return parser.nextToken().type == TokenType::RBrack;
7275
}
7276
7277
dest.num = 0;
7278
dest.name = L"";
7279
7280
return true;
7281
}
7282
7283
static bool decodeDigit(wchar_t digit, int& dest)
7284
{
7285
if (digit >= '0' && digit <= '9')
7286
{
7287
dest = digit-'0';
7288
return true;
7289
}
7290
return false;
7291
}
7292
7293
bool MipsParser::parseVfpuRegister(Parser& parser, MipsRegisterValue& reg, int size)
7294
{
7295
const Token& token = parser.peekToken();
7296
const std::wstring stringValue = token.getStringValue();
7297
if (token.type != TokenType::Identifier || stringValue.size() != 4)
7298
return false;
7299
7300
int mtx,col,row;
7301
if (decodeDigit(stringValue[1],mtx) == false) return false;
7302
if (decodeDigit(stringValue[2],col) == false) return false;
7303
if (decodeDigit(stringValue[3],row) == false) return false;
7304
wchar_t mode = towlower(stringValue[0]);
7305
7306
if (size < 0 || size > 3)
7307
return false;
7308
7309
if (row > 3 || col > 3 || mtx > 7)
7310
return false;
7311
7312
reg.num = 0;
7313
switch (mode)
7314
{
7315
case 'r': // transposed vector
7316
reg.num |= (1 << 5);
7317
std::swap(col,row); // fallthrough
7318
case 'c': // vector
7319
reg.type = MipsRegisterType::VfpuVector;
7320
7321
switch (size)
7322
{
7323
case 1: // pair
7324
case 3: // quad
7325
if (row & 1)
7326
return false;
7327
break;
7328
case 2: // triple
7329
if (row & 2)
7330
return false;
7331
row <<= 1;
7332
break;
7333
default:
7334
return false;
7335
}
7336
break;
7337
case 's': // single
7338
reg.type = MipsRegisterType::VfpuVector;
7339
7340
if (size != 0)
7341
return false;
7342
break;
7343
case 'e': // transposed matrix
7344
reg.num |= (1 << 5); // fallthrough
7345
case 'm': // matrix
7346
reg.type = MipsRegisterType::VfpuMatrix;
7347
7348
// check size
7349
switch (size)
7350
{
7351
case 1: // 2x2
7352
case 3: // 4x4
7353
if (row & 1)
7354
return false;
7355
break;
7356
case 2: // 3x3
7357
if (row & ~1)
7358
return false;
7359
row <<= 1;
7360
break;
7361
default:
7362
return false;
7363
}
7364
break;
7365
default:
7366
return false;
7367
}
7368
7369
reg.num |= mtx << 2;
7370
reg.num |= col;
7371
reg.num |= row << 5;
7372
7373
reg.name = stringValue;
7374
parser.eatToken();
7375
return true;
7376
}
7377
7378
bool MipsParser::parseVfpuControlRegister(Parser& parser, MipsRegisterValue& reg)
7379
{
7380
static const wchar_t* vfpuCtrlNames[16] = {
7381
L"spfx", L"tpfx", L"dpfx", L"cc",
7382
L"inf4", L"rsv5", L"rsv6", L"rev",
7383
L"rcx0", L"rcx1", L"rcx2", L"rcx3",
7384
L"rcx4", L"rcx5", L"rcx6", L"rcx7",
7385
};
7386
7387
const Token& token = parser.peekToken();
7388
const std::wstring stringValue = token.getStringValue();
7389
7390
if (token.type == TokenType::Identifier)
7391
{
7392
for (int i = 0; i < 16; i++)
7393
{
7394
if (stringValue == vfpuCtrlNames[i])
7395
{
7396
reg.num = i;
7397
reg.name = vfpuCtrlNames[i];
7398
7399
parser.eatToken();
7400
return true;
7401
}
7402
}
7403
} else if (token.type == TokenType::Integer && token.intValue <= 15)
7404
{
7405
reg.num = (int) token.intValue;
7406
reg.name = vfpuCtrlNames[reg.num];
7407
7408
parser.eatToken();
7409
return true;
7410
}
7411
7412
return false;
7413
}
7414
7415
bool MipsParser::parseImmediate(Parser& parser, Expression& dest)
7416
{
7417
// check for (reg) or reg sequence
7418
TokenizerPosition pos = parser.getTokenizer()->getPosition();
7419
7420
bool hasParen = parser.peekToken().type == TokenType::LParen;
7421
if (hasParen)
7422
parser.eatToken();
7423
7424
MipsRegisterValue tempValue;
7425
bool isRegister = parseRegister(parser,tempValue);
7426
parser.getTokenizer()->setPosition(pos);
7427
7428
if (isRegister)
7429
return false;
7430
7431
dest = parser.parseExpression();
7432
return dest.isLoaded();
7433
}
7434
7435
bool MipsParser::matchSymbol(Parser& parser, wchar_t symbol)
7436
{
7437
switch (symbol)
7438
{
7439
case '(':
7440
return parser.matchToken(TokenType::LParen);
7441
case ')':
7442
return parser.matchToken(TokenType::RParen);
7443
case ',':
7444
return parser.matchToken(TokenType::Comma);
7445
}
7446
7447
return false;
7448
}
7449
7450
bool MipsParser::parseVcstParameter(Parser& parser, int& result)
7451
{
7452
static TokenSequenceParser sequenceParser;
7453
7454
// initialize on first use
7455
if (sequenceParser.getEntryCount() == 0)
7456
{
7457
// maxfloat
7458
sequenceParser.addEntry(1,
7459
{TokenType::Identifier},
7460
{L"maxfloat"}
7461
);
7462
// sqrt(2)
7463
sequenceParser.addEntry(2,
7464
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::RParen},
7465
{L"sqrt", INT64_C(2)}
7466
);
7467
// sqrt(1/2)
7468
sequenceParser.addEntry(3,
7469
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::Div, TokenType::Integer, TokenType::RParen},
7470
{L"sqrt", INT64_C(1), INT64_C(2)}
7471
);
7472
// sqrt(0.5)
7473
sequenceParser.addEntry(3,
7474
{TokenType::Identifier, TokenType::LParen, TokenType::Float, TokenType::RParen},
7475
{L"sqrt", 0.5}
7476
);
7477
// 2/sqrt(pi)
7478
sequenceParser.addEntry(4,
7479
{TokenType::Integer, TokenType::Div, TokenType::Identifier, TokenType::LParen, TokenType::Identifier, TokenType::RParen},
7480
{INT64_C(2), L"sqrt", L"pi"}
7481
);
7482
// 2/pi
7483
sequenceParser.addEntry(5,
7484
{TokenType::Integer, TokenType::Div, TokenType::Identifier},
7485
{INT64_C(2), L"pi"}
7486
);
7487
// 1/pi
7488
sequenceParser.addEntry(6,
7489
{TokenType::Integer, TokenType::Div, TokenType::Identifier},
7490
{INT64_C(1), L"pi"}
7491
);
7492
// pi/4
7493
sequenceParser.addEntry(7,
7494
{TokenType::Identifier, TokenType::Div, TokenType::Integer},
7495
{L"pi", INT64_C(4)}
7496
);
7497
// pi/2
7498
sequenceParser.addEntry(8,
7499
{TokenType::Identifier, TokenType::Div, TokenType::Integer},
7500
{L"pi", INT64_C(2)}
7501
);
7502
// pi/6 - early because "pi" is a prefix of it
7503
sequenceParser.addEntry(16,
7504
{TokenType::Identifier, TokenType::Div, TokenType::Integer},
7505
{L"pi", INT64_C(6)}
7506
);
7507
// pi
7508
sequenceParser.addEntry(9,
7509
{TokenType::Identifier},
7510
{L"pi"}
7511
);
7512
// e
7513
sequenceParser.addEntry(10,
7514
{TokenType::Identifier},
7515
{L"e"}
7516
);
7517
// log2(e)
7518
sequenceParser.addEntry(11,
7519
{TokenType::Identifier, TokenType::LParen, TokenType::Identifier, TokenType::RParen},
7520
{L"log2", L"e"}
7521
);
7522
// log10(e)
7523
sequenceParser.addEntry(12,
7524
{TokenType::Identifier, TokenType::LParen, TokenType::Identifier, TokenType::RParen},
7525
{L"log10", L"e"}
7526
);
7527
// ln(2)
7528
sequenceParser.addEntry(13,
7529
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::RParen},
7530
{L"ln", INT64_C(2)}
7531
);
7532
// ln(10)
7533
sequenceParser.addEntry(14,
7534
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::RParen},
7535
{L"ln", INT64_C(10)}
7536
);
7537
// 2*pi
7538
sequenceParser.addEntry(15,
7539
{TokenType::Integer, TokenType::Mult, TokenType::Identifier},
7540
{INT64_C(2), L"pi"}
7541
);
7542
// log10(2)
7543
sequenceParser.addEntry(17,
7544
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::RParen},
7545
{L"log10", INT64_C(2)}
7546
);
7547
// log2(10)
7548
sequenceParser.addEntry(18,
7549
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::RParen},
7550
{L"log2", INT64_C(10)}
7551
);
7552
// sqrt(3)/2
7553
sequenceParser.addEntry(19,
7554
{TokenType::Identifier, TokenType::LParen, TokenType::Integer, TokenType::RParen, TokenType::Div, TokenType::Integer},
7555
{L"sqrt", INT64_C(3), INT64_C(2)}
7556
);
7557
}
7558
7559
return sequenceParser.parse(parser,result);
7560
}
7561
7562
bool MipsParser::parseVfpuVrot(Parser& parser, int& result, int size)
7563
{
7564
int sin = -1;
7565
int cos = -1;
7566
bool negSine = false;
7567
int sineCount = 0;
7568
7569
if (parser.nextToken().type != TokenType::LBrack)
7570
return false;
7571
7572
int numElems = size+1;
7573
for (int i = 0; i < numElems; i++)
7574
{
7575
const Token* tokenFinder = &parser.nextToken();
7576
7577
if (i != 0)
7578
{
7579
if (tokenFinder->type != TokenType::Comma)
7580
return false;
7581
7582
tokenFinder = &parser.nextToken();
7583
}
7584
7585
bool isNeg = tokenFinder->type == TokenType::Minus;
7586
if (isNeg)
7587
tokenFinder = &parser.nextToken();
7588
7589
const Token& token = *tokenFinder;
7590
7591
const std::wstring stringValue = token.getStringValue();
7592
if (token.type != TokenType::Identifier || stringValue.size() != 1)
7593
return false;
7594
7595
switch (stringValue[0])
7596
{
7597
case 's':
7598
// if one is negative, all have to be
7599
if ((!isNeg && negSine) || (isNeg && !negSine && sineCount > 0))
7600
return false;
7601
7602
negSine = negSine || isNeg;
7603
sin = i;
7604
sineCount++;
7605
break;
7606
case 'c':
7607
// can't be negative, or happen twice
7608
if (isNeg || cos != -1)
7609
return false;
7610
cos = i;
7611
break;
7612
case '0':
7613
if (isNeg)
7614
return false;
7615
break;
7616
default:
7617
return false;
7618
}
7619
}
7620
7621
if (parser.nextToken().type != TokenType::RBrack)
7622
return false;
7623
7624
result = negSine ? 0x10 : 0;
7625
7626
if (sin == -1 && cos == -1)
7627
{
7628
return false;
7629
} else if (sin == -1)
7630
{
7631
if (numElems == 4)
7632
return false;
7633
7634
result |= cos;
7635
result |= ((size+1) << 2);
7636
} else if (cos == -1)
7637
{
7638
if (numElems == 4)
7639
return false;
7640
7641
if (sineCount == 1)
7642
{
7643
result |= (size+1);
7644
result |= (sin << 2);
7645
} else if (sineCount == numElems)
7646
{
7647
result |= (size+1);
7648
result |= ((size+1) << 2);
7649
} else {
7650
return false;
7651
}
7652
} else {
7653
if (sineCount > 1)
7654
{
7655
if (sineCount+1 != numElems)
7656
return false;
7657
7658
result |= cos;
7659
result |= (cos << 2);
7660
} else {
7661
result |= cos;
7662
result |= (sin << 2);
7663
}
7664
}
7665
7666
return true;
7667
}
7668
7669
bool MipsParser::parseVfpuCondition(Parser& parser, int& result)
7670
{
7671
static const wchar_t* conditions[] = {
7672
L"fl", L"eq", L"lt", L"le", L"tr", L"ne", L"ge", L"gt",
7673
L"ez", L"en", L"ei", L"es", L"nz", L"nn", L"ni", L"ns"
7674
};
7675
7676
const Token& token = parser.nextToken();
7677
if (token.type != TokenType::Identifier)
7678
return false;
7679
7680
const std::wstring stringValue = token.getStringValue();
7681
for (size_t i = 0; i < ARRAY_SIZE(conditions); i++)
7682
{
7683
if (stringValue == conditions[i])
7684
{
7685
result = i;
7686
return true;
7687
}
7688
}
7689
7690
return false;
7691
}
7692
7693
bool MipsParser::parseVpfxsParameter(Parser& parser, int& result)
7694
{
7695
static TokenSequenceParser sequenceParser;
7696
7697
// initialize on first use
7698
if (sequenceParser.getEntryCount() == 0)
7699
{
7700
// 0
7701
sequenceParser.addEntry(0, {TokenType::Integer}, {INT64_C(0)} );
7702
// 1
7703
sequenceParser.addEntry(1, {TokenType::Integer}, {INT64_C(1)} );
7704
// 2
7705
sequenceParser.addEntry(2, {TokenType::Integer}, {INT64_C(2)} );
7706
// 1/2
7707
sequenceParser.addEntry(3, {TokenType::Integer, TokenType::Div, TokenType::Integer}, {INT64_C(1), INT64_C(2)} );
7708
// 3
7709
sequenceParser.addEntry(4, {TokenType::Integer}, {INT64_C(3)} );
7710
// 1/3
7711
sequenceParser.addEntry(5, {TokenType::Integer, TokenType::Div, TokenType::Integer}, {INT64_C(1), INT64_C(3)} );
7712
// 1/4
7713
sequenceParser.addEntry(6, {TokenType::Integer, TokenType::Div, TokenType::Integer}, {INT64_C(1), INT64_C(4)} );
7714
// 1/6
7715
sequenceParser.addEntry(7, {TokenType::Integer, TokenType::Div, TokenType::Integer}, {INT64_C(1), INT64_C(6)} );
7716
}
7717
7718
if (parser.nextToken().type != TokenType::LBrack)
7719
return false;
7720
7721
for (int i = 0; i < 4; i++)
7722
{
7723
const Token *tokenFinder = &parser.nextToken();
7724
7725
if (i != 0)
7726
{
7727
if (tokenFinder->type != TokenType::Comma)
7728
return false;
7729
7730
tokenFinder = &parser.nextToken();
7731
}
7732
7733
// negation
7734
if (tokenFinder->type == TokenType::Minus)
7735
{
7736
result |= 1 << (16+i);
7737
tokenFinder = &parser.nextToken();
7738
}
7739
7740
// abs
7741
bool abs = false;
7742
if (tokenFinder->type == TokenType::BitOr)
7743
{
7744
result |= 1 << (8+i);
7745
abs = true;
7746
tokenFinder = &parser.nextToken();
7747
}
7748
7749
const Token& token = *tokenFinder;
7750
7751
// check for register
7752
const wchar_t* reg;
7753
static const wchar_t* vpfxstRegisters = L"xyzw";
7754
const std::wstring stringValue = token.getStringValue();
7755
if (stringValue.size() == 1 && (reg = wcschr(vpfxstRegisters,stringValue[0])) != nullptr)
7756
{
7757
result |= (reg-vpfxstRegisters) << (i*2);
7758
7759
if (abs && parser.nextToken().type != TokenType::BitOr)
7760
return false;
7761
7762
continue;
7763
}
7764
7765
// abs is invalid with constants
7766
if (abs)
7767
return false;
7768
7769
result |= 1 << (12+i);
7770
7771
int constNum = -1;
7772
if (sequenceParser.parse(parser,constNum) == false)
7773
return false;
7774
7775
result |= (constNum & 3) << (i*2);
7776
if (constNum & 4)
7777
result |= 1 << (8+i);
7778
}
7779
7780
return parser.nextToken().type == TokenType::RBrack;
7781
}
7782
7783
bool MipsParser::parseVpfxdParameter(Parser& parser, int& result)
7784
{
7785
static TokenSequenceParser sequenceParser;
7786
7787
// initialize on first use
7788
if (sequenceParser.getEntryCount() == 0)
7789
{
7790
// 0-1
7791
sequenceParser.addEntry(1,
7792
{TokenType::Integer, TokenType::Minus, TokenType::Integer},
7793
{INT64_C(0), INT64_C(1)} );
7794
// 0-1
7795
sequenceParser.addEntry(-1,
7796
{TokenType::Integer, TokenType::Minus, TokenType::NumberString},
7797
{INT64_C(0), L"1m"} );
7798
// 0:1
7799
sequenceParser.addEntry(1,
7800
{TokenType::Integer, TokenType::Colon, TokenType::Integer},
7801
{INT64_C(0), INT64_C(1)} );
7802
// 0:1
7803
sequenceParser.addEntry(-1,
7804
{TokenType::Integer, TokenType::Colon, TokenType::NumberString},
7805
{INT64_C(0), L"1m"} );
7806
// -1-1
7807
sequenceParser.addEntry(3,
7808
{TokenType::Minus, TokenType::Integer, TokenType::Minus, TokenType::Integer},
7809
{INT64_C(1), INT64_C(1)} );
7810
// -1-1m
7811
sequenceParser.addEntry(-3,
7812
{TokenType::Minus, TokenType::Integer, TokenType::Minus, TokenType::NumberString},
7813
{INT64_C(1), L"1m"} );
7814
// -1:1
7815
sequenceParser.addEntry(3,
7816
{TokenType::Minus, TokenType::Integer, TokenType::Colon, TokenType::Integer},
7817
{INT64_C(1), INT64_C(1)} );
7818
// -1:1m
7819
sequenceParser.addEntry(-3,
7820
{TokenType::Minus, TokenType::Integer, TokenType::Colon, TokenType::NumberString},
7821
{INT64_C(1), L"1m"} );
7822
}
7823
7824
for (int i = 0; i < 4; i++)
7825
{
7826
if (i != 0)
7827
{
7828
if (parser.nextToken().type != TokenType::Comma)
7829
return false;
7830
}
7831
7832
parser.eatToken();
7833
7834
int num = 0;
7835
if (sequenceParser.parse(parser,num) == false)
7836
return false;
7837
7838
// m versions
7839
if (num < 0)
7840
{
7841
result |= 1 << (8+i);
7842
num = abs(num);
7843
}
7844
7845
result |= num << (2*i);
7846
}
7847
7848
return parser.nextToken().type == TokenType::RBrack;
7849
}
7850
7851
7852
bool MipsParser::decodeCop2BranchCondition(const std::wstring& text, size_t& pos, int& result)
7853
{
7854
if (pos+3 == text.size())
7855
{
7856
if (startsWith(text,L"any",pos))
7857
{
7858
result = 4;
7859
pos += 3;
7860
return true;
7861
}
7862
if (startsWith(text,L"all",pos))
7863
{
7864
result = 5;
7865
pos += 3;
7866
return true;
7867
}
7868
} else if (pos+1 == text.size())
7869
{
7870
switch (text[pos++])
7871
{
7872
case 'x':
7873
case '0':
7874
result = 0;
7875
return true;
7876
case 'y':
7877
case '1':
7878
result = 1;
7879
return true;
7880
case 'z':
7881
case '2':
7882
result = 2;
7883
return true;
7884
case 'w':
7885
case '3':
7886
result = 3;
7887
return true;
7888
case '4':
7889
result = 4;
7890
return true;
7891
case '5':
7892
result = 5;
7893
return true;
7894
}
7895
7896
// didn't match it
7897
pos--;
7898
}
7899
7900
return false;
7901
}
7902
7903
bool MipsParser::parseCop2BranchCondition(Parser& parser, int& result)
7904
{
7905
const Token& token = parser.nextToken();
7906
7907
if (token.type == TokenType::Integer)
7908
{
7909
result = (int) token.intValue;
7910
return token.intValue <= 5;
7911
}
7912
7913
if (token.type != TokenType::Identifier)
7914
return false;
7915
7916
size_t pos = 0;
7917
return decodeCop2BranchCondition(token.getStringValue(),pos,result);
7918
}
7919
7920
bool MipsParser::parseWb(Parser& parser)
7921
{
7922
const Token& token = parser.nextToken();
7923
if (token.type != TokenType::Identifier)
7924
return false;
7925
7926
return token.getStringValue() == L"wb";
7927
}
7928
7929
static bool decodeImmediateSize(const char*& encoding, MipsImmediateType& dest)
7930
{
7931
if (*encoding == 'h') // half float
7932
{
7933
encoding++;
7934
dest = MipsImmediateType::ImmediateHalfFloat;
7935
} else {
7936
int num = 0;
7937
while (*encoding >= '0' && *encoding <= '9')
7938
{
7939
num = num*10 + *encoding-'0';
7940
encoding++;
7941
}
7942
7943
switch (num)
7944
{
7945
case 5:
7946
dest = MipsImmediateType::Immediate5;
7947
break;
7948
case 7:
7949
dest = MipsImmediateType::Immediate7;
7950
break;
7951
case 10:
7952
dest = MipsImmediateType::Immediate10;
7953
break;
7954
case 16:
7955
dest = MipsImmediateType::Immediate16;
7956
break;
7957
case 20:
7958
dest = MipsImmediateType::Immediate20;
7959
break;
7960
case 25:
7961
dest = MipsImmediateType::Immediate25;
7962
break;
7963
case 26:
7964
dest = MipsImmediateType::Immediate26;
7965
break;
7966
default:
7967
return false;
7968
}
7969
}
7970
7971
return true;
7972
}
7973
7974
bool MipsParser::decodeVfpuType(const std::wstring& name, size_t& pos, int& dest)
7975
{
7976
if (pos >= name.size())
7977
return false;
7978
7979
switch (name[pos++])
7980
{
7981
case 's':
7982
dest = 0;
7983
return true;
7984
case 'p':
7985
dest = 1;
7986
return true;
7987
case 't':
7988
dest = 2;
7989
return true;
7990
case 'q':
7991
dest = 3;
7992
return true;
7993
}
7994
7995
pos--;
7996
return false;
7997
}
7998
7999
bool MipsParser::decodeOpcode(const std::wstring& name, const tMipsOpcode& opcode)
8000
{
8001
const char* encoding = opcode.name;
8002
size_t pos = 0;
8003
8004
registers.reset();
8005
immediate.reset();
8006
opcodeData.reset();
8007
hasFixedSecondaryImmediate = false;
8008
8009
while (*encoding != 0)
8010
{
8011
switch (*encoding++)
8012
{
8013
case 'S':
8014
CHECK(decodeVfpuType(name,pos,opcodeData.vfpuSize));
8015
break;
8016
case 'B':
8017
CHECK(decodeCop2BranchCondition(name,pos,immediate.secondary.originalValue));
8018
immediate.secondary.type = MipsImmediateType::Cop2BranchType;
8019
immediate.secondary.value = immediate.secondary.originalValue;
8020
hasFixedSecondaryImmediate = true;
8021
break;
8022
default:
8023
CHECK(pos < name.size());
8024
CHECK(*(encoding-1) == name[pos++]);
8025
break;
8026
}
8027
}
8028
8029
return pos >= name.size();
8030
}
8031
8032
void MipsParser::setOmittedRegisters(const tMipsOpcode& opcode)
8033
{
8034
// copy over omitted registers
8035
if (opcode.flags & MO_RSD)
8036
registers.grd = registers.grs;
8037
8038
if (opcode.flags & MO_RST)
8039
registers.grt = registers.grs;
8040
8041
if (opcode.flags & MO_RDT)
8042
registers.grt = registers.grd;
8043
8044
if (opcode.flags & MO_FRSD)
8045
registers.frd = registers.frs;
8046
8047
if (opcode.flags & MO_RSPVRSD)
8048
registers.rspvrd = registers.rspvrs;
8049
}
8050
8051
bool MipsParser::parseParameters(Parser& parser, const tMipsOpcode& opcode)
8052
{
8053
const char* encoding = opcode.encoding;
8054
8055
// initialize opcode variables
8056
immediate.primary.type = MipsImmediateType::None;
8057
if (!hasFixedSecondaryImmediate)
8058
immediate.secondary.type = MipsImmediateType::None;
8059
8060
if (opcodeData.vfpuSize == -1)
8061
{
8062
if (opcode.flags & MO_VFPU_SINGLE)
8063
opcodeData.vfpuSize = 0;
8064
else if (opcode.flags & MO_VFPU_PAIR)
8065
opcodeData.vfpuSize = 1;
8066
else if (opcode.flags & MO_VFPU_TRIPLE)
8067
opcodeData.vfpuSize = 2;
8068
else if (opcode.flags & MO_VFPU_QUAD)
8069
opcodeData.vfpuSize = 3;
8070
}
8071
8072
// parse parameters
8073
MipsRegisterValue tempRegister;
8074
int actualSize = opcodeData.vfpuSize;
8075
8076
while (*encoding != 0)
8077
{
8078
switch (*encoding++)
8079
{
8080
case 't': // register
8081
CHECK(parseRegister(parser,registers.grt));
8082
break;
8083
case 'd': // register
8084
CHECK(parseRegister(parser,registers.grd));
8085
break;
8086
case 's': // register
8087
CHECK(parseRegister(parser,registers.grs));
8088
break;
8089
case 'T': // float register
8090
CHECK(parseFpuRegister(parser,registers.frt));
8091
break;
8092
case 'D': // float register
8093
CHECK(parseFpuRegister(parser,registers.frd));
8094
break;
8095
case 'S': // float register
8096
CHECK(parseFpuRegister(parser,registers.frs));
8097
break;
8098
case 'f': // fpu control register
8099
CHECK(parseFpuControlRegister(parser,registers.frs));
8100
break;
8101
case 'z': // cop0 register
8102
CHECK(parseCop0Register(parser,registers.grd));
8103
break;
8104
case 'v': // psp vfpu reg
8105
if (*encoding == 'S')
8106
{
8107
encoding++;
8108
actualSize = 0;
8109
}
8110
8111
switch (*encoding++)
8112
{
8113
case 's':
8114
CHECK(parseVfpuRegister(parser,registers.vrs,actualSize));
8115
CHECK(registers.vrs.type == MipsRegisterType::VfpuVector);
8116
if (opcode.flags & MO_VFPU_6BIT) CHECK(!(registers.vrs.num & 0x40));
8117
break;
8118
case 't':
8119
CHECK(parseVfpuRegister(parser,registers.vrt,actualSize));
8120
CHECK(registers.vrt.type == MipsRegisterType::VfpuVector);
8121
if (opcode.flags & MO_VFPU_6BIT) CHECK(!(registers.vrt.num & 0x40));
8122
break;
8123
case 'd':
8124
CHECK(parseVfpuRegister(parser,registers.vrd,actualSize));
8125
CHECK(registers.vrd.type == MipsRegisterType::VfpuVector);
8126
if (opcode.flags & MO_VFPU_6BIT) CHECK(!(registers.vrd.num & 0x40));
8127
break;
8128
case 'c':
8129
CHECK(parseVfpuControlRegister(parser,registers.vrd));
8130
break;
8131
default:
8132
return false;
8133
}
8134
break;
8135
case 'm': // vfpu matrix register
8136
switch (*encoding++)
8137
{
8138
case 's':
8139
CHECK(parseVfpuRegister(parser,registers.vrs,opcodeData.vfpuSize));
8140
CHECK(registers.vrs.type == MipsRegisterType::VfpuMatrix);
8141
if (opcode.flags & MO_TRANSPOSE_VS)
8142
registers.vrs.num ^= 0x20;
8143
break;
8144
case 't':
8145
CHECK(parseVfpuRegister(parser,registers.vrt,opcodeData.vfpuSize));
8146
CHECK(registers.vrt.type == MipsRegisterType::VfpuMatrix);
8147
break;
8148
case 'd':
8149
CHECK(parseVfpuRegister(parser,registers.vrd,opcodeData.vfpuSize));
8150
CHECK(registers.vrd.type == MipsRegisterType::VfpuMatrix);
8151
break;
8152
default:
8153
return false;
8154
}
8155
break;
8156
case 'V': // ps2 vector reg
8157
switch (*encoding++)
8158
{
8159
case 't': // register
8160
CHECK(parsePs2Cop2Register(parser,registers.ps2vrt));
8161
break;
8162
case 'd': // register
8163
CHECK(parsePs2Cop2Register(parser,registers.ps2vrd));
8164
break;
8165
case 's': // register
8166
CHECK(parsePs2Cop2Register(parser,registers.ps2vrs));
8167
break;
8168
default:
8169
return false;
8170
}
8171
break;
8172
case 'g': // psx cop2 reg
8173
switch (*encoding++)
8174
{
8175
case 't': // gte data register
8176
CHECK(parsePsxCop2DataRegister(parser,registers.grt));
8177
break;
8178
case 's': // gte data register
8179
CHECK(parsePsxCop2DataRegister(parser,registers.grd));
8180
break;
8181
case 'c': // gte control register
8182
CHECK(parsePsxCop2ControlRegister(parser,registers.grd));
8183
break;
8184
default:
8185
return false;
8186
}
8187
break;
8188
case 'r': // forced register
8189
CHECK(parseRegister(parser,tempRegister));
8190
CHECK(tempRegister.num == *encoding++);
8191
break;
8192
case 'R': // rsp register
8193
switch (*encoding++)
8194
{
8195
case 'z': // cop0 register
8196
CHECK(parseRspCop0Register(parser,registers.grd));
8197
break;
8198
case 'c': // vector control register
8199
CHECK(parseRspVectorControlRegister(parser,registers.grd));
8200
break;
8201
case 't': // vector register
8202
CHECK(parseRspVectorRegister(parser,registers.rspvrt));
8203
break;
8204
case 'd': // vector register
8205
CHECK(parseRspVectorRegister(parser,registers.rspvrd));
8206
break;
8207
case 's': // vector register
8208
CHECK(parseRspVectorRegister(parser,registers.rspvrs));
8209
break;
8210
case 'e': // vector element
8211
CHECK(parseRspVectorElement(parser,registers.rspve));
8212
break;
8213
case 'l': // scalar element
8214
CHECK(parseRspScalarElement(parser,registers.rspve));
8215
break;
8216
case 'm': // scalar destination element
8217
CHECK(parseRspScalarElement(parser,registers.rspvde));
8218
break;
8219
case 'o': // byte offset element
8220
CHECK(parseRspOffsetElement(parser,registers.rspvealt));
8221
break;
8222
default:
8223
return false;
8224
}
8225
break;
8226
case 'i': // primary immediate
8227
CHECK(parseImmediate(parser,immediate.primary.expression));
8228
allowFunctionCallExpression(*encoding != '(');
8229
CHECK(decodeImmediateSize(encoding,immediate.primary.type));
8230
allowFunctionCallExpression(true);
8231
break;
8232
case 'j': // secondary immediate
8233
switch (*encoding++)
8234
{
8235
case 'c':
8236
CHECK(parseImmediate(parser,immediate.secondary.expression));
8237
immediate.secondary.type = MipsImmediateType::CacheOp;
8238
break;
8239
case 'e':
8240
CHECK(parseImmediate(parser,immediate.secondary.expression));
8241
immediate.secondary.type = MipsImmediateType::Ext;
8242
break;
8243
case 'i':
8244
CHECK(parseImmediate(parser,immediate.secondary.expression));
8245
immediate.secondary.type = MipsImmediateType::Ins;
8246
break;
8247
case 'b':
8248
CHECK(parseCop2BranchCondition(parser,immediate.secondary.originalValue));
8249
immediate.secondary.type = MipsImmediateType::Cop2BranchType;
8250
immediate.secondary.value = immediate.secondary.originalValue;
8251
break;
8252
default:
8253
return false;
8254
}
8255
break;
8256
case 'C': // vfpu condition
8257
CHECK(parseVfpuCondition(parser,opcodeData.vectorCondition));
8258
break;
8259
case 'W': // vfpu argument
8260
switch (*encoding++)
8261
{
8262
case 's':
8263
CHECK(parseVpfxsParameter(parser,immediate.primary.originalValue));
8264
immediate.primary.value = immediate.primary.originalValue;
8265
immediate.primary.type = MipsImmediateType::Immediate20_0;
8266
break;
8267
case 'd':
8268
CHECK(parseVpfxdParameter(parser,immediate.primary.originalValue));
8269
immediate.primary.value = immediate.primary.originalValue;
8270
immediate.primary.type = MipsImmediateType::Immediate16;
8271
break;
8272
case 'c':
8273
CHECK(parseVcstParameter(parser,immediate.primary.originalValue));
8274
immediate.primary.value = immediate.primary.originalValue;
8275
immediate.primary.type = MipsImmediateType::Immediate5;
8276
break;
8277
case 'r':
8278
CHECK(parseVfpuVrot(parser,immediate.primary.originalValue,opcodeData.vfpuSize));
8279
immediate.primary.value = immediate.primary.originalValue;
8280
immediate.primary.type = MipsImmediateType::Immediate5;
8281
break;
8282
default:
8283
return false;
8284
}
8285
break;
8286
case 'w': // 'wb' characters
8287
CHECK(parseWb(parser));
8288
break;
8289
default:
8290
CHECK(matchSymbol(parser,*(encoding-1)));
8291
break;
8292
}
8293
}
8294
8295
opcodeData.opcode = opcode;
8296
setOmittedRegisters(opcode);
8297
8298
// the next token has to be a separator, else the parameters aren't
8299
// completely parsed
8300
8301
return parser.nextToken().type == TokenType::Separator;
8302
8303
}
8304
8305
std::unique_ptr<CMipsInstruction> MipsParser::parseOpcode(Parser& parser)
8306
{
8307
if (parser.peekToken().type != TokenType::Identifier)
8308
return nullptr;
8309
8310
const Token &token = parser.nextToken();
8311
8312
bool paramFail = false;
8313
const MipsArchDefinition& arch = mipsArchs[Mips.GetVersion()];
8314
const std::wstring stringValue = token.getStringValue();
8315
8316
for (int z = 0; MipsOpcodes[z].name != nullptr; z++)
8317
{
8318
if ((MipsOpcodes[z].archs & arch.supportSets) == 0)
8319
continue;
8320
if ((MipsOpcodes[z].archs & arch.excludeMask) != 0)
8321
continue;
8322
8323
if ((MipsOpcodes[z].flags & MO_64BIT) && !(arch.flags & MO_64BIT))
8324
continue;
8325
if ((MipsOpcodes[z].flags & MO_FPU) && !(arch.flags & MO_FPU))
8326
continue;
8327
if ((MipsOpcodes[z].flags & MO_DFPU) && !(arch.flags & MO_DFPU))
8328
continue;
8329
8330
if (decodeOpcode(stringValue,MipsOpcodes[z]) == true)
8331
{
8332
TokenizerPosition tokenPos = parser.getTokenizer()->getPosition();
8333
8334
if (parseParameters(parser,MipsOpcodes[z]) == true)
8335
{
8336
// success, return opcode
8337
return ::make_unique<CMipsInstruction>(opcodeData,immediate,registers);
8338
}
8339
8340
parser.getTokenizer()->setPosition(tokenPos);
8341
paramFail = true;
8342
}
8343
}
8344
8345
if (paramFail == true)
8346
parser.printError(token,L"MIPS parameter failure");
8347
else
8348
parser.printError(token,L"Invalid MIPS opcode '%s'",stringValue);
8349
8350
return nullptr;
8351
}
8352
8353
bool MipsParser::parseMacroParameters(Parser& parser, const MipsMacroDefinition& macro)
8354
{
8355
const wchar_t* encoding = (const wchar_t*) macro.args;
8356
8357
while (*encoding != 0)
8358
{
8359
switch (*encoding++)
8360
{
8361
case 't': // register
8362
CHECK(parseRegister(parser,registers.grt));
8363
break;
8364
case 'd': // register
8365
CHECK(parseRegister(parser,registers.grd));
8366
break;
8367
case 's': // register
8368
CHECK(parseRegister(parser,registers.grs));
8369
break;
8370
case 'S': // register
8371
CHECK(parseFpuRegister(parser,registers.frs));
8372
break;
8373
case 'i': // primary immediate
8374
allowFunctionCallExpression(*encoding != '(');
8375
CHECK(parseImmediate(parser,immediate.primary.expression));
8376
allowFunctionCallExpression(true);
8377
break;
8378
case 'I': // secondary immediate
8379
allowFunctionCallExpression(*encoding != '(');
8380
CHECK(parseImmediate(parser,immediate.secondary.expression));
8381
allowFunctionCallExpression(true);
8382
break;
8383
default:
8384
CHECK(matchSymbol(parser,*(encoding-1)));
8385
break;
8386
}
8387
}
8388
8389
// lw rx,imm is a prefix of lw rx,imm(ry)
8390
if (parser.peekToken().type == TokenType::LParen)
8391
return false;
8392
8393
// the next token has to be a separator, else the parameters aren't
8394
// completely parsed
8395
return parser.nextToken().type == TokenType::Separator;
8396
}
8397
8398
std::unique_ptr<CAssemblerCommand> MipsParser::parseMacro(Parser& parser)
8399
{
8400
TokenizerPosition startPos = parser.getTokenizer()->getPosition();
8401
8402
// Cannot be a reference (we eat below.)
8403
const Token token = parser.peekToken();
8404
if (token.type != TokenType::Identifier)
8405
return nullptr;
8406
8407
parser.eatToken();
8408
const std::wstring stringValue = token.getStringValue();
8409
for (int z = 0; mipsMacros[z].name != nullptr; z++)
8410
{
8411
if (stringValue == mipsMacros[z].name)
8412
{
8413
TokenizerPosition tokenPos = parser.getTokenizer()->getPosition();
8414
8415
if (parseMacroParameters(parser,mipsMacros[z]) == true)
8416
{
8417
return mipsMacros[z].function(parser,registers,immediate,mipsMacros[z].flags);
8418
}
8419
8420
parser.getTokenizer()->setPosition(tokenPos);
8421
}
8422
}
8423
8424
// no matching macro found, restore state
8425
parser.getTokenizer()->setPosition(startPos);
8426
return nullptr;
8427
}
8428
8429
void MipsOpcodeFormatter::handleOpcodeName(const MipsOpcodeData& opData)
8430
{
8431
const char* encoding = opData.opcode.name;
8432
8433
while (*encoding != 0)
8434
{
8435
switch (*encoding++)
8436
{
8437
case 'S':
8438
buffer += "sptq"[opData.vfpuSize];
8439
break;
8440
case 'B':
8441
// TODO
8442
break;
8443
default:
8444
buffer += *(encoding-1);
8445
break;
8446
}
8447
}
8448
}
8449
8450
void MipsOpcodeFormatter::handleImmediate(MipsImmediateType type, unsigned int originalValue, unsigned int opcodeFlags)
8451
{
8452
switch (type)
8453
{
8454
case MipsImmediateType::ImmediateHalfFloat:
8455
buffer += formatString(L"%f", bitsToFloat(originalValue));
8456
break;
8457
case MipsImmediateType::Immediate16:
8458
if (!(opcodeFlags & MO_IPCR) && originalValue & 0x8000)
8459
buffer += formatString(L"-0x%X", 0x10000-(originalValue & 0xFFFF));
8460
else
8461
buffer += formatString(L"0x%X", originalValue);
8462
break;
8463
default:
8464
buffer += formatString(L"0x%X", originalValue);
8465
break;
8466
}
8467
}
8468
8469
void MipsOpcodeFormatter::handleOpcodeParameters(const MipsOpcodeData& opData, const MipsRegisterData& regData,
8470
const MipsImmediateData& immData)
8471
{
8472
const char* encoding = opData.opcode.encoding;
8473
8474
MipsImmediateType type;
8475
while (*encoding != 0)
8476
{
8477
switch (*encoding++)
8478
{
8479
case 'r': // forced register
8480
buffer += formatString(L"r%d",*encoding);
8481
encoding += 1;
8482
break;
8483
case 's': // register
8484
buffer += regData.grs.name;
8485
break;
8486
case 'd': // register
8487
buffer += regData.grd.name;
8488
break;
8489
case 't': // register
8490
buffer += regData.grt.name;
8491
break;
8492
case 'S': // fpu register
8493
buffer += regData.frs.name;
8494
break;
8495
case 'D': // fpu register
8496
buffer += regData.frd.name;
8497
break;
8498
case 'T': // fpu register
8499
buffer += regData.frt.name;
8500
break;
8501
case 'v': // psp vfpu reg
8502
case 'm': // vfpu matrix register
8503
switch (*encoding++)
8504
{
8505
case 'd':
8506
buffer += regData.vrd.name;
8507
break;
8508
case 's':
8509
buffer += regData.vrs.name;
8510
break;
8511
case 't':
8512
buffer += regData.vrt.name;
8513
break;
8514
}
8515
break;
8516
case 'V': // ps2 vector reg
8517
switch (*encoding++)
8518
{
8519
case 'd':
8520
buffer += regData.ps2vrd.name;
8521
break;
8522
case 's':
8523
buffer += regData.ps2vrs.name;
8524
break;
8525
case 't':
8526
buffer += regData.ps2vrt.name;
8527
break;
8528
}
8529
break;
8530
case 'i': // primary immediate
8531
decodeImmediateSize(encoding,type);
8532
handleImmediate(immData.primary.type,immData.primary.originalValue,opData.opcode.flags);
8533
break;
8534
case 'j': // secondary immediate
8535
handleImmediate(immData.secondary.type,immData.secondary.originalValue, opData.opcode.flags);
8536
encoding++;
8537
break;
8538
case 'C': // vfpu condition
8539
case 'W': // vfpu argument
8540
// TODO
8541
break;
8542
case 'w': // 'wb' characters
8543
buffer += L"wb";
8544
break;
8545
default:
8546
buffer += *(encoding-1);
8547
break;
8548
}
8549
}
8550
}
8551
8552
const std::wstring& MipsOpcodeFormatter::formatOpcode(const MipsOpcodeData& opData, const MipsRegisterData& regData,
8553
const MipsImmediateData& immData)
8554
{
8555
buffer = L" ";
8556
handleOpcodeName(opData);
8557
8558
while (buffer.size() < 11)
8559
buffer += ' ';
8560
8561
handleOpcodeParameters(opData,regData,immData);
8562
return buffer;
8563
}
8564
8565
// file: Archs/MIPS/PsxRelocator.cpp
8566
#include <map>
8567
8568
struct PsxLibEntry
8569
{
8570
std::wstring name;
8571
ByteArray data;
8572
};
8573
8574
const unsigned char psxObjectFileMagicNum[6] = { 'L', 'N', 'K', '\x02', '\x2E', '\x07' };
8575
8576
std::vector<PsxLibEntry> loadPsxLibrary(const std::wstring& inputName)
8577
{
8578
ByteArray input = ByteArray::fromFile(inputName);
8579
std::vector<PsxLibEntry> result;
8580
8581
if (input.size() == 0)
8582
return result;
8583
8584
if (memcmp(input.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) == 0)
8585
{
8586
PsxLibEntry entry;
8587
entry.name = getFileNameFromPath(inputName);
8588
entry.data = input;
8589
result.push_back(entry);
8590
return result;
8591
}
8592
8593
if (memcmp(input.data(),"LIB\x01",4) != 0)
8594
return result;
8595
8596
size_t pos = 4;
8597
while (pos < input.size())
8598
{
8599
PsxLibEntry entry;
8600
8601
for (int i = 0; i < 16 && input[pos+i] != ' '; i++)
8602
{
8603
entry.name += input[pos+i];
8604
}
8605
8606
int size = input.getDoubleWord(pos+16);
8607
int skip = 20;
8608
8609
while (input[pos+skip] != 0)
8610
{
8611
skip += 1+input[pos+skip];
8612
}
8613
8614
skip++;
8615
8616
entry.data = input.mid(pos+skip,size-skip);
8617
pos += size;
8618
8619
result.push_back(entry);
8620
}
8621
8622
return result;
8623
}
8624
8625
size_t PsxRelocator::loadString(ByteArray& data, size_t pos, std::wstring& dest)
8626
{
8627
dest = L"";
8628
int len = data[pos++];
8629
8630
for (int i = 0; i < len; i++)
8631
{
8632
dest += data[pos++];
8633
}
8634
8635
return len+1;
8636
}
8637
8638
bool PsxRelocator::parseObject(ByteArray data, PsxRelocatorFile& dest)
8639
{
8640
if (memcmp(data.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) != 0)
8641
return false;
8642
8643
size_t pos = 6;
8644
8645
std::vector<PsxSegment>& segments = dest.segments;
8646
std::vector<PsxSymbol>& syms = dest.symbols;
8647
8648
int activeSegment = -1;
8649
int lastSegmentPartStart = -1;
8650
while (pos < data.size())
8651
{
8652
switch (data[pos])
8653
{
8654
case 0x10: // segment definition
8655
{
8656
PsxSegment seg;
8657
seg.id = data.getDoubleWord(pos+1);
8658
segments.push_back(seg);
8659
pos += 5;
8660
8661
if (data[pos] != 8)
8662
return false;
8663
8664
std::wstring& name = segments[segments.size()-1].name;
8665
pos += 1 + loadString(data,pos+1,name);
8666
}
8667
break;
8668
case 0x14: // group?
8669
pos += data[pos+4]+5;
8670
break;
8671
case 0x1C: // source file name
8672
pos += data[pos+3]+4;
8673
break;
8674
8675
case 0x06: // set segment id
8676
{
8677
int id = data.getWord(pos+1);
8678
pos += 3;
8679
8680
int num = -1;
8681
for (size_t i = 0; i < segments.size(); i++)
8682
{
8683
if (segments[i].id == id)
8684
{
8685
num = (int) i;
8686
break;
8687
}
8688
}
8689
8690
activeSegment = num;
8691
}
8692
break;
8693
case 0x02: // append to data segment
8694
{
8695
int size = data.getWord(pos+1);
8696
pos += 3;
8697
8698
ByteArray d = data.mid(pos,size);
8699
pos += size;
8700
8701
lastSegmentPartStart = (int) segments[activeSegment].data.size();
8702
segments[activeSegment].data.append(d);
8703
}
8704
break;
8705
case 0x08: // append zeroes data segment
8706
{
8707
int size = data.getWord(pos+1);
8708
pos += 3;
8709
8710
ByteArray d;
8711
d.reserveBytes(size);
8712
segments[activeSegment].data.append(d);
8713
}
8714
break;
8715
case 0x0A: // relocation data
8716
{
8717
int type = data[pos+1];
8718
pos += 2;
8719
8720
PsxRelocation rel;
8721
rel.relativeOffset = 0;
8722
rel.filePos = (int) pos-2;
8723
8724
switch (type)
8725
{
8726
case 0x10: // 32 bit word
8727
rel.type = PsxRelocationType::WordLiteral;
8728
rel.segmentOffset = data.getWord(pos);
8729
pos += 2;
8730
break;
8731
case 0x4A: // jal
8732
rel.type = PsxRelocationType::FunctionCall;
8733
rel.segmentOffset = data.getWord(pos);
8734
pos += 2;
8735
break;
8736
case 0x52: // upper immerdiate
8737
rel.type = PsxRelocationType::UpperImmediate;
8738
rel.segmentOffset = data.getWord(pos);
8739
pos += 2;
8740
break;
8741
case 0x54: // lower immediate (add)
8742
rel.type = PsxRelocationType::LowerImmediate;
8743
rel.segmentOffset = data.getWord(pos);
8744
pos += 2;
8745
break;
8746
default:
8747
return false;
8748
}
8749
8750
rel.segmentOffset += lastSegmentPartStart;
8751
checkothertype:
8752
int otherType = data[pos++];
8753
switch (otherType)
8754
{
8755
case 0x02: // reference to symbol with id num
8756
rel.refType = PsxRelocationRefType::SymblId;
8757
rel.referenceId = data.getWord(pos);
8758
pos += 2;
8759
break;
8760
case 0x2C: // ref to other segment?
8761
rel.refType = PsxRelocationRefType::SegmentOffset;
8762
8763
switch (data[pos++])
8764
{
8765
case 0x00:
8766
rel.relativeOffset = data.getDoubleWord(pos);
8767
pos += 4;
8768
goto checkothertype;
8769
case 0x04:
8770
rel.referenceId = data.getWord(pos); // segment id
8771
pos += 2;
8772
8773
if (data[pos++] != 0x00)
8774
{
8775
return false;
8776
}
8777
8778
rel.referencePos = data.getDoubleWord(pos);
8779
pos += 4;
8780
break;
8781
default:
8782
return false;
8783
}
8784
break;
8785
case 0x2E: // negative ref?
8786
rel.refType = PsxRelocationRefType::SegmentOffset;
8787
8788
switch (data[pos++])
8789
{
8790
case 0x00:
8791
rel.relativeOffset = -data.getDoubleWord(pos);
8792
pos += 4;
8793
goto checkothertype;
8794
default:
8795
return false;
8796
}
8797
break;
8798
default:
8799
return false;
8800
}
8801
8802
segments[activeSegment].relocations.push_back(rel);
8803
}
8804
break;
8805
case 0x12: // internal symbol
8806
{
8807
PsxSymbol sym;
8808
sym.type = PsxSymbolType::Internal;
8809
sym.segment = data.getWord(pos+1);
8810
sym.offset = data.getDoubleWord(pos+3);
8811
pos += 7 + loadString(data,pos+7,sym.name);
8812
syms.push_back(sym);
8813
}
8814
break;
8815
case 0x0E: // external symbol
8816
{
8817
PsxSymbol sym;
8818
sym.type = PsxSymbolType::External;
8819
sym.id = data.getWord(pos+1);
8820
pos += 3 + loadString(data,pos+3,sym.name);
8821
syms.push_back(sym);
8822
}
8823
break;
8824
case 0x30: // bss symbol?
8825
{
8826
PsxSymbol sym;
8827
sym.type = PsxSymbolType::BSS;
8828
sym.id = data.getWord(pos+1);
8829
sym.segment = data.getWord(pos+3);
8830
sym.size = data.getDoubleWord(pos+5);
8831
pos += 9 + loadString(data,pos+9,sym.name);
8832
syms.push_back(sym);
8833
}
8834
break;
8835
case 0x0C: // internal with id
8836
{
8837
PsxSymbol sym;
8838
sym.type = PsxSymbolType::InternalID;
8839
sym.id = data.getWord(pos+1);
8840
sym.segment = data.getWord(pos+3);
8841
sym.offset = data.getDoubleWord(pos+5);
8842
pos += 9 + loadString(data,pos+9,sym.name);
8843
syms.push_back(sym);
8844
}
8845
break;
8846
case 0x4A: // function
8847
{
8848
PsxSymbol sym;
8849
sym.type = PsxSymbolType::Function;
8850
sym.segment = data.getWord(pos+1);
8851
sym.offset = data.getDoubleWord(pos+3);
8852
pos += 0x1D + loadString(data,pos+0x1D,sym.name);
8853
syms.push_back(sym);
8854
}
8855
break;
8856
case 0x4C: // function size
8857
pos += 11;
8858
break;
8859
case 0x3C: // ??
8860
pos += 3;
8861
break;
8862
case 0x00: // ??
8863
pos++;
8864
break;
8865
case 0x32: // ??
8866
pos += 3;
8867
break;
8868
case 0x3A: // ??
8869
pos += 9;
8870
break;
8871
default:
8872
return false;
8873
}
8874
}
8875
8876
return true;
8877
}
8878
8879
bool PsxRelocator::init(const std::wstring& inputName)
8880
{
8881
auto inputFiles = loadPsxLibrary(inputName);
8882
if (inputFiles.size() == 0)
8883
{
8884
Logger::printError(Logger::Error,L"Could not load library");
8885
return false;
8886
}
8887
8888
reloc = new MipsElfRelocator();
8889
8890
for (PsxLibEntry& entry: inputFiles)
8891
{
8892
PsxRelocatorFile file;
8893
file.name = entry.name;
8894
8895
if (parseObject(entry.data,file) == false)
8896
{
8897
Logger::printError(Logger::Error,L"Could not load object file %s",entry.name);
8898
return false;
8899
}
8900
8901
// init symbols
8902
for (PsxSymbol& sym: file.symbols)
8903
{
8904
std::wstring lowered = sym.name;
8905
std::transform(lowered.begin(), lowered.end(), lowered.begin(), ::towlower);
8906
8907
sym.label = Global.symbolTable.getLabel(lowered,-1,-1);
8908
if (sym.label == nullptr)
8909
{
8910
Logger::printError(Logger::Error,L"Invalid label name \"%s\"",sym.name);
8911
continue;
8912
}
8913
8914
if (sym.label->isDefined() && sym.type != PsxSymbolType::External)
8915
{
8916
Logger::printError(Logger::Error,L"Label \"%s\" already defined",sym.name);
8917
continue;
8918
}
8919
8920
sym.label->setOriginalName(sym.name);
8921
}
8922
8923
files.push_back(file);
8924
}
8925
8926
return true;
8927
}
8928
8929
bool PsxRelocator::relocateFile(PsxRelocatorFile& file, int& relocationAddress)
8930
{
8931
std::map<int,int> relocationOffsets;
8932
std::map<int,int> symbolOffsets;
8933
int start = relocationAddress;
8934
8935
// assign addresses to segments
8936
for (PsxSegment& seg: file.segments)
8937
{
8938
int index = seg.id;
8939
size_t size = seg.data.size();
8940
8941
relocationOffsets[index] = relocationAddress;
8942
relocationAddress += (int) size;
8943
8944
while (relocationAddress % 4)
8945
relocationAddress++;
8946
}
8947
8948
// parse/add/relocate symbols
8949
bool error = false;
8950
for (PsxSymbol& sym: file.symbols)
8951
{
8952
int pos;
8953
switch (sym.type)
8954
{
8955
case PsxSymbolType::Internal:
8956
case PsxSymbolType::Function:
8957
sym.label->setValue(relocationOffsets[sym.segment]+sym.offset);
8958
sym.label->setDefined(true);
8959
break;
8960
case PsxSymbolType::InternalID:
8961
pos = relocationOffsets[sym.segment]+sym.offset;
8962
sym.label->setValue(pos);
8963
sym.label->setDefined(true);
8964
symbolOffsets[sym.id] = pos;
8965
break;
8966
case PsxSymbolType::BSS:
8967
sym.label->setValue(relocationAddress);
8968
sym.label->setDefined(true);
8969
symbolOffsets[sym.id] = relocationAddress;
8970
relocationAddress += sym.size;
8971
8972
while (relocationAddress % 4)
8973
relocationAddress++;
8974
break;
8975
case PsxSymbolType::External:
8976
if (sym.label->isDefined() == false)
8977
{
8978
Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",sym.name,file.name);
8979
error = true;
8980
continue;
8981
}
8982
8983
symbolOffsets[sym.id] = (int) sym.label->getValue();
8984
break;
8985
}
8986
}
8987
8988
if (error)
8989
return false;
8990
8991
size_t dataStart = outputData.size();
8992
outputData.reserveBytes(relocationAddress-start);
8993
8994
// load code and data
8995
for (PsxSegment& seg: file.segments)
8996
{
8997
// relocate
8998
ByteArray sectionData = seg.data;
8999
9000
std::vector<RelocationAction> relocationActions;
9001
for (PsxRelocation& rel: seg.relocations)
9002
{
9003
RelocationData relData;
9004
int pos = rel.segmentOffset;
9005
relData.opcodeOffset = pos;
9006
relData.opcode = sectionData.getDoubleWord(pos);
9007
9008
switch (rel.refType)
9009
{
9010
case PsxRelocationRefType::SymblId:
9011
relData.relocationBase = symbolOffsets[rel.referenceId]+rel.relativeOffset;
9012
break;
9013
case PsxRelocationRefType::SegmentOffset:
9014
relData.relocationBase = relocationOffsets[rel.referenceId] + rel.referencePos+rel.relativeOffset;
9015
break;
9016
}
9017
9018
std::vector<std::wstring> errors;
9019
bool result = false;
9020
9021
switch (rel.type)
9022
{
9023
case PsxRelocationType::WordLiteral:
9024
result = reloc->relocateOpcode(R_MIPS_32,relData, relocationActions, errors);
9025
break;
9026
case PsxRelocationType::UpperImmediate:
9027
result = reloc->relocateOpcode(R_MIPS_HI16,relData, relocationActions, errors);
9028
break;
9029
case PsxRelocationType::LowerImmediate:
9030
result = reloc->relocateOpcode(R_MIPS_LO16,relData, relocationActions, errors);
9031
break;
9032
case PsxRelocationType::FunctionCall:
9033
result = reloc->relocateOpcode(R_MIPS_26,relData, relocationActions, errors);
9034
break;
9035
}
9036
9037
if (!result)
9038
{
9039
for (const std::wstring& error : errors)
9040
{
9041
Logger::queueError(Logger::Error, error);
9042
}
9043
error = true;
9044
}
9045
}
9046
9047
// finish any dangling relocations
9048
std::vector<std::wstring> errors;
9049
if (!reloc->finish(relocationActions, errors))
9050
{
9051
for (const std::wstring& error : errors)
9052
{
9053
Logger::queueError(Logger::Error, error);
9054
}
9055
error = true;
9056
}
9057
9058
// now actually write the relocated values
9059
for (const RelocationAction& action : relocationActions)
9060
{
9061
sectionData.replaceDoubleWord(action.offset, action.newValue);
9062
}
9063
9064
size_t arrayStart = dataStart+relocationOffsets[seg.id]-start;
9065
memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size());
9066
}
9067
9068
return !error;
9069
}
9070
9071
bool PsxRelocator::relocate(int& memoryAddress)
9072
{
9073
int oldCrc = getCrc32(outputData.data(),outputData.size());
9074
outputData.clear();
9075
dataChanged = false;
9076
9077
bool error = false;
9078
int start = memoryAddress;
9079
9080
for (PsxRelocatorFile& file: files)
9081
{
9082
if (relocateFile(file,memoryAddress) == false)
9083
error = true;
9084
}
9085
9086
int newCrc = getCrc32(outputData.data(),outputData.size());
9087
if (oldCrc != newCrc)
9088
dataChanged = true;
9089
9090
memoryAddress -= start;
9091
return !error;
9092
}
9093
9094
9095
void PsxRelocator::writeSymbols(SymbolData& symData) const
9096
{
9097
for (const PsxRelocatorFile& file: files)
9098
{
9099
for (const PsxSymbol& sym: file.symbols)
9100
{
9101
if (sym.type != PsxSymbolType::External)
9102
symData.addLabel(sym.label->getValue(),sym.name.c_str());
9103
}
9104
}
9105
}
9106
9107
//
9108
// DirectivePsxObjImport
9109
//
9110
9111
DirectivePsxObjImport::DirectivePsxObjImport(const std::wstring& fileName)
9112
{
9113
if (rel.init(fileName))
9114
{
9115
}
9116
}
9117
9118
bool DirectivePsxObjImport::Validate()
9119
{
9120
int memory = (int) g_fileManager->getVirtualAddress();
9121
rel.relocate(memory);
9122
g_fileManager->advanceMemory(memory);
9123
return rel.hasDataChanged();
9124
}
9125
9126
void DirectivePsxObjImport::Encode() const
9127
{
9128
const ByteArray& data = rel.getData();
9129
g_fileManager->write(data.data(),data.size());
9130
}
9131
9132
void DirectivePsxObjImport::writeSymData(SymbolData& symData) const
9133
{
9134
rel.writeSymbols(symData);
9135
}
9136
9137
// file: Archs/Architecture.cpp
9138
9139
CInvalidArchitecture InvalidArchitecture;
9140
9141
ArchitectureCommand::ArchitectureCommand(const std::wstring& tempText, const std::wstring& symText)
9142
{
9143
this->tempText = tempText;
9144
this->symText = symText;
9145
this->endianness = Arch->getEndianness();
9146
}
9147
9148
bool ArchitectureCommand::Validate()
9149
{
9150
position = g_fileManager->getVirtualAddress();
9151
g_fileManager->setEndianness(endianness);
9152
return false;
9153
}
9154
9155
void ArchitectureCommand::Encode() const
9156
{
9157
g_fileManager->setEndianness(endianness);
9158
}
9159
9160
void ArchitectureCommand::writeTempData(TempData& tempData) const
9161
{
9162
if (tempText.size() != 0)
9163
{
9164
std::wstringstream stream(tempText);
9165
9166
std::wstring line;
9167
while (std::getline(stream,line,L'\n'))
9168
{
9169
if (line.size() != 0)
9170
tempData.writeLine(position,line);
9171
}
9172
}
9173
}
9174
9175
void ArchitectureCommand::writeSymData(SymbolData& symData) const
9176
{
9177
// TODO: find a less ugly way to check for undefined memory positions
9178
if (position == -1)
9179
return;
9180
9181
if (symText.size() != 0)
9182
symData.addLabel(position,symText);
9183
}
9184
9185
9186
void CInvalidArchitecture::NextSection()
9187
{
9188
Logger::printError(Logger::FatalError,L"No architecture specified");
9189
}
9190
9191
void CInvalidArchitecture::Pass2()
9192
{
9193
Logger::printError(Logger::FatalError,L"No architecture specified");
9194
}
9195
9196
void CInvalidArchitecture::Revalidate()
9197
{
9198
Logger::printError(Logger::FatalError,L"No architecture specified");
9199
}
9200
9201
std::unique_ptr<IElfRelocator> CInvalidArchitecture::getElfRelocator()
9202
{
9203
Logger::printError(Logger::FatalError,L"No architecture specified");
9204
return nullptr;
9205
}
9206
9207
9208
// file: Commands/CAssemblerCommand.cpp
9209
9210
CAssemblerCommand::CAssemblerCommand()
9211
{
9212
FileNum = Global.FileInfo.FileNum;
9213
FileLine = Global.FileInfo.LineNumber;
9214
section = Global.Section;
9215
}
9216
9217
void CAssemblerCommand::applyFileInfo()
9218
{
9219
Global.FileInfo.FileNum = FileNum;
9220
Global.FileInfo.LineNumber = FileLine;
9221
}
9222
9223
// file: Commands/CAssemblerLabel.h
9224
9225
class Label;
9226
9227
class CAssemblerLabel: public CAssemblerCommand
9228
{
9229
public:
9230
CAssemblerLabel(const std::wstring& name, const std::wstring& originalName);
9231
CAssemblerLabel(const std::wstring& name, const std::wstring& originalName, Expression& value);
9232
virtual bool Validate();
9233
virtual void Encode() const;
9234
virtual void writeTempData(TempData& tempData) const;
9235
virtual void writeSymData(SymbolData& symData) const;
9236
private:
9237
Expression labelValue;
9238
std::shared_ptr<Label> label;
9239
bool defined;
9240
};
9241
9242
class CDirectiveFunction: public CAssemblerCommand
9243
{
9244
public:
9245
CDirectiveFunction(const std::wstring& name, const std::wstring& originalName);
9246
virtual bool Validate();
9247
virtual void Encode() const;
9248
virtual void writeTempData(TempData& tempData) const;
9249
virtual void writeSymData(SymbolData& symData) const;
9250
void setContent(std::unique_ptr<CAssemblerCommand> content) { this->content = std::move(content); }
9251
private:
9252
std::unique_ptr<CAssemblerLabel> label;
9253
std::unique_ptr<CAssemblerCommand> content;
9254
int64_t start, end;
9255
};
9256
9257
// file: Commands/CAssemblerLabel.cpp
9258
9259
CAssemblerLabel::CAssemblerLabel(const std::wstring& name, const std::wstring& originalName)
9260
{
9261
this->defined = false;
9262
this->label = nullptr;
9263
9264
if (Global.symbolTable.isLocalSymbol(name) == false)
9265
updateSection(++Global.Section);
9266
9267
label = Global.symbolTable.getLabel(name, FileNum, getSection());
9268
if (label == nullptr)
9269
{
9270
Logger::printError(Logger::Error, L"Invalid label name \"%s\"", name);
9271
return;
9272
}
9273
9274
label->setOriginalName(originalName);
9275
9276
// does this need to be in validate?
9277
if (label->getUpdateInfo())
9278
{
9279
#ifdef ARMIPS_ARM
9280
if (Arch == &Arm && Arm.GetThumbMode())
9281
label->setInfo(1);
9282
else
9283
#endif
9284
label->setInfo(0);
9285
}
9286
}
9287
9288
CAssemblerLabel::CAssemblerLabel(const std::wstring& name, const std::wstring& originalName, Expression& value)
9289
: CAssemblerLabel(name,originalName)
9290
{
9291
labelValue = value;
9292
}
9293
9294
bool CAssemblerLabel::Validate()
9295
{
9296
bool result = false;
9297
if (defined == false)
9298
{
9299
if (label->isDefined())
9300
{
9301
Logger::queueError(Logger::Error, L"Label \"%s\" already defined", label->getName());
9302
return false;
9303
}
9304
9305
label->setDefined(true);
9306
defined = true;
9307
result = true;
9308
}
9309
9310
bool hasPhysicalValue = false;
9311
int64_t virtualValue = 0;
9312
int64_t physicalValue = 0;
9313
9314
if (labelValue.isLoaded())
9315
{
9316
// label value is given by expression
9317
if (labelValue.evaluateInteger(virtualValue) == false)
9318
{
9319
Logger::printError(Logger::Error, L"Invalid expression");
9320
return result;
9321
}
9322
} else {
9323
// label value is given by current address
9324
virtualValue = g_fileManager->getVirtualAddress();
9325
physicalValue = g_fileManager->getPhysicalAddress();
9326
hasPhysicalValue = true;
9327
}
9328
9329
if (label->getValue() != virtualValue)
9330
{
9331
label->setValue(virtualValue);
9332
result = true;
9333
}
9334
9335
if (hasPhysicalValue && (!label->hasPhysicalValue() || physicalValue != label->getPhysicalValue()))
9336
{
9337
label->setPhysicalValue(physicalValue);
9338
result = true;
9339
}
9340
9341
return result;
9342
}
9343
9344
void CAssemblerLabel::Encode() const
9345
{
9346
9347
}
9348
9349
void CAssemblerLabel::writeTempData(TempData& tempData) const
9350
{
9351
if (Global.symbolTable.isGeneratedLabel(label->getName()) == false)
9352
tempData.writeLine(label->getValue(),formatString(L"%s:",label->getName()));
9353
}
9354
9355
void CAssemblerLabel::writeSymData(SymbolData& symData) const
9356
{
9357
// TODO: find a less ugly way to check for undefined memory positions
9358
if (label->getValue() == -1 || Global.symbolTable.isGeneratedLabel(label->getName()))
9359
return;
9360
9361
symData.addLabel(label->getValue(),label->getOriginalName());
9362
}
9363
9364
9365
9366
9367
CDirectiveFunction::CDirectiveFunction(const std::wstring& name, const std::wstring& originalName)
9368
{
9369
this->label = ::make_unique<CAssemblerLabel>(name,originalName);
9370
this->content = nullptr;
9371
this->start = this->end = 0;
9372
}
9373
9374
bool CDirectiveFunction::Validate()
9375
{
9376
start = g_fileManager->getVirtualAddress();
9377
9378
label->applyFileInfo();
9379
bool result = label->Validate();
9380
9381
content->applyFileInfo();
9382
if (content->Validate())
9383
result = true;
9384
9385
end = g_fileManager->getVirtualAddress();
9386
return result;
9387
}
9388
9389
void CDirectiveFunction::Encode() const
9390
{
9391
label->Encode();
9392
content->Encode();
9393
}
9394
9395
void CDirectiveFunction::writeTempData(TempData& tempData) const
9396
{
9397
label->writeTempData(tempData);
9398
content->applyFileInfo();
9399
content->writeTempData(tempData);
9400
}
9401
9402
void CDirectiveFunction::writeSymData(SymbolData& symData) const
9403
{
9404
symData.startFunction(start);
9405
label->writeSymData(symData);
9406
content->writeSymData(symData);
9407
symData.endFunction(end);
9408
}
9409
9410
// file: Commands/CDirectiveArea.h
9411
9412
class CDirectiveArea: public CAssemblerCommand
9413
{
9414
public:
9415
CDirectiveArea(Expression& size);
9416
virtual bool Validate();
9417
virtual void Encode() const;
9418
virtual void writeTempData(TempData& tempData) const;
9419
virtual void writeSymData(SymbolData& symData) const;
9420
void setFillExpression(Expression& exp);
9421
void setContent(std::unique_ptr<CAssemblerCommand> content) { this->content = std::move(content); }
9422
private:
9423
int64_t position;
9424
Expression sizeExpression;
9425
int64_t areaSize;
9426
int64_t contentSize;
9427
Expression fillExpression;
9428
int8_t fillValue;
9429
std::unique_ptr<CAssemblerCommand> content;
9430
};
9431
9432
// file: Commands/CDirectiveArea.cpp
9433
#include <algorithm>
9434
9435
CDirectiveArea::CDirectiveArea(Expression& size)
9436
{
9437
this->areaSize = 0;
9438
this->contentSize = 0;
9439
this->fillValue = 0;
9440
9441
this->sizeExpression = size;
9442
this->content = nullptr;
9443
}
9444
9445
void CDirectiveArea::setFillExpression(Expression& exp)
9446
{
9447
fillExpression = exp;
9448
}
9449
9450
bool CDirectiveArea::Validate()
9451
{
9452
int64_t oldAreaSize = areaSize;
9453
int64_t oldContentSize = contentSize;
9454
9455
position = g_fileManager->getVirtualAddress();
9456
9457
if (sizeExpression.evaluateInteger(areaSize) == false)
9458
{
9459
Logger::queueError(Logger::Error,L"Invalid size expression");
9460
return false;
9461
}
9462
9463
if (areaSize < 0)
9464
{
9465
Logger::queueError(Logger::Error, L"Negative area size");
9466
return false;
9467
}
9468
9469
if (fillExpression.isLoaded())
9470
{
9471
if (fillExpression.evaluateInteger(fillValue) == false)
9472
{
9473
Logger::queueError(Logger::Error,L"Invalid fill expression");
9474
return false;
9475
}
9476
}
9477
9478
content->applyFileInfo();
9479
bool result = content->Validate();
9480
contentSize = g_fileManager->getVirtualAddress()-position;
9481
9482
// restore info of this command
9483
applyFileInfo();
9484
9485
if (areaSize < contentSize)
9486
{
9487
Logger::queueError(Logger::Error,L"Area overflowed");
9488
}
9489
9490
if (fillExpression.isLoaded())
9491
g_fileManager->advanceMemory(areaSize-contentSize);
9492
9493
if (areaSize != oldAreaSize || contentSize != oldContentSize)
9494
result = true;
9495
9496
return result;
9497
}
9498
9499
void CDirectiveArea::Encode() const
9500
{
9501
content->Encode();
9502
9503
if (fillExpression.isLoaded())
9504
{
9505
unsigned char buffer[64];
9506
memset(buffer,fillValue,64);
9507
9508
size_t writeSize = areaSize-contentSize;
9509
while (writeSize > 0)
9510
{
9511
size_t part = std::min<size_t>(64,writeSize);
9512
g_fileManager->write(buffer,part);
9513
writeSize -= part;
9514
}
9515
}
9516
}
9517
9518
void CDirectiveArea::writeTempData(TempData& tempData) const
9519
{
9520
tempData.writeLine(position,formatString(L".area 0x%08X",areaSize));
9521
content->applyFileInfo();
9522
content->writeTempData(tempData);
9523
9524
if (fillExpression.isLoaded())
9525
{
9526
std::wstring fillString = formatString(L".fill 0x%08X,0x%02X",areaSize-contentSize,fillValue);
9527
tempData.writeLine(position+contentSize,fillString);
9528
tempData.writeLine(position+areaSize,L".endarea");
9529
} else {
9530
tempData.writeLine(position+contentSize,L".endarea");
9531
}
9532
}
9533
9534
void CDirectiveArea::writeSymData(SymbolData& symData) const
9535
{
9536
content->writeSymData(symData);
9537
9538
if (fillExpression.isLoaded())
9539
symData.addData(position+contentSize,areaSize-contentSize,SymbolData::Data8);
9540
}
9541
9542
// file: Commands/CDirectiveConditional.h
9543
9544
enum class ConditionType
9545
{
9546
IF,
9547
ELSE,
9548
ELSEIF,
9549
ENDIF,
9550
IFDEF,
9551
IFNDEF,
9552
};
9553
9554
class CDirectiveConditional: public CAssemblerCommand
9555
{
9556
public:
9557
CDirectiveConditional(ConditionType type);
9558
CDirectiveConditional(ConditionType type, const std::wstring& name);
9559
CDirectiveConditional(ConditionType type, const Expression& exp);
9560
virtual bool Validate();
9561
virtual void Encode() const;
9562
virtual void writeTempData(TempData& tempData) const;
9563
virtual void writeSymData(SymbolData& symData) const;
9564
void setContent(std::unique_ptr<CAssemblerCommand> ifBlock, std::unique_ptr<CAssemblerCommand> elseBlock);
9565
private:
9566
bool evaluate();
9567
9568
Expression expression;
9569
std::shared_ptr<Label> label;
9570
bool previousResult;
9571
9572
ConditionType type;
9573
std::unique_ptr<CAssemblerCommand> ifBlock;
9574
std::unique_ptr<CAssemblerCommand> elseBlock;
9575
};
9576
9577
// file: Commands/CDirectiveConditional.cpp
9578
9579
#ifdef ARMIPS_ARM
9580
extern CArmArchitecture Arm;
9581
#endif
9582
9583
CDirectiveConditional::CDirectiveConditional(ConditionType type)
9584
{
9585
this->type = type;
9586
9587
ifBlock = nullptr;
9588
elseBlock = nullptr;
9589
previousResult = false;
9590
}
9591
9592
CDirectiveConditional::CDirectiveConditional(ConditionType type, const std::wstring& name)
9593
: CDirectiveConditional(type)
9594
{
9595
label = Global.symbolTable.getLabel(name,Global.FileInfo.FileNum,Global.Section);
9596
if (label == nullptr)
9597
Logger::printError(Logger::Error,L"Invalid label name \"%s\"",name);
9598
}
9599
9600
CDirectiveConditional::CDirectiveConditional(ConditionType type, const Expression& exp)
9601
: CDirectiveConditional(type)
9602
{
9603
this->expression = exp;
9604
}
9605
9606
void CDirectiveConditional::setContent(std::unique_ptr<CAssemblerCommand> ifBlock, std::unique_ptr<CAssemblerCommand> elseBlock)
9607
{
9608
this->ifBlock = std::move(ifBlock);
9609
this->elseBlock = std::move(elseBlock);
9610
}
9611
9612
bool CDirectiveConditional::evaluate()
9613
{
9614
int64_t value;
9615
if (expression.isLoaded())
9616
{
9617
if (expression.evaluateInteger(value) == false)
9618
{
9619
Logger::queueError(Logger::Error,L"Invalid conditional expression");
9620
return false;
9621
}
9622
}
9623
9624
switch (type)
9625
{
9626
case ConditionType::IF:
9627
return value != 0;
9628
case ConditionType::IFDEF:
9629
return label->isDefined();
9630
case ConditionType::IFNDEF:
9631
return !label->isDefined();
9632
default:
9633
break;
9634
}
9635
9636
Logger::queueError(Logger::Error,L"Invalid conditional type");
9637
return false;
9638
}
9639
9640
bool CDirectiveConditional::Validate()
9641
{
9642
bool result = evaluate();
9643
bool returnValue = result != previousResult;
9644
previousResult = result;
9645
9646
if (result)
9647
{
9648
ifBlock->applyFileInfo();
9649
if (ifBlock->Validate())
9650
returnValue = true;
9651
} else if (elseBlock != nullptr)
9652
{
9653
elseBlock->applyFileInfo();
9654
if (elseBlock->Validate())
9655
returnValue = true;
9656
}
9657
9658
return returnValue;
9659
}
9660
9661
void CDirectiveConditional::Encode() const
9662
{
9663
if (previousResult)
9664
{
9665
ifBlock->Encode();
9666
} else if (elseBlock != nullptr)
9667
{
9668
elseBlock->Encode();
9669
}
9670
}
9671
9672
void CDirectiveConditional::writeTempData(TempData& tempData) const
9673
{
9674
if (previousResult)
9675
{
9676
ifBlock->applyFileInfo();
9677
ifBlock->writeTempData(tempData);
9678
} else if (elseBlock != nullptr)
9679
{
9680
elseBlock->applyFileInfo();
9681
elseBlock->writeTempData(tempData);
9682
}
9683
}
9684
9685
void CDirectiveConditional::writeSymData(SymbolData& symData) const
9686
{
9687
if (previousResult)
9688
{
9689
ifBlock->writeSymData(symData);
9690
} else if (elseBlock != nullptr)
9691
{
9692
elseBlock->writeSymData(symData);
9693
}
9694
}
9695
9696
// file: Commands/CDirectiveData.h
9697
9698
enum class EncodingMode { Invalid, U8, U16, U32, U64, Ascii, Float, Double, Sjis, Custom };
9699
9700
class TableCommand: public CAssemblerCommand
9701
{
9702
public:
9703
TableCommand(const std::wstring& fileName, TextFile::Encoding encoding);
9704
virtual bool Validate();
9705
virtual void Encode() const { };
9706
virtual void writeTempData(TempData& tempData) const { };
9707
virtual void writeSymData(SymbolData& symData) const { };
9708
private:
9709
EncodingTable table;
9710
};
9711
9712
class CDirectiveData: public CAssemblerCommand
9713
{
9714
public:
9715
CDirectiveData();
9716
~CDirectiveData();
9717
void setNormal(std::vector<Expression>& entries, size_t unitSize);
9718
void setFloat(std::vector<Expression>& entries);
9719
void setDouble(std::vector<Expression>& entries);
9720
void setAscii(std::vector<Expression>& entries, bool terminate);
9721
void setSjis(std::vector<Expression>& entries, bool terminate);
9722
void setCustom(std::vector<Expression>& entries, bool terminate);
9723
virtual bool Validate();
9724
virtual void Encode() const;
9725
virtual void writeTempData(TempData& tempData) const;
9726
virtual void writeSymData(SymbolData& symData) const;
9727
private:
9728
void encodeCustom(EncodingTable& table);
9729
void encodeSjis();
9730
void encodeFloat();
9731
void encodeDouble();
9732
void encodeNormal();
9733
size_t getUnitSize() const;
9734
size_t getDataSize() const;
9735
9736
int64_t position;
9737
EncodingMode mode;
9738
bool writeTermination;
9739
std::vector<Expression> entries;
9740
ByteArray customData;
9741
std::vector<int64_t> normalData;
9742
Endianness endianness;
9743
};
9744
9745
// file: Commands/CDirectiveData.cpp
9746
9747
//
9748
// TableCommand
9749
//
9750
9751
TableCommand::TableCommand(const std::wstring& fileName, TextFile::Encoding encoding)
9752
{
9753
auto fullName = getFullPathName(fileName);
9754
9755
if (fileExists(fullName) == false)
9756
{
9757
Logger::printError(Logger::Error,L"Table file \"%s\" does not exist",fileName);
9758
return;
9759
}
9760
9761
if (table.load(fullName,encoding) == false)
9762
{
9763
Logger::printError(Logger::Error,L"Invalid table file \"%s\"",fileName);
9764
return;
9765
}
9766
}
9767
9768
bool TableCommand::Validate()
9769
{
9770
Global.Table = table;
9771
return false;
9772
}
9773
9774
9775
//
9776
// CDirectiveData
9777
//
9778
9779
CDirectiveData::CDirectiveData()
9780
{
9781
mode = EncodingMode::Invalid;
9782
writeTermination = false;
9783
endianness = Arch->getEndianness();
9784
}
9785
9786
CDirectiveData::~CDirectiveData()
9787
{
9788
9789
}
9790
9791
void CDirectiveData::setNormal(std::vector<Expression>& entries, size_t unitSize)
9792
{
9793
switch (unitSize)
9794
{
9795
case 1:
9796
this->mode = EncodingMode::U8;
9797
break;
9798
case 2:
9799
this->mode = EncodingMode::U16;
9800
break;
9801
case 4:
9802
this->mode = EncodingMode::U32;
9803
break;
9804
case 8:
9805
this->mode = EncodingMode::U64;
9806
break;
9807
default:
9808
Logger::printError(Logger::Error,L"Invalid data unit size %d",unitSize);
9809
return;
9810
}
9811
9812
this->entries = entries;
9813
this->writeTermination = false;
9814
normalData.reserve(entries.size());
9815
}
9816
9817
void CDirectiveData::setFloat(std::vector<Expression>& entries)
9818
{
9819
this->mode = EncodingMode::Float;
9820
this->entries = entries;
9821
this->writeTermination = false;
9822
}
9823
9824
void CDirectiveData::setDouble(std::vector<Expression>& entries)
9825
{
9826
this->mode = EncodingMode::Double;
9827
this->entries = entries;
9828
this->writeTermination = false;
9829
}
9830
9831
void CDirectiveData::setAscii(std::vector<Expression>& entries, bool terminate)
9832
{
9833
this->mode = EncodingMode::Ascii;
9834
this->entries = entries;
9835
this->writeTermination = terminate;
9836
}
9837
9838
void CDirectiveData::setSjis(std::vector<Expression>& entries, bool terminate)
9839
{
9840
this->mode = EncodingMode::Sjis;
9841
this->entries = entries;
9842
this->writeTermination = terminate;
9843
}
9844
9845
void CDirectiveData::setCustom(std::vector<Expression>& entries, bool terminate)
9846
{
9847
this->mode = EncodingMode::Custom;
9848
this->entries = entries;
9849
this->writeTermination = terminate;
9850
}
9851
9852
size_t CDirectiveData::getUnitSize() const
9853
{
9854
switch (mode)
9855
{
9856
case EncodingMode::U8:
9857
case EncodingMode::Ascii:
9858
case EncodingMode::Sjis:
9859
case EncodingMode::Custom:
9860
return 1;
9861
case EncodingMode::U16:
9862
return 2;
9863
case EncodingMode::U32:
9864
case EncodingMode::Float:
9865
return 4;
9866
case EncodingMode::U64:
9867
case EncodingMode::Double:
9868
return 8;
9869
case EncodingMode::Invalid:
9870
break;
9871
}
9872
9873
return 0;
9874
}
9875
9876
size_t CDirectiveData::getDataSize() const
9877
{
9878
switch (mode)
9879
{
9880
case EncodingMode::Sjis:
9881
case EncodingMode::Custom:
9882
return customData.size();
9883
case EncodingMode::U8:
9884
case EncodingMode::Ascii:
9885
case EncodingMode::U16:
9886
case EncodingMode::U32:
9887
case EncodingMode::U64:
9888
case EncodingMode::Float:
9889
case EncodingMode::Double:
9890
return normalData.size()*getUnitSize();
9891
case EncodingMode::Invalid:
9892
break;
9893
}
9894
9895
return 0;
9896
}
9897
9898
void CDirectiveData::encodeCustom(EncodingTable& table)
9899
{
9900
customData.clear();
9901
for (size_t i = 0; i < entries.size(); i++)
9902
{
9903
ExpressionValue value = entries[i].evaluate();
9904
if (!value.isValid())
9905
{
9906
Logger::queueError(Logger::Error,L"Invalid expression");
9907
continue;
9908
}
9909
9910
if (value.isInt())
9911
{
9912
customData.appendByte(value.intValue);
9913
} else if (value.isString())
9914
{
9915
ByteArray encoded = table.encodeString(value.strValue,false);
9916
if (encoded.size() == 0 && value.strValue.size() > 0)
9917
{
9918
Logger::queueError(Logger::Error,L"Failed to encode \"%s\"",value.strValue);
9919
}
9920
customData.append(encoded);
9921
} else {
9922
Logger::queueError(Logger::Error,L"Invalid expression type");
9923
}
9924
}
9925
9926
if (writeTermination)
9927
{
9928
ByteArray encoded = table.encodeTermination();
9929
customData.append(encoded);
9930
}
9931
}
9932
9933
void CDirectiveData::encodeSjis()
9934
{
9935
static EncodingTable sjisTable;
9936
if (sjisTable.isLoaded() == false)
9937
{
9938
unsigned char hexBuffer[2];
9939
9940
sjisTable.setTerminationEntry((unsigned char*)"\0",1);
9941
9942
for (unsigned short SJISValue = 0x0001; SJISValue < 0x0100; SJISValue++)
9943
{
9944
wchar_t unicodeValue = sjisToUnicode(SJISValue);
9945
if (unicodeValue != 0xFFFF)
9946
{
9947
hexBuffer[0] = SJISValue & 0xFF;
9948
sjisTable.addEntry(hexBuffer, 1, unicodeValue);
9949
}
9950
}
9951
for (unsigned short SJISValue = 0x8100; SJISValue < 0xEF00; SJISValue++)
9952
{
9953
wchar_t unicodeValue = sjisToUnicode(SJISValue);
9954
if (unicodeValue != 0xFFFF)
9955
{
9956
hexBuffer[0] = (SJISValue >> 8) & 0xFF;
9957
hexBuffer[1] = SJISValue & 0xFF;
9958
sjisTable.addEntry(hexBuffer, 2, unicodeValue);
9959
}
9960
}
9961
}
9962
9963
encodeCustom(sjisTable);
9964
}
9965
9966
void CDirectiveData::encodeFloat()
9967
{
9968
normalData.clear();
9969
for (size_t i = 0; i < entries.size(); i++)
9970
{
9971
ExpressionValue value = entries[i].evaluate();
9972
if (!value.isValid())
9973
{
9974
Logger::queueError(Logger::Error,L"Invalid expression");
9975
continue;
9976
}
9977
9978
if (value.isInt() && mode == EncodingMode::Float)
9979
{
9980
int32_t num = getFloatBits((float)value.intValue);
9981
normalData.push_back(num);
9982
} else if (value.isInt() && mode == EncodingMode::Double)
9983
{
9984
int64_t num = getDoubleBits((double)value.intValue);
9985
normalData.push_back(num);
9986
} else if (value.isFloat() && mode == EncodingMode::Float)
9987
{
9988
int32_t num = getFloatBits((float)value.floatValue);
9989
normalData.push_back(num);
9990
} else if (value.isFloat() && mode == EncodingMode::Double)
9991
{
9992
int64_t num = getDoubleBits((double)value.floatValue);
9993
normalData.push_back(num);
9994
} else {
9995
Logger::queueError(Logger::Error,L"Invalid expression type");
9996
}
9997
}
9998
}
9999
10000
void CDirectiveData::encodeNormal()
10001
{
10002
normalData.clear();
10003
for (size_t i = 0; i < entries.size(); i++)
10004
{
10005
ExpressionValue value = entries[i].evaluate();
10006
if (!value.isValid())
10007
{
10008
Logger::queueError(Logger::Error,L"Invalid expression");
10009
continue;
10010
}
10011
10012
if (value.isString())
10013
{
10014
bool hadNonAscii = false;
10015
for (size_t l = 0; l < value.strValue.size(); l++)
10016
{
10017
int64_t num = value.strValue[l];
10018
normalData.push_back(num);
10019
10020
if (num >= 0x80 && hadNonAscii == false)
10021
{
10022
Logger::printError(Logger::Warning,L"Non-ASCII character in data directive. Use .string instead");
10023
hadNonAscii = true;
10024
}
10025
}
10026
} else if (value.isInt())
10027
{
10028
int64_t num = value.intValue;
10029
normalData.push_back(num);
10030
} else if (value.isFloat() && mode == EncodingMode::U32)
10031
{
10032
int32_t num = getFloatBits((float)value.floatValue);
10033
normalData.push_back(num);
10034
} else if(value.isFloat() && mode == EncodingMode::U64) {
10035
int64_t num = getDoubleBits((double)value.floatValue);
10036
normalData.push_back(num);
10037
} else {
10038
Logger::queueError(Logger::Error,L"Invalid expression type");
10039
}
10040
}
10041
10042
if (writeTermination)
10043
{
10044
normalData.push_back(0);
10045
}
10046
}
10047
10048
bool CDirectiveData::Validate()
10049
{
10050
position = g_fileManager->getVirtualAddress();
10051
10052
size_t oldSize = getDataSize();
10053
switch (mode)
10054
{
10055
case EncodingMode::U8:
10056
case EncodingMode::U16:
10057
case EncodingMode::U32:
10058
case EncodingMode::U64:
10059
case EncodingMode::Ascii:
10060
encodeNormal();
10061
break;
10062
case EncodingMode::Float:
10063
case EncodingMode::Double:
10064
encodeFloat();
10065
break;
10066
case EncodingMode::Sjis:
10067
encodeSjis();
10068
break;
10069
case EncodingMode::Custom:
10070
encodeCustom(Global.Table);
10071
break;
10072
default:
10073
Logger::queueError(Logger::Error,L"Invalid encoding type");
10074
break;
10075
}
10076
10077
g_fileManager->advanceMemory(getDataSize());
10078
return oldSize != getDataSize();
10079
}
10080
10081
void CDirectiveData::Encode() const
10082
{
10083
switch (mode)
10084
{
10085
case EncodingMode::Sjis:
10086
case EncodingMode::Custom:
10087
g_fileManager->write(customData.data(),customData.size());
10088
break;
10089
case EncodingMode::U8:
10090
case EncodingMode::Ascii:
10091
for (auto value: normalData)
10092
{
10093
g_fileManager->writeU8((uint8_t)value);
10094
}
10095
break;
10096
case EncodingMode::U16:
10097
for (auto value: normalData)
10098
{
10099
g_fileManager->writeU16((uint16_t)value);
10100
}
10101
break;
10102
case EncodingMode::U32:
10103
case EncodingMode::Float:
10104
for (auto value: normalData)
10105
{
10106
g_fileManager->writeU32((uint32_t)value);
10107
}
10108
break;
10109
case EncodingMode::U64:
10110
case EncodingMode::Double:
10111
for (auto value: normalData)
10112
{
10113
g_fileManager->writeU64((uint64_t)value);
10114
}
10115
break;
10116
case EncodingMode::Invalid:
10117
// TODO: Assert?
10118
break;
10119
}
10120
}
10121
10122
void CDirectiveData::writeTempData(TempData& tempData) const
10123
{
10124
size_t size = (getUnitSize()*2+3)*getDataSize()+20;
10125
wchar_t* str = new wchar_t[size];
10126
wchar_t* start = str;
10127
10128
switch (mode)
10129
{
10130
case EncodingMode::Sjis:
10131
case EncodingMode::Custom:
10132
str += swprintf(str,20,L".byte ");
10133
10134
for (size_t i = 0; i < customData.size(); i++)
10135
{
10136
str += swprintf(str,20,L"0x%02X,",(uint8_t)customData[i]);
10137
}
10138
break;
10139
case EncodingMode::U8:
10140
case EncodingMode::Ascii:
10141
str += swprintf(str,20,L".byte ");
10142
10143
for (size_t i = 0; i < normalData.size(); i++)
10144
{
10145
str += swprintf(str,20,L"0x%02X,",(uint8_t)normalData[i]);
10146
}
10147
break;
10148
case EncodingMode::U16:
10149
str += swprintf(str,20,L".halfword ");
10150
10151
for (size_t i = 0; i < normalData.size(); i++)
10152
{
10153
str += swprintf(str,20,L"0x%04X,",(uint16_t)normalData[i]);
10154
}
10155
break;
10156
case EncodingMode::U32:
10157
case EncodingMode::Float:
10158
str += swprintf(str,20,L".word ");
10159
10160
for (size_t i = 0; i < normalData.size(); i++)
10161
{
10162
str += swprintf(str,20,L"0x%08X,",(uint32_t)normalData[i]);
10163
}
10164
break;
10165
case EncodingMode::U64:
10166
case EncodingMode::Double:
10167
str += swprintf(str,20,L".doubleword ");
10168
10169
for (size_t i = 0; i < normalData.size(); i++)
10170
{
10171
str += swprintf(str,20,L"0x%16llX,",(uint64_t)normalData[i]);
10172
}
10173
break;
10174
case EncodingMode::Invalid:
10175
// TODO: Assert?
10176
break;
10177
}
10178
10179
*(str-1) = 0;
10180
tempData.writeLine(position,start);
10181
delete[] start;
10182
}
10183
10184
void CDirectiveData::writeSymData(SymbolData& symData) const
10185
{
10186
switch (mode)
10187
{
10188
case EncodingMode::Ascii:
10189
symData.addData(position,getDataSize(),SymbolData::DataAscii);
10190
break;
10191
case EncodingMode::U8:
10192
case EncodingMode::Sjis:
10193
case EncodingMode::Custom:
10194
symData.addData(position,getDataSize(),SymbolData::Data8);
10195
break;
10196
case EncodingMode::U16:
10197
symData.addData(position,getDataSize(),SymbolData::Data16);
10198
break;
10199
case EncodingMode::U32:
10200
case EncodingMode::Float:
10201
symData.addData(position,getDataSize(),SymbolData::Data32);
10202
break;
10203
case EncodingMode::U64:
10204
case EncodingMode::Double:
10205
symData.addData(position,getDataSize(),SymbolData::Data64);
10206
break;
10207
case EncodingMode::Invalid:
10208
// TODO: Assert?
10209
break;
10210
}
10211
}
10212
10213
// file: Commands/CDirectiveFile.cpp
10214
10215
//
10216
// CDirectiveFile
10217
//
10218
10219
CDirectiveFile::CDirectiveFile()
10220
{
10221
type = Type::Invalid;
10222
file = nullptr;
10223
}
10224
10225
void CDirectiveFile::initOpen(const std::wstring& fileName, int64_t memory)
10226
{
10227
type = Type::Open;
10228
std::wstring fullName = getFullPathName(fileName);
10229
10230
file = std::make_shared<GenericAssemblerFile>(fullName,memory,false);
10231
g_fileManager->addFile(file);
10232
10233
updateSection(++Global.Section);
10234
}
10235
10236
void CDirectiveFile::initCreate(const std::wstring& fileName, int64_t memory)
10237
{
10238
type = Type::Create;
10239
std::wstring fullName = getFullPathName(fileName);
10240
10241
file = std::make_shared<GenericAssemblerFile>(fullName,memory,true);
10242
g_fileManager->addFile(file);
10243
10244
updateSection(++Global.Section);
10245
}
10246
10247
void CDirectiveFile::initCopy(const std::wstring& inputName, const std::wstring& outputName, int64_t memory)
10248
{
10249
type = Type::Copy;
10250
std::wstring fullInputName = getFullPathName(inputName);
10251
std::wstring fullOutputName = getFullPathName(outputName);
10252
10253
file = std::make_shared<GenericAssemblerFile>(fullOutputName,fullInputName,memory);
10254
g_fileManager->addFile(file);
10255
10256
updateSection(++Global.Section);
10257
}
10258
10259
void CDirectiveFile::initClose()
10260
{
10261
type = Type::Close;
10262
updateSection(++Global.Section);
10263
}
10264
10265
bool CDirectiveFile::Validate()
10266
{
10267
virtualAddress = g_fileManager->getVirtualAddress();
10268
Arch->NextSection();
10269
10270
switch (type)
10271
{
10272
case Type::Open:
10273
case Type::Create:
10274
case Type::Copy:
10275
g_fileManager->openFile(file,true);
10276
return false;
10277
case Type::Close:
10278
closeFile = g_fileManager->getOpenFile();
10279
g_fileManager->closeFile();
10280
return false;
10281
case Type::Invalid:
10282
break;
10283
}
10284
10285
return false;
10286
}
10287
10288
void CDirectiveFile::Encode() const
10289
{
10290
switch (type)
10291
{
10292
case Type::Open:
10293
case Type::Create:
10294
case Type::Copy:
10295
g_fileManager->openFile(file,false);
10296
break;
10297
case Type::Close:
10298
g_fileManager->closeFile();
10299
break;
10300
case Type::Invalid:
10301
// TODO: Assert?
10302
break;
10303
}
10304
}
10305
10306
void CDirectiveFile::writeTempData(TempData& tempData) const
10307
{
10308
std::wstring str;
10309
10310
switch (type)
10311
{
10312
case Type::Open:
10313
str = formatString(L".open \"%s\",0x%08X",file->getFileName(),file->getOriginalHeaderSize());
10314
break;
10315
case Type::Create:
10316
str = formatString(L".create \"%s\",0x%08X",file->getFileName(),file->getOriginalHeaderSize());
10317
break;
10318
case Type::Copy:
10319
str = formatString(L".open \"%s\",\"%s\",0x%08X",file->getOriginalFileName(),
10320
file->getFileName(),file->getOriginalHeaderSize());
10321
break;
10322
case Type::Close:
10323
str = L".close";
10324
break;
10325
case Type::Invalid:
10326
// TODO: Assert?
10327
break;
10328
}
10329
10330
tempData.writeLine(virtualAddress,str);
10331
}
10332
10333
void CDirectiveFile::writeSymData(SymbolData& symData) const
10334
{
10335
switch (type)
10336
{
10337
case Type::Open:
10338
case Type::Create:
10339
case Type::Copy:
10340
file->beginSymData(symData);
10341
break;
10342
case Type::Close:
10343
if (closeFile)
10344
closeFile->endSymData(symData);
10345
break;
10346
case Type::Invalid:
10347
// TODO: Assert?
10348
break;
10349
}
10350
}
10351
10352
//
10353
// CDirectivePosition
10354
//
10355
10356
CDirectivePosition::CDirectivePosition(Expression expression, Type type)
10357
: expression(expression), type(type)
10358
{
10359
updateSection(++Global.Section);
10360
}
10361
10362
void CDirectivePosition::exec() const
10363
{
10364
switch (type)
10365
{
10366
case Physical:
10367
g_fileManager->seekPhysical(position);
10368
break;
10369
case Virtual:
10370
g_fileManager->seekVirtual(position);
10371
break;
10372
}
10373
}
10374
10375
bool CDirectivePosition::Validate()
10376
{
10377
virtualAddress = g_fileManager->getVirtualAddress();
10378
10379
if (expression.evaluateInteger(position) == false)
10380
{
10381
Logger::queueError(Logger::FatalError,L"Invalid position");
10382
return false;
10383
}
10384
10385
Arch->NextSection();
10386
exec();
10387
return false;
10388
}
10389
10390
void CDirectivePosition::Encode() const
10391
{
10392
Arch->NextSection();
10393
exec();
10394
}
10395
10396
void CDirectivePosition::writeTempData(TempData& tempData) const
10397
{
10398
switch (type)
10399
{
10400
case Physical:
10401
tempData.writeLine(virtualAddress,formatString(L".orga 0x%08X",position));
10402
break;
10403
case Virtual:
10404
tempData.writeLine(virtualAddress,formatString(L".org 0x%08X",position));
10405
break;
10406
}
10407
}
10408
10409
//
10410
// CDirectiveIncbin
10411
//
10412
10413
CDirectiveIncbin::CDirectiveIncbin(const std::wstring& fileName)
10414
: size(0), start(0)
10415
{
10416
this->fileName = getFullPathName(fileName);
10417
10418
if (fileExists(this->fileName) == false)
10419
{
10420
Logger::printError(Logger::FatalError,L"File %s not found",this->fileName);
10421
}
10422
10423
this->fileSize = ::fileSize(this->fileName);
10424
}
10425
10426
bool CDirectiveIncbin::Validate()
10427
{
10428
virtualAddress = g_fileManager->getVirtualAddress();
10429
10430
if (startExpression.isLoaded())
10431
{
10432
if (startExpression.evaluateInteger(start) == false)
10433
{
10434
Logger::queueError(Logger::Error,L"Invalid position expression");
10435
return false;
10436
}
10437
10438
if (start > fileSize)
10439
{
10440
Logger::queueError(Logger::Error,L"Start position past end of file");
10441
return false;
10442
}
10443
} else {
10444
start = 0;
10445
}
10446
10447
if (sizeExpression.isLoaded())
10448
{
10449
if (sizeExpression.evaluateInteger(size) == false)
10450
{
10451
Logger::queueError(Logger::Error,L"Invalid size expression");
10452
return false;
10453
}
10454
} else {
10455
size = fileSize-start;
10456
}
10457
10458
if (start+size > fileSize)
10459
{
10460
Logger::queueError(Logger::Warning,L"Read size truncated due to file size");
10461
size = fileSize-start;
10462
}
10463
10464
Arch->NextSection();
10465
g_fileManager->advanceMemory(size);
10466
return false;
10467
}
10468
10469
void CDirectiveIncbin::Encode() const
10470
{
10471
if (size != 0)
10472
{
10473
ByteArray data = ByteArray::fromFile(fileName,(long)start,size);
10474
if ((int) data.size() != size)
10475
{
10476
Logger::printError(Logger::Error,L"Could not read file \"%s\"",fileName);
10477
return;
10478
}
10479
g_fileManager->write(data.data(),data.size());
10480
}
10481
}
10482
10483
void CDirectiveIncbin::writeTempData(TempData& tempData) const
10484
{
10485
tempData.writeLine(virtualAddress,formatString(L".incbin \"%s\"",fileName));
10486
}
10487
10488
void CDirectiveIncbin::writeSymData(SymbolData& symData) const
10489
{
10490
symData.addData(virtualAddress,size,SymbolData::Data8);
10491
}
10492
10493
10494
//
10495
// CDirectiveAlignFill
10496
//
10497
10498
CDirectiveAlignFill::CDirectiveAlignFill(int64_t value, Mode mode)
10499
{
10500
this->mode = mode;
10501
this->value = value;
10502
this->finalSize = 0;
10503
this->fillByte = 0;
10504
}
10505
10506
CDirectiveAlignFill::CDirectiveAlignFill(Expression& value, Mode mode)
10507
: CDirectiveAlignFill(0,mode)
10508
{
10509
valueExpression = value;
10510
}
10511
10512
CDirectiveAlignFill::CDirectiveAlignFill(Expression& value, Expression& fillValue, Mode mode)
10513
: CDirectiveAlignFill(value,mode)
10514
{
10515
fillExpression = fillValue;
10516
}
10517
10518
bool CDirectiveAlignFill::Validate()
10519
{
10520
virtualAddress = g_fileManager->getVirtualAddress();
10521
10522
if (valueExpression.isLoaded())
10523
{
10524
if (valueExpression.evaluateInteger(value) == false)
10525
{
10526
Logger::queueError(Logger::FatalError,L"Invalid %s",mode == Fill ? L"size" : L"alignment");
10527
return false;
10528
}
10529
}
10530
10531
if (mode != Fill && isPowerOfTwo(value) == false)
10532
{
10533
Logger::queueError(Logger::Error, L"Invalid alignment %d", value);
10534
return false;
10535
}
10536
10537
int64_t oldSize = finalSize;
10538
int64_t mod;
10539
switch (mode)
10540
{
10541
case AlignVirtual:
10542
mod = g_fileManager->getVirtualAddress() % value;
10543
finalSize = mod ? value-mod : 0;
10544
break;
10545
case AlignPhysical:
10546
mod = g_fileManager->getPhysicalAddress() % value;
10547
finalSize = mod ? value-mod : 0;
10548
break;
10549
case Fill:
10550
finalSize = value;
10551
break;
10552
}
10553
10554
if (fillExpression.isLoaded())
10555
{
10556
if (fillExpression.evaluateInteger(fillByte) == false)
10557
{
10558
Logger::printError(Logger::FatalError,L"Invalid fill value");
10559
return false;
10560
}
10561
}
10562
10563
Arch->NextSection();
10564
g_fileManager->advanceMemory(finalSize);
10565
10566
bool result = oldSize != finalSize;
10567
oldSize = finalSize;
10568
return result;
10569
}
10570
10571
void CDirectiveAlignFill::Encode() const
10572
{
10573
unsigned char buffer[128];
10574
int64_t n = finalSize;
10575
10576
memset(buffer,fillByte,n > 128 ? 128 : n);
10577
while (n > 128)
10578
{
10579
g_fileManager->write(buffer,128);
10580
n -= 128;
10581
}
10582
10583
g_fileManager->write(buffer,n);
10584
}
10585
10586
void CDirectiveAlignFill::writeTempData(TempData& tempData) const
10587
{
10588
switch (mode)
10589
{
10590
case AlignVirtual:
10591
tempData.writeLine(virtualAddress,formatString(L".align 0x%08X",value));
10592
break;
10593
case AlignPhysical:
10594
tempData.writeLine(virtualAddress, formatString(L".aligna 0x%08X", value));
10595
break;
10596
case Fill:
10597
tempData.writeLine(virtualAddress,formatString(L".fill 0x%08X,0x%02X",value,fillByte));
10598
break;
10599
}
10600
}
10601
10602
void CDirectiveAlignFill::writeSymData(SymbolData& symData) const
10603
{
10604
switch (mode)
10605
{
10606
case AlignVirtual: // ?
10607
case AlignPhysical: // ?
10608
break;
10609
case Fill:
10610
symData.addData(virtualAddress,value,SymbolData::Data8);
10611
break;
10612
}
10613
}
10614
10615
//
10616
// CDirectiveSkip
10617
//
10618
10619
CDirectiveSkip::CDirectiveSkip(Expression& expression)
10620
: expression(expression) {}
10621
10622
bool CDirectiveSkip::Validate()
10623
{
10624
virtualAddress = g_fileManager->getVirtualAddress();
10625
10626
if (expression.isLoaded())
10627
{
10628
if (expression.evaluateInteger(value) == false)
10629
{
10630
Logger::queueError(Logger::FatalError,L"Invalid skip length");
10631
return false;
10632
}
10633
}
10634
10635
Arch->NextSection();
10636
g_fileManager->advanceMemory(value);
10637
10638
return false;
10639
}
10640
10641
void CDirectiveSkip::Encode() const
10642
{
10643
Arch->NextSection();
10644
g_fileManager->advanceMemory(value);
10645
}
10646
10647
void CDirectiveSkip::writeTempData(TempData& tempData) const
10648
{
10649
tempData.writeLine(virtualAddress,formatString(L".skip 0x%08X",value));
10650
}
10651
10652
//
10653
// CDirectiveHeaderSize
10654
//
10655
10656
CDirectiveHeaderSize::CDirectiveHeaderSize(Expression expression)
10657
: expression(expression) {}
10658
10659
void CDirectiveHeaderSize::exec() const
10660
{
10661
std::shared_ptr<AssemblerFile> openFile = g_fileManager->getOpenFile();
10662
if (!openFile->hasFixedVirtualAddress())
10663
{
10664
Logger::printError(Logger::Error,L"Header size not applicable for this file");
10665
return;
10666
}
10667
std::shared_ptr<GenericAssemblerFile> file = std::static_pointer_cast<GenericAssemblerFile>(openFile);
10668
int64_t physicalAddress = file->getPhysicalAddress();
10669
file->setHeaderSize(headerSize);
10670
file->seekPhysical(physicalAddress);
10671
}
10672
10673
bool CDirectiveHeaderSize::Validate()
10674
{
10675
virtualAddress = g_fileManager->getVirtualAddress();
10676
10677
if (expression.evaluateInteger(headerSize) == false)
10678
{
10679
Logger::queueError(Logger::FatalError,L"Invalid header size");
10680
return false;
10681
}
10682
10683
exec();
10684
return false;
10685
}
10686
10687
void CDirectiveHeaderSize::Encode() const
10688
{
10689
exec();
10690
}
10691
10692
void CDirectiveHeaderSize::writeTempData(TempData& tempData) const
10693
{
10694
tempData.writeLine(virtualAddress,formatString(L".headersize %s0x%08X",
10695
headerSize < 0 ? L"-" : L"", headerSize < 0 ? -headerSize : headerSize));
10696
}
10697
10698
10699
//
10700
// DirectiveObjImport
10701
//
10702
10703
DirectiveObjImport::DirectiveObjImport(const std::wstring& inputName)
10704
{
10705
ctor = nullptr;
10706
if (rel.init(inputName))
10707
{
10708
rel.exportSymbols();
10709
}
10710
}
10711
10712
DirectiveObjImport::DirectiveObjImport(const std::wstring& inputName, const std::wstring& ctorName)
10713
{
10714
if (rel.init(inputName))
10715
{
10716
rel.exportSymbols();
10717
ctor = rel.generateCtor(ctorName);
10718
}
10719
}
10720
10721
bool DirectiveObjImport::Validate()
10722
{
10723
bool result = false;
10724
if (ctor != nullptr && ctor->Validate())
10725
result = true;
10726
10727
int64_t memory = g_fileManager->getVirtualAddress();
10728
rel.relocate(memory);
10729
g_fileManager->advanceMemory((size_t)memory);
10730
10731
return rel.hasDataChanged() || result;
10732
}
10733
10734
void DirectiveObjImport::Encode() const
10735
{
10736
if (ctor != nullptr)
10737
ctor->Encode();
10738
10739
const ByteArray& data = rel.getData();
10740
g_fileManager->write(data.data(),data.size());
10741
}
10742
10743
void DirectiveObjImport::writeTempData(TempData& tempData) const
10744
{
10745
if (ctor != nullptr)
10746
ctor->writeTempData(tempData);
10747
}
10748
10749
void DirectiveObjImport::writeSymData(SymbolData& symData) const
10750
{
10751
if (ctor != nullptr)
10752
ctor->writeSymData(symData);
10753
10754
rel.writeSymbols(symData);
10755
}
10756
10757
// file: Commands/CDirectiveMessage.h
10758
10759
class CDirectiveMessage: public CAssemblerCommand
10760
{
10761
public:
10762
enum class Type { Warning, Error, Notice };
10763
CDirectiveMessage(Type type, Expression exp);
10764
virtual bool Validate();
10765
virtual void Encode() const {};
10766
virtual void writeTempData(TempData& tempData) const { };
10767
private:
10768
Type errorType;
10769
Expression exp;
10770
};
10771
10772
class CDirectiveSym: public CAssemblerCommand
10773
{
10774
public:
10775
CDirectiveSym(bool enable) {enabled = enable; };
10776
virtual bool Validate() { return false; };
10777
virtual void Encode() const { };
10778
virtual void writeTempData(TempData& tempData) const { };
10779
virtual void writeSymData(SymbolData& symData) const { symData.setEnabled(enabled); }
10780
private:
10781
bool enabled;
10782
};
10783
10784
// file: Commands/CDirectiveMessage.cpp
10785
10786
CDirectiveMessage::CDirectiveMessage(Type type, Expression exp)
10787
{
10788
errorType = type;
10789
this->exp = exp;
10790
}
10791
10792
bool CDirectiveMessage::Validate()
10793
{
10794
std::wstring text;
10795
if (exp.evaluateString(text,true) == false)
10796
{
10797
Logger::queueError(Logger::Error,L"Invalid expression");
10798
return false;
10799
}
10800
10801
switch (errorType)
10802
{
10803
case Type::Warning:
10804
Logger::queueError(Logger::Warning,text);
10805
break;
10806
case Type::Error:
10807
Logger::queueError(Logger::Error,text);
10808
break;
10809
case Type::Notice:
10810
Logger::queueError(Logger::Notice,text);
10811
break;
10812
}
10813
return false;
10814
}
10815
10816
// file: Commands/CommandSequence.cpp
10817
10818
CommandSequence::CommandSequence()
10819
: CAssemblerCommand()
10820
{
10821
10822
}
10823
10824
bool CommandSequence::Validate()
10825
{
10826
bool result = false;
10827
10828
for (const std::unique_ptr<CAssemblerCommand>& cmd: commands)
10829
{
10830
cmd->applyFileInfo();
10831
if (cmd->Validate())
10832
result = true;
10833
}
10834
10835
return result;
10836
}
10837
10838
void CommandSequence::Encode() const
10839
{
10840
for (const std::unique_ptr<CAssemblerCommand>& cmd: commands)
10841
{
10842
cmd->Encode();
10843
}
10844
}
10845
10846
void CommandSequence::writeTempData(TempData& tempData) const
10847
{
10848
for (const std::unique_ptr<CAssemblerCommand>& cmd: commands)
10849
{
10850
cmd->applyFileInfo();
10851
cmd->writeTempData(tempData);
10852
}
10853
}
10854
10855
void CommandSequence::writeSymData(SymbolData& symData) const
10856
{
10857
for (const std::unique_ptr<CAssemblerCommand>& cmd: commands)
10858
{
10859
cmd->writeSymData(symData);
10860
}
10861
}
10862
10863
// file: Parser/DirectivesParser.cpp
10864
10865
#include <initializer_list>
10866
#include <algorithm>
10867
10868
std::unique_ptr<CAssemblerCommand> parseDirectiveOpen(Parser& parser, int flags)
10869
{
10870
std::vector<Expression> list;
10871
if (parser.parseExpressionList(list,2,3) == false)
10872
return nullptr;
10873
10874
int64_t memoryAddress;
10875
std::wstring inputName, outputName;
10876
10877
if (list[0].evaluateString(inputName,false) == false)
10878
return nullptr;
10879
10880
if (list.back().evaluateInteger(memoryAddress) == false)
10881
return nullptr;
10882
10883
auto file = ::make_unique<CDirectiveFile>();
10884
if (list.size() == 3)
10885
{
10886
if (list[1].evaluateString(outputName,false) == false)
10887
return nullptr;
10888
10889
file->initCopy(inputName,outputName,memoryAddress);
10890
return file;
10891
} else {
10892
file->initOpen(inputName,memoryAddress);
10893
return file;
10894
}
10895
}
10896
10897
std::unique_ptr<CAssemblerCommand> parseDirectiveCreate(Parser& parser, int flags)
10898
{
10899
std::vector<Expression> list;
10900
if (parser.parseExpressionList(list,2,2) == false)
10901
return nullptr;
10902
10903
int64_t memoryAddress;
10904
std::wstring inputName, outputName;
10905
10906
if (list[0].evaluateString(inputName,false) == false)
10907
return nullptr;
10908
10909
if (list.back().evaluateInteger(memoryAddress) == false)
10910
return nullptr;
10911
10912
auto file = ::make_unique<CDirectiveFile>();
10913
file->initCreate(inputName,memoryAddress);
10914
return file;
10915
}
10916
10917
std::unique_ptr<CAssemblerCommand> parseDirectiveClose(Parser& parser, int flags)
10918
{
10919
auto file = ::make_unique<CDirectiveFile>();
10920
file->initClose();
10921
return file;
10922
}
10923
10924
std::unique_ptr<CAssemblerCommand> parseDirectiveIncbin(Parser& parser, int flags)
10925
{
10926
std::vector<Expression> list;
10927
if (parser.parseExpressionList(list,1,3) == false)
10928
return nullptr;
10929
10930
std::wstring fileName;
10931
if (list[0].evaluateString(fileName,false) == false)
10932
return nullptr;
10933
10934
auto incbin = ::make_unique<CDirectiveIncbin>(fileName);
10935
if (list.size() >= 2)
10936
incbin->setStart(list[1]);
10937
10938
if (list.size() == 3)
10939
incbin->setSize(list[2]);
10940
10941
return incbin;
10942
}
10943
10944
std::unique_ptr<CAssemblerCommand> parseDirectivePosition(Parser& parser, int flags)
10945
{
10946
Expression exp = parser.parseExpression();
10947
if (exp.isLoaded() == false)
10948
return nullptr;
10949
10950
CDirectivePosition::Type type;
10951
switch (flags & DIRECTIVE_USERMASK)
10952
{
10953
case DIRECTIVE_POS_PHYSICAL:
10954
type = CDirectivePosition::Physical;
10955
break;
10956
case DIRECTIVE_POS_VIRTUAL:
10957
type = CDirectivePosition::Virtual;
10958
break;
10959
default:
10960
return nullptr;
10961
}
10962
10963
return ::make_unique<CDirectivePosition>(exp,type);
10964
}
10965
10966
std::unique_ptr<CAssemblerCommand> parseDirectiveAlignFill(Parser& parser, int flags)
10967
{
10968
CDirectiveAlignFill::Mode mode;
10969
switch (flags & DIRECTIVE_USERMASK)
10970
{
10971
case DIRECTIVE_ALIGN_VIRTUAL:
10972
mode = CDirectiveAlignFill::AlignVirtual;
10973
break;
10974
case DIRECTIVE_ALIGN_PHYSICAL:
10975
mode = CDirectiveAlignFill::AlignPhysical;
10976
break;
10977
case DIRECTIVE_ALIGN_FILL:
10978
mode = CDirectiveAlignFill::Fill;
10979
break;
10980
default:
10981
return nullptr;
10982
}
10983
10984
if (mode != CDirectiveAlignFill::Fill && parser.peekToken().type == TokenType::Separator)
10985
return ::make_unique<CDirectiveAlignFill>(UINT64_C(4),mode);
10986
10987
std::vector<Expression> list;
10988
if (parser.parseExpressionList(list,1,2) == false)
10989
return nullptr;
10990
10991
if (list.size() == 2)
10992
return ::make_unique<CDirectiveAlignFill>(list[0],list[1],mode);
10993
else
10994
return ::make_unique<CDirectiveAlignFill>(list[0],mode);
10995
}
10996
10997
std::unique_ptr<CAssemblerCommand> parseDirectiveSkip(Parser& parser, int flags)
10998
{
10999
std::vector<Expression> list;
11000
if (parser.parseExpressionList(list,1,1) == false)
11001
return nullptr;
11002
11003
return ::make_unique<CDirectiveSkip>(list[0]);
11004
}
11005
11006
std::unique_ptr<CAssemblerCommand> parseDirectiveHeaderSize(Parser& parser, int flags)
11007
{
11008
Expression exp = parser.parseExpression();
11009
if (exp.isLoaded() == false)
11010
return nullptr;
11011
11012
return ::make_unique<CDirectiveHeaderSize>(exp);
11013
}
11014
11015
std::unique_ptr<CAssemblerCommand> parseDirectiveObjImport(Parser& parser, int flags)
11016
{
11017
std::vector<Expression> list;
11018
if (parser.parseExpressionList(list,1,2) == false)
11019
return nullptr;
11020
11021
std::wstring fileName;
11022
if (list[0].evaluateString(fileName,true) == false)
11023
return nullptr;
11024
11025
if (list.size() == 2)
11026
{
11027
std::wstring ctorName;
11028
if (list[1].evaluateIdentifier(ctorName) == false)
11029
return nullptr;
11030
11031
return ::make_unique<DirectiveObjImport>(fileName,ctorName);
11032
}
11033
11034
return ::make_unique<DirectiveObjImport>(fileName);
11035
}
11036
11037
std::unique_ptr<CAssemblerCommand> parseDirectiveConditional(Parser& parser, int flags)
11038
{
11039
ConditionType type;
11040
std::wstring name;
11041
Expression exp;
11042
11043
const Token& start = parser.peekToken();
11044
ConditionalResult condResult = ConditionalResult::Unknown;
11045
switch (flags)
11046
{
11047
case DIRECTIVE_COND_IF:
11048
type = ConditionType::IF;
11049
exp = parser.parseExpression();
11050
if (exp.isLoaded() == false)
11051
{
11052
parser.printError(start,L"Invalid condition");
11053
return ::make_unique<DummyCommand>();
11054
}
11055
11056
if (exp.isConstExpression())
11057
{
11058
ExpressionValue result = exp.evaluate();
11059
if (result.isInt())
11060
condResult = result.intValue != 0 ? ConditionalResult::True : ConditionalResult::False;
11061
}
11062
break;
11063
case DIRECTIVE_COND_IFDEF:
11064
type = ConditionType::IFDEF;
11065
if (parser.parseIdentifier(name) == false)
11066
return nullptr;
11067
break;
11068
case DIRECTIVE_COND_IFNDEF:
11069
type = ConditionType::IFNDEF;
11070
if (parser.parseIdentifier(name) == false)
11071
return nullptr;
11072
break;
11073
}
11074
11075
if(parser.nextToken().type != TokenType::Separator)
11076
{
11077
parser.printError(start,L"Directive not terminated");
11078
return nullptr;
11079
}
11080
11081
parser.pushConditionalResult(condResult);
11082
std::unique_ptr<CAssemblerCommand> ifBlock = parser.parseCommandSequence(L'.', {L".else", L".elseif", L".elseifdef", L".elseifndef", L".endif"});
11083
parser.popConditionalResult();
11084
11085
// update the file info so that else commands get the right line number
11086
parser.updateFileInfo();
11087
11088
std::unique_ptr<CAssemblerCommand> elseBlock = nullptr;
11089
const Token &next = parser.nextToken();
11090
const std::wstring stringValue = next.getStringValue();
11091
11092
ConditionalResult elseResult;
11093
switch (condResult)
11094
{
11095
case ConditionalResult::True:
11096
elseResult = ConditionalResult::False;
11097
break;
11098
case ConditionalResult::False:
11099
elseResult = ConditionalResult::True;
11100
break;
11101
case ConditionalResult::Unknown:
11102
elseResult = condResult;
11103
break;
11104
}
11105
11106
parser.pushConditionalResult(elseResult);
11107
if (stringValue == L".else")
11108
{
11109
elseBlock = parser.parseCommandSequence(L'.', {L".endif"});
11110
11111
parser.eatToken(); // eat .endif
11112
} else if (stringValue == L".elseif")
11113
{
11114
elseBlock = parseDirectiveConditional(parser,DIRECTIVE_COND_IF);
11115
} else if (stringValue == L".elseifdef")
11116
{
11117
elseBlock = parseDirectiveConditional(parser,DIRECTIVE_COND_IFDEF);
11118
} else if (stringValue == L".elseifndef")
11119
{
11120
elseBlock = parseDirectiveConditional(parser,DIRECTIVE_COND_IFNDEF);
11121
} else if (stringValue != L".endif")
11122
{
11123
parser.popConditionalResult();
11124
return nullptr;
11125
}
11126
11127
parser.popConditionalResult();
11128
11129
// for true or false blocks, there's no need to create a conditional command
11130
if (condResult == ConditionalResult::True)
11131
{
11132
return ifBlock;
11133
}
11134
11135
if (condResult == ConditionalResult::False)
11136
{
11137
if (elseBlock != nullptr)
11138
return elseBlock;
11139
else
11140
return ::make_unique<DummyCommand>();
11141
}
11142
11143
std::unique_ptr<CDirectiveConditional> cond;
11144
if (exp.isLoaded())
11145
cond = ::make_unique<CDirectiveConditional>(type,exp);
11146
else if (name.size() != 0)
11147
cond = ::make_unique<CDirectiveConditional>(type,name);
11148
else
11149
cond = ::make_unique<CDirectiveConditional>(type);
11150
11151
cond->setContent(std::move(ifBlock),std::move(elseBlock));
11152
return cond;
11153
}
11154
11155
std::unique_ptr<CAssemblerCommand> parseDirectiveTable(Parser& parser, int flags)
11156
{
11157
const Token& start = parser.peekToken();
11158
11159
std::vector<Expression> list;
11160
if (parser.parseExpressionList(list,1,2) == false)
11161
return nullptr;
11162
11163
std::wstring fileName;
11164
if (list[0].evaluateString(fileName,true) == false)
11165
{
11166
parser.printError(start,L"Invalid file name");
11167
return nullptr;
11168
}
11169
11170
TextFile::Encoding encoding = TextFile::GUESS;
11171
if (list.size() == 2)
11172
{
11173
std::wstring encodingName;
11174
if (list[1].evaluateString(encodingName,true) == false)
11175
{
11176
parser.printError(start,L"Invalid encoding name");
11177
return nullptr;
11178
}
11179
11180
encoding = getEncodingFromString(encodingName);
11181
}
11182
11183
return ::make_unique<TableCommand>(fileName,encoding);
11184
}
11185
11186
std::unique_ptr<CAssemblerCommand> parseDirectiveData(Parser& parser, int flags)
11187
{
11188
bool terminate = false;
11189
if (flags & DIRECTIVE_DATA_TERMINATION)
11190
{
11191
terminate = true;
11192
flags &= ~DIRECTIVE_DATA_TERMINATION;
11193
}
11194
11195
std::vector<Expression> list;
11196
if (parser.parseExpressionList(list,1,-1) == false)
11197
return nullptr;
11198
11199
auto data = ::make_unique<CDirectiveData>();
11200
switch (flags & DIRECTIVE_USERMASK)
11201
{
11202
case DIRECTIVE_DATA_8:
11203
data->setNormal(list,1);
11204
break;
11205
case DIRECTIVE_DATA_16:
11206
data->setNormal(list,2);
11207
break;
11208
case DIRECTIVE_DATA_32:
11209
data->setNormal(list,4);
11210
break;
11211
case DIRECTIVE_DATA_64:
11212
data->setNormal(list,8);
11213
break;
11214
case DIRECTIVE_DATA_ASCII:
11215
data->setAscii(list,terminate);
11216
break;
11217
case DIRECTIVE_DATA_SJIS:
11218
data->setSjis(list,terminate);
11219
break;
11220
case DIRECTIVE_DATA_CUSTOM:
11221
data->setCustom(list,terminate);
11222
break;
11223
case DIRECTIVE_DATA_FLOAT:
11224
data->setFloat(list);
11225
break;
11226
case DIRECTIVE_DATA_DOUBLE:
11227
data->setDouble(list);
11228
break;
11229
}
11230
11231
return data;
11232
}
11233
11234
std::unique_ptr<CAssemblerCommand> parseDirectiveMipsArch(Parser& parser, int flags)
11235
{
11236
Arch = &Mips;
11237
Mips.SetLoadDelay(false, 0);
11238
11239
switch (flags)
11240
{
11241
case DIRECTIVE_MIPS_PSX:
11242
Mips.SetVersion(MARCH_PSX);
11243
return ::make_unique<ArchitectureCommand>(L".psx", L"");
11244
case DIRECTIVE_MIPS_PS2:
11245
Mips.SetVersion(MARCH_PS2);
11246
return ::make_unique<ArchitectureCommand>(L".ps2", L"");
11247
case DIRECTIVE_MIPS_PSP:
11248
Mips.SetVersion(MARCH_PSP);
11249
return ::make_unique<ArchitectureCommand>(L".psp", L"");
11250
case DIRECTIVE_MIPS_N64:
11251
Mips.SetVersion(MARCH_N64);
11252
return ::make_unique<ArchitectureCommand>(L".n64", L"");
11253
case DIRECTIVE_MIPS_RSP:
11254
Mips.SetVersion(MARCH_RSP);
11255
return ::make_unique<ArchitectureCommand>(L".rsp", L"");
11256
}
11257
11258
return nullptr;
11259
}
11260
11261
std::unique_ptr<CAssemblerCommand> parseDirectiveArmArch(Parser& parser, int flags)
11262
{
11263
#ifdef ARMIPS_ARM
11264
Arch = &Arm;
11265
11266
switch (flags)
11267
{
11268
case DIRECTIVE_ARM_GBA:
11269
Arm.SetThumbMode(true);
11270
Arm.setVersion(AARCH_GBA);
11271
return ::make_unique<ArchitectureCommand>(L".gba\n.thumb", L".thumb");
11272
case DIRECTIVE_ARM_NDS:
11273
Arm.SetThumbMode(false);
11274
Arm.setVersion(AARCH_NDS);
11275
return ::make_unique<ArchitectureCommand>(L".nds\n.arm", L".arm");
11276
case DIRECTIVE_ARM_3DS:
11277
Arm.SetThumbMode(false);
11278
Arm.setVersion(AARCH_3DS);
11279
return ::make_unique<ArchitectureCommand>(L".3ds\n.arm", L".arm");
11280
case DIRECTIVE_ARM_BIG:
11281
Arm.SetThumbMode(false);
11282
Arm.setVersion(AARCH_BIG);
11283
return ::make_unique<ArchitectureCommand>(L".arm.big\n.arm", L".arm");
11284
case DIRECTIVE_ARM_LITTLE:
11285
Arm.SetThumbMode(false);
11286
Arm.setVersion(AARCH_LITTLE);
11287
return ::make_unique<ArchitectureCommand>(L".arm.little\n.arm", L".arm");
11288
}
11289
#endif
11290
11291
return nullptr;
11292
}
11293
11294
std::unique_ptr<CAssemblerCommand> parseDirectiveArea(Parser& parser, int flags)
11295
{
11296
std::vector<Expression> parameters;
11297
if (parser.parseExpressionList(parameters,1,2) == false)
11298
return nullptr;
11299
11300
auto area = ::make_unique<CDirectiveArea>(parameters[0]);
11301
if (parameters.size() == 2)
11302
area->setFillExpression(parameters[1]);
11303
11304
std::unique_ptr<CAssemblerCommand> content = parser.parseCommandSequence(L'.', {L".endarea"});
11305
parser.eatToken();
11306
11307
area->setContent(std::move(content));
11308
return area;
11309
}
11310
11311
std::unique_ptr<CAssemblerCommand> parseDirectiveErrorWarning(Parser& parser, int flags)
11312
{
11313
const Token &tok = parser.nextToken();
11314
11315
if (tok.type != TokenType::Identifier && tok.type != TokenType::String)
11316
return nullptr;
11317
11318
std::wstring stringValue = tok.getStringValue();
11319
std::transform(stringValue.begin(),stringValue.end(),stringValue.begin(),::towlower);
11320
11321
if (stringValue == L"on")
11322
{
11323
Logger::setErrorOnWarning(true);
11324
return ::make_unique<DummyCommand>();
11325
} else if (stringValue == L"off")
11326
{
11327
Logger::setErrorOnWarning(false);
11328
return ::make_unique<DummyCommand>();
11329
}
11330
11331
return nullptr;
11332
}
11333
11334
std::unique_ptr<CAssemblerCommand> parseDirectiveRelativeInclude(Parser& parser, int flags)
11335
{
11336
const Token &tok = parser.nextToken();
11337
11338
if (tok.type != TokenType::Identifier && tok.type != TokenType::String)
11339
return nullptr;
11340
11341
std::wstring stringValue = tok.getStringValue();
11342
std::transform(stringValue.begin(),stringValue.end(),stringValue.begin(),::towlower);
11343
11344
if (stringValue == L"on")
11345
{
11346
Global.relativeInclude = true;
11347
return ::make_unique<DummyCommand>();
11348
} else if (stringValue == L"off")
11349
{
11350
Global.relativeInclude = false;
11351
return ::make_unique<DummyCommand>();
11352
}
11353
11354
return nullptr;
11355
}
11356
11357
std::unique_ptr<CAssemblerCommand> parseDirectiveNocash(Parser& parser, int flags)
11358
{
11359
const Token &tok = parser.nextToken();
11360
11361
if (tok.type != TokenType::Identifier && tok.type != TokenType::String)
11362
return nullptr;
11363
11364
std::wstring stringValue = tok.getStringValue();
11365
std::transform(stringValue.begin(),stringValue.end(),stringValue.begin(),::towlower);
11366
11367
if (stringValue == L"on")
11368
{
11369
Global.nocash = true;
11370
return ::make_unique<DummyCommand>();
11371
} else if (stringValue == L"off")
11372
{
11373
Global.nocash = false;
11374
return ::make_unique<DummyCommand>();
11375
}
11376
11377
return nullptr;
11378
}
11379
11380
std::unique_ptr<CAssemblerCommand> parseDirectiveSym(Parser& parser, int flags)
11381
{
11382
const Token &tok = parser.nextToken();
11383
11384
if (tok.type != TokenType::Identifier && tok.type != TokenType::String)
11385
return nullptr;
11386
11387
std::wstring stringValue = tok.getStringValue();
11388
std::transform(stringValue.begin(),stringValue.end(),stringValue.begin(),::towlower);
11389
11390
if (stringValue == L"on")
11391
return ::make_unique<CDirectiveSym>(true);
11392
else if (stringValue == L"off")
11393
return ::make_unique<CDirectiveSym>(false);
11394
else
11395
return nullptr;
11396
}
11397
11398
std::unique_ptr<CAssemblerCommand> parseDirectiveDefineLabel(Parser& parser, int flags)
11399
{
11400
const Token& tok = parser.nextToken();
11401
if (tok.type != TokenType::Identifier)
11402
return nullptr;
11403
11404
if (parser.nextToken().type != TokenType::Comma)
11405
return nullptr;
11406
11407
Expression value = parser.parseExpression();
11408
if (value.isLoaded() == false)
11409
return nullptr;
11410
11411
const std::wstring stringValue = tok.getStringValue();
11412
if (Global.symbolTable.isValidSymbolName(stringValue) == false)
11413
{
11414
parser.printError(tok,L"Invalid label name \"%s\"",stringValue);
11415
return nullptr;
11416
}
11417
11418
return ::make_unique<CAssemblerLabel>(stringValue,tok.getOriginalText(),value);
11419
}
11420
11421
std::unique_ptr<CAssemblerCommand> parseDirectiveFunction(Parser& parser, int flags)
11422
{
11423
const Token& tok = parser.nextToken();
11424
if (tok.type != TokenType::Identifier)
11425
return nullptr;
11426
11427
if (parser.nextToken().type != TokenType::Separator)
11428
{
11429
parser.printError(tok,L"Directive not terminated");
11430
return nullptr;
11431
}
11432
11433
auto func = ::make_unique<CDirectiveFunction>(tok.getStringValue(),tok.getOriginalText());
11434
std::unique_ptr<CAssemblerCommand> seq = parser.parseCommandSequence(L'.', {L".endfunc",L".endfunction",L".func",L".function"});
11435
11436
const std::wstring stringValue = parser.peekToken().getStringValue();
11437
if (stringValue == L".endfunc" ||
11438
stringValue == L".endfunction")
11439
{
11440
parser.eatToken();
11441
if(parser.nextToken().type != TokenType::Separator)
11442
{
11443
parser.printError(tok,L"Directive not terminated");
11444
return nullptr;
11445
}
11446
}
11447
11448
func->setContent(std::move(seq));
11449
return func;
11450
}
11451
11452
std::unique_ptr<CAssemblerCommand> parseDirectiveMessage(Parser& parser, int flags)
11453
{
11454
Expression exp = parser.parseExpression();
11455
11456
switch (flags)
11457
{
11458
case DIRECTIVE_MSG_WARNING:
11459
return ::make_unique<CDirectiveMessage>(CDirectiveMessage::Type::Warning,exp);
11460
case DIRECTIVE_MSG_ERROR:
11461
return ::make_unique<CDirectiveMessage>(CDirectiveMessage::Type::Error,exp);
11462
case DIRECTIVE_MSG_NOTICE:
11463
return ::make_unique<CDirectiveMessage>(CDirectiveMessage::Type::Notice,exp);
11464
}
11465
11466
return nullptr;
11467
}
11468
11469
std::unique_ptr<CAssemblerCommand> parseDirectiveInclude(Parser& parser, int flags)
11470
{
11471
const Token& start = parser.peekToken();
11472
11473
std::vector<Expression> parameters;
11474
if (parser.parseExpressionList(parameters,1,2) == false)
11475
return nullptr;
11476
11477
std::wstring fileName;
11478
if (parameters[0].evaluateString(fileName,true) == false)
11479
return nullptr;
11480
11481
fileName = getFullPathName(fileName);
11482
11483
TextFile::Encoding encoding = TextFile::GUESS;
11484
if (parameters.size() == 2)
11485
{
11486
std::wstring encodingName;
11487
if (parameters[1].evaluateString(encodingName,true) == false
11488
&& parameters[1].evaluateIdentifier(encodingName) == false)
11489
return nullptr;
11490
11491
encoding = getEncodingFromString(encodingName);
11492
}
11493
11494
// don't include the file if it's inside a false block
11495
if (parser.isInsideTrueBlock() == false)
11496
return ::make_unique<DummyCommand>();
11497
11498
if (fileExists(fileName) == false)
11499
{
11500
parser.printError(start,L"Included file \"%s\" does not exist",fileName);
11501
return nullptr;
11502
}
11503
11504
TextFile f;
11505
if (f.open(fileName,TextFile::Read,encoding) == false)
11506
{
11507
parser.printError(start,L"Could not open included file \"%s\"",fileName);
11508
return nullptr;
11509
}
11510
11511
return parser.parseFile(f);
11512
}
11513
11514
const DirectiveMap directives = {
11515
{ L".open", { &parseDirectiveOpen, DIRECTIVE_NOTINMEMORY } },
11516
{ L".openfile", { &parseDirectiveOpen, DIRECTIVE_NOTINMEMORY } },
11517
{ L".create", { &parseDirectiveCreate, DIRECTIVE_NOTINMEMORY } },
11518
{ L".createfile", { &parseDirectiveCreate, DIRECTIVE_NOTINMEMORY } },
11519
{ L".close", { &parseDirectiveClose, DIRECTIVE_NOTINMEMORY } },
11520
{ L".closefile", { &parseDirectiveClose, DIRECTIVE_NOTINMEMORY } },
11521
{ L".incbin", { &parseDirectiveIncbin, 0 } },
11522
{ L".import", { &parseDirectiveIncbin, 0 } },
11523
{ L".org", { &parseDirectivePosition, DIRECTIVE_POS_VIRTUAL } },
11524
{ L"org", { &parseDirectivePosition, DIRECTIVE_POS_VIRTUAL } },
11525
{ L".orga", { &parseDirectivePosition, DIRECTIVE_POS_PHYSICAL } },
11526
{ L"orga", { &parseDirectivePosition, DIRECTIVE_POS_PHYSICAL } },
11527
{ L".headersize", { &parseDirectiveHeaderSize, 0 } },
11528
{ L".align", { &parseDirectiveAlignFill, DIRECTIVE_ALIGN_VIRTUAL } },
11529
{ L".aligna", { &parseDirectiveAlignFill, DIRECTIVE_ALIGN_PHYSICAL } },
11530
{ L".fill", { &parseDirectiveAlignFill, DIRECTIVE_ALIGN_FILL } },
11531
{ L"defs", { &parseDirectiveAlignFill, DIRECTIVE_ALIGN_FILL } },
11532
{ L".skip", { &parseDirectiveSkip, 0 } },
11533
11534
{ L".if", { &parseDirectiveConditional, DIRECTIVE_COND_IF } },
11535
{ L".ifdef", { &parseDirectiveConditional, DIRECTIVE_COND_IFDEF } },
11536
{ L".ifndef", { &parseDirectiveConditional, DIRECTIVE_COND_IFNDEF } },
11537
11538
{ L".loadtable", { &parseDirectiveTable, 0 } },
11539
{ L".table", { &parseDirectiveTable, 0 } },
11540
{ L".byte", { &parseDirectiveData, DIRECTIVE_DATA_8 } },
11541
{ L".halfword", { &parseDirectiveData, DIRECTIVE_DATA_16 } },
11542
{ L".word", { &parseDirectiveData, DIRECTIVE_DATA_32 } },
11543
{ L".doubleword", { &parseDirectiveData, DIRECTIVE_DATA_64 } },
11544
{ L".db", { &parseDirectiveData, DIRECTIVE_DATA_8 } },
11545
{ L".dh", { &parseDirectiveData, DIRECTIVE_DATA_16|DIRECTIVE_NOCASHOFF } },
11546
{ L".dw", { &parseDirectiveData, DIRECTIVE_DATA_32|DIRECTIVE_NOCASHOFF } },
11547
{ L".dd", { &parseDirectiveData, DIRECTIVE_DATA_64|DIRECTIVE_NOCASHOFF } },
11548
{ L".dw", { &parseDirectiveData, DIRECTIVE_DATA_16|DIRECTIVE_NOCASHON } },
11549
{ L".dd", { &parseDirectiveData, DIRECTIVE_DATA_32|DIRECTIVE_NOCASHON } },
11550
{ L".dcb", { &parseDirectiveData, DIRECTIVE_DATA_8 } },
11551
{ L".dcw", { &parseDirectiveData, DIRECTIVE_DATA_16 } },
11552
{ L".dcd", { &parseDirectiveData, DIRECTIVE_DATA_32 } },
11553
{ L".dcq", { &parseDirectiveData, DIRECTIVE_DATA_64 } },
11554
{ L"db", { &parseDirectiveData, DIRECTIVE_DATA_8 } },
11555
{ L"dh", { &parseDirectiveData, DIRECTIVE_DATA_16|DIRECTIVE_NOCASHOFF } },
11556
{ L"dw", { &parseDirectiveData, DIRECTIVE_DATA_32|DIRECTIVE_NOCASHOFF } },
11557
{ L"dd", { &parseDirectiveData, DIRECTIVE_DATA_64|DIRECTIVE_NOCASHOFF } },
11558
{ L"dw", { &parseDirectiveData, DIRECTIVE_DATA_16|DIRECTIVE_NOCASHON } },
11559
{ L"dd", { &parseDirectiveData, DIRECTIVE_DATA_32|DIRECTIVE_NOCASHON } },
11560
{ L"dcb", { &parseDirectiveData, DIRECTIVE_DATA_8 } },
11561
{ L"dcw", { &parseDirectiveData, DIRECTIVE_DATA_16 } },
11562
{ L"dcd", { &parseDirectiveData, DIRECTIVE_DATA_32 } },
11563
{ L"dcq", { &parseDirectiveData, DIRECTIVE_DATA_64 } },
11564
{ L".float", { &parseDirectiveData, DIRECTIVE_DATA_FLOAT } },
11565
{ L".double", { &parseDirectiveData, DIRECTIVE_DATA_DOUBLE } },
11566
{ L".ascii", { &parseDirectiveData, DIRECTIVE_DATA_ASCII } },
11567
{ L".asciiz", { &parseDirectiveData, DIRECTIVE_DATA_ASCII|DIRECTIVE_DATA_TERMINATION } },
11568
{ L".string", { &parseDirectiveData, DIRECTIVE_DATA_CUSTOM|DIRECTIVE_DATA_TERMINATION } },
11569
{ L".str", { &parseDirectiveData, DIRECTIVE_DATA_CUSTOM|DIRECTIVE_DATA_TERMINATION } },
11570
{ L".stringn", { &parseDirectiveData, DIRECTIVE_DATA_CUSTOM } },
11571
{ L".strn", { &parseDirectiveData, DIRECTIVE_DATA_CUSTOM } },
11572
{ L".sjis", { &parseDirectiveData, DIRECTIVE_DATA_SJIS|DIRECTIVE_DATA_TERMINATION } },
11573
{ L".sjisn", { &parseDirectiveData, DIRECTIVE_DATA_SJIS } },
11574
11575
{ L".psx", { &parseDirectiveMipsArch, DIRECTIVE_MIPS_PSX } },
11576
{ L".ps2", { &parseDirectiveMipsArch, DIRECTIVE_MIPS_PS2 } },
11577
{ L".psp", { &parseDirectiveMipsArch, DIRECTIVE_MIPS_PSP } },
11578
{ L".n64", { &parseDirectiveMipsArch, DIRECTIVE_MIPS_N64 } },
11579
{ L".rsp", { &parseDirectiveMipsArch, DIRECTIVE_MIPS_RSP } },
11580
11581
{ L".gba", { &parseDirectiveArmArch, DIRECTIVE_ARM_GBA } },
11582
{ L".nds", { &parseDirectiveArmArch, DIRECTIVE_ARM_NDS } },
11583
{ L".3ds", { &parseDirectiveArmArch, DIRECTIVE_ARM_3DS } },
11584
{ L".arm.big", { &parseDirectiveArmArch, DIRECTIVE_ARM_BIG } },
11585
{ L".arm.little", { &parseDirectiveArmArch, DIRECTIVE_ARM_LITTLE } },
11586
11587
{ L".area", { &parseDirectiveArea, 0 } },
11588
11589
{ L".importobj", { &parseDirectiveObjImport, 0 } },
11590
{ L".importlib", { &parseDirectiveObjImport, 0 } },
11591
11592
{ L".erroronwarning", { &parseDirectiveErrorWarning, 0 } },
11593
{ L".relativeinclude", { &parseDirectiveRelativeInclude, 0 } },
11594
{ L".nocash", { &parseDirectiveNocash, 0 } },
11595
{ L".sym", { &parseDirectiveSym, 0 } },
11596
11597
{ L".definelabel", { &parseDirectiveDefineLabel, 0 } },
11598
{ L".function", { &parseDirectiveFunction, DIRECTIVE_MANUALSEPARATOR } },
11599
{ L".func", { &parseDirectiveFunction, DIRECTIVE_MANUALSEPARATOR } },
11600
11601
{ L".warning", { &parseDirectiveMessage, DIRECTIVE_MSG_WARNING } },
11602
{ L".error", { &parseDirectiveMessage, DIRECTIVE_MSG_ERROR } },
11603
{ L".notice", { &parseDirectiveMessage, DIRECTIVE_MSG_NOTICE } },
11604
11605
{ L".include", { &parseDirectiveInclude, 0 } },
11606
};
11607
11608
// file: Parser/ExpressionParser.cpp
11609
11610
static ExpressionInternal* expression(Tokenizer& tokenizer);
11611
11612
static bool allowFunctionCall = true;
11613
11614
void allowFunctionCallExpression(bool allow)
11615
{
11616
allowFunctionCall = allow;
11617
}
11618
11619
static ExpressionInternal* primaryExpression(Tokenizer& tokenizer)
11620
{
11621
const Token &tok = tokenizer.peekToken();
11622
11623
switch (tok.type)
11624
{
11625
case TokenType::Float:
11626
tokenizer.eatToken();
11627
return new ExpressionInternal(tok.floatValue);
11628
case TokenType::Identifier:
11629
{
11630
const std::wstring stringValue = tok.getStringValue();
11631
tokenizer.eatToken();
11632
if (stringValue == L".")
11633
return new ExpressionInternal(OperatorType::MemoryPos);
11634
else
11635
return new ExpressionInternal(stringValue,OperatorType::Identifier);
11636
}
11637
case TokenType::String:
11638
tokenizer.eatToken();
11639
return new ExpressionInternal(tok.getStringValue(),OperatorType::String);
11640
case TokenType::Integer:
11641
tokenizer.eatToken();
11642
return new ExpressionInternal(tok.intValue);
11643
case TokenType::LParen:
11644
{
11645
tokenizer.eatToken();
11646
ExpressionInternal* exp = expression(tokenizer);
11647
11648
if (tokenizer.nextToken().type != TokenType::RParen)
11649
{
11650
delete exp;
11651
return nullptr;
11652
}
11653
11654
return exp;
11655
}
11656
case TokenType::Invalid:
11657
default:
11658
break;
11659
}
11660
11661
return nullptr;
11662
}
11663
11664
static ExpressionInternal* postfixExpression(Tokenizer& tokenizer)
11665
{
11666
if (allowFunctionCall &&
11667
tokenizer.peekToken(0).type == TokenType::Identifier &&
11668
tokenizer.peekToken(1).type == TokenType::LParen)
11669
{
11670
const std::wstring functionName = tokenizer.nextToken().getStringValue();
11671
tokenizer.eatToken();
11672
11673
std::vector<ExpressionInternal*> parameters;
11674
while (tokenizer.peekToken().type != TokenType::RParen)
11675
{
11676
if (parameters.size() != 0 && tokenizer.nextToken().type != TokenType::Comma)
11677
{
11678
for (ExpressionInternal* exp: parameters)
11679
delete exp;
11680
return nullptr;
11681
}
11682
11683
ExpressionInternal* exp = expression(tokenizer);
11684
if (exp == nullptr)
11685
{
11686
for (ExpressionInternal* exp: parameters)
11687
delete exp;
11688
return nullptr;
11689
}
11690
11691
parameters.push_back(exp);
11692
}
11693
11694
tokenizer.eatToken();
11695
11696
return new ExpressionInternal(functionName,parameters);
11697
}
11698
11699
return primaryExpression(tokenizer);
11700
}
11701
11702
static ExpressionInternal* unaryExpression(Tokenizer& tokenizer)
11703
{
11704
ExpressionInternal* exp = postfixExpression(tokenizer);
11705
if (exp != nullptr)
11706
return exp;
11707
11708
const TokenType opType = tokenizer.nextToken().type;
11709
exp = postfixExpression(tokenizer);
11710
if (exp == nullptr)
11711
return nullptr;
11712
11713
switch (opType)
11714
{
11715
case TokenType::Plus:
11716
return exp;
11717
case TokenType::Minus:
11718
return new ExpressionInternal(OperatorType::Neg,exp);
11719
case TokenType::Tilde:
11720
return new ExpressionInternal(OperatorType::BitNot,exp);
11721
case TokenType::Exclamation:
11722
return new ExpressionInternal(OperatorType::LogNot,exp);
11723
case TokenType::Degree:
11724
return new ExpressionInternal(OperatorType::ToString,exp);
11725
default:
11726
delete exp;
11727
return nullptr;
11728
}
11729
}
11730
11731
static ExpressionInternal* multiplicativeExpression(Tokenizer& tokenizer)
11732
{
11733
ExpressionInternal* exp = unaryExpression(tokenizer);
11734
if (exp == nullptr)
11735
return nullptr;
11736
11737
while (true)
11738
{
11739
OperatorType op = OperatorType::Invalid;
11740
switch (tokenizer.peekToken().type)
11741
{
11742
case TokenType::Mult:
11743
op = OperatorType::Mult;
11744
break;
11745
case TokenType::Div:
11746
op = OperatorType::Div;
11747
break;
11748
case TokenType::Mod:
11749
op = OperatorType::Mod;
11750
break;
11751
default:
11752
break;
11753
}
11754
11755
if (op == OperatorType::Invalid)
11756
break;
11757
11758
tokenizer.eatToken();
11759
11760
ExpressionInternal* exp2 = unaryExpression(tokenizer);
11761
if (exp2 == nullptr)
11762
{
11763
delete exp;
11764
return nullptr;
11765
}
11766
11767
exp = new ExpressionInternal(op,exp,exp2);
11768
}
11769
11770
return exp;
11771
}
11772
11773
static ExpressionInternal* additiveExpression(Tokenizer& tokenizer)
11774
{
11775
ExpressionInternal* exp = multiplicativeExpression(tokenizer);
11776
if (exp == nullptr)
11777
return nullptr;
11778
11779
while (true)
11780
{
11781
OperatorType op = OperatorType::Invalid;
11782
switch (tokenizer.peekToken().type)
11783
{
11784
case TokenType::Plus:
11785
op = OperatorType::Add;
11786
break;
11787
case TokenType::Minus:
11788
op = OperatorType::Sub;
11789
break;
11790
default:
11791
break;
11792
}
11793
11794
if (op == OperatorType::Invalid)
11795
break;
11796
11797
tokenizer.eatToken();
11798
11799
ExpressionInternal* exp2 = multiplicativeExpression(tokenizer);
11800
if (exp2 == nullptr)
11801
{
11802
delete exp;
11803
return nullptr;
11804
}
11805
11806
exp = new ExpressionInternal(op,exp,exp2);
11807
}
11808
11809
return exp;
11810
}
11811
11812
static ExpressionInternal* shiftExpression(Tokenizer& tokenizer)
11813
{
11814
ExpressionInternal* exp = additiveExpression(tokenizer);
11815
if (exp == nullptr)
11816
return nullptr;
11817
11818
while (true)
11819
{
11820
OperatorType op = OperatorType::Invalid;
11821
switch (tokenizer.peekToken().type)
11822
{
11823
case TokenType::LeftShift:
11824
op = OperatorType::LeftShift;
11825
break;
11826
case TokenType::RightShift:
11827
op = OperatorType::RightShift;
11828
break;
11829
default:
11830
break;
11831
}
11832
11833
if (op == OperatorType::Invalid)
11834
break;
11835
11836
tokenizer.eatToken();
11837
11838
ExpressionInternal* exp2 = additiveExpression(tokenizer);
11839
if (exp2 == nullptr)
11840
{
11841
delete exp;
11842
return nullptr;
11843
}
11844
11845
exp = new ExpressionInternal(op,exp,exp2);
11846
}
11847
11848
return exp;
11849
}
11850
11851
static ExpressionInternal* relationalExpression(Tokenizer& tokenizer)
11852
{
11853
ExpressionInternal* exp = shiftExpression(tokenizer);
11854
if (exp == nullptr)
11855
return nullptr;
11856
11857
while (true)
11858
{
11859
OperatorType op = OperatorType::Invalid;
11860
switch (tokenizer.peekToken().type)
11861
{
11862
case TokenType::Less:
11863
op = OperatorType::Less;
11864
break;
11865
case TokenType::LessEqual:
11866
op = OperatorType::LessEqual;
11867
break;
11868
case TokenType::Greater:
11869
op = OperatorType::Greater;
11870
break;
11871
case TokenType::GreaterEqual:
11872
op = OperatorType::GreaterEqual;
11873
break;
11874
default:
11875
break;
11876
}
11877
11878
if (op == OperatorType::Invalid)
11879
break;
11880
11881
tokenizer.eatToken();
11882
11883
ExpressionInternal* exp2 = shiftExpression(tokenizer);
11884
if (exp2 == nullptr)
11885
{
11886
delete exp;
11887
return nullptr;
11888
}
11889
11890
exp = new ExpressionInternal(op,exp,exp2);
11891
}
11892
11893
return exp;
11894
}
11895
11896
static ExpressionInternal* equalityExpression(Tokenizer& tokenizer)
11897
{
11898
ExpressionInternal* exp = relationalExpression(tokenizer);
11899
if (exp == nullptr)
11900
return nullptr;
11901
11902
while (true)
11903
{
11904
OperatorType op = OperatorType::Invalid;
11905
switch (tokenizer.peekToken().type)
11906
{
11907
case TokenType::Equal:
11908
op = OperatorType::Equal;
11909
break;
11910
case TokenType::NotEqual:
11911
op = OperatorType::NotEqual;
11912
break;
11913
default:
11914
break;
11915
}
11916
11917
if (op == OperatorType::Invalid)
11918
break;
11919
11920
tokenizer.eatToken();
11921
11922
ExpressionInternal* exp2 = relationalExpression(tokenizer);
11923
if (exp2 == nullptr)
11924
{
11925
delete exp;
11926
return nullptr;
11927
}
11928
11929
exp = new ExpressionInternal(op,exp,exp2);
11930
}
11931
11932
return exp;
11933
}
11934
11935
static ExpressionInternal* andExpression(Tokenizer& tokenizer)
11936
{
11937
ExpressionInternal* exp = equalityExpression(tokenizer);
11938
if (exp == nullptr)
11939
return nullptr;
11940
11941
while (tokenizer.peekToken().type == TokenType::BitAnd)
11942
{
11943
tokenizer.eatToken();
11944
11945
ExpressionInternal* exp2 = equalityExpression(tokenizer);
11946
if (exp2 == nullptr)
11947
{
11948
delete exp;
11949
return nullptr;
11950
}
11951
11952
exp = new ExpressionInternal(OperatorType::BitAnd,exp,exp2);
11953
}
11954
11955
return exp;
11956
}
11957
11958
static ExpressionInternal* exclusiveOrExpression(Tokenizer& tokenizer)
11959
{
11960
ExpressionInternal* exp = andExpression(tokenizer);
11961
if (exp == nullptr)
11962
return nullptr;
11963
11964
while (tokenizer.peekToken().type == TokenType::Caret)
11965
{
11966
tokenizer.eatToken();
11967
11968
ExpressionInternal* exp2 = andExpression(tokenizer);
11969
if (exp2 == nullptr)
11970
{
11971
delete exp;
11972
return nullptr;
11973
}
11974
11975
exp = new ExpressionInternal(OperatorType::Xor,exp,exp2);
11976
}
11977
11978
return exp;
11979
}
11980
11981
static ExpressionInternal* inclusiveOrExpression(Tokenizer& tokenizer)
11982
{
11983
ExpressionInternal* exp = exclusiveOrExpression(tokenizer);
11984
if (exp == nullptr)
11985
return nullptr;
11986
11987
while (tokenizer.peekToken().type == TokenType::BitOr)
11988
{
11989
tokenizer.eatToken();
11990
11991
ExpressionInternal* exp2 = exclusiveOrExpression(tokenizer);
11992
if (exp2 == nullptr)
11993
{
11994
delete exp;
11995
return nullptr;
11996
}
11997
11998
exp = new ExpressionInternal(OperatorType::BitOr,exp,exp2);
11999
}
12000
12001
return exp;
12002
}
12003
12004
static ExpressionInternal* logicalAndExpression(Tokenizer& tokenizer)
12005
{
12006
ExpressionInternal* exp = inclusiveOrExpression(tokenizer);
12007
if (exp == nullptr)
12008
return nullptr;
12009
12010
while (tokenizer.peekToken().type == TokenType::LogAnd)
12011
{
12012
tokenizer.eatToken();
12013
12014
ExpressionInternal* exp2 = inclusiveOrExpression(tokenizer);
12015
if (exp2 == nullptr)
12016
{
12017
delete exp;
12018
return nullptr;
12019
}
12020
12021
exp = new ExpressionInternal(OperatorType::LogAnd,exp,exp2);
12022
}
12023
12024
return exp;
12025
}
12026
12027
static ExpressionInternal* logicalOrExpression(Tokenizer& tokenizer)
12028
{
12029
ExpressionInternal* exp = logicalAndExpression(tokenizer);
12030
if (exp == nullptr)
12031
return nullptr;
12032
12033
while (tokenizer.peekToken().type == TokenType::LogOr)
12034
{
12035
tokenizer.eatToken();
12036
12037
ExpressionInternal* exp2 = logicalAndExpression(tokenizer);
12038
if (exp2 == nullptr)
12039
{
12040
delete exp;
12041
return nullptr;
12042
}
12043
12044
exp = new ExpressionInternal(OperatorType::LogOr,exp,exp2);
12045
}
12046
12047
return exp;
12048
}
12049
12050
static ExpressionInternal* conditionalExpression(Tokenizer& tokenizer)
12051
{
12052
ExpressionInternal* exp = logicalOrExpression(tokenizer);
12053
if (exp == nullptr)
12054
return nullptr;
12055
12056
// check a ? b : c
12057
if (tokenizer.peekToken().type != TokenType::Question)
12058
return exp;
12059
12060
tokenizer.eatToken();
12061
ExpressionInternal* second = expression(tokenizer);
12062
12063
if (second != nullptr && tokenizer.nextToken().type == TokenType::Colon)
12064
{
12065
ExpressionInternal* third = expression(tokenizer);
12066
if (third != nullptr)
12067
return new ExpressionInternal(OperatorType::TertiaryIf,exp,second,third);
12068
12069
delete third;
12070
}
12071
12072
delete second;
12073
delete exp;
12074
return nullptr;
12075
}
12076
12077
static ExpressionInternal* expression(Tokenizer& tokenizer)
12078
{
12079
return conditionalExpression(tokenizer);
12080
}
12081
12082
Expression parseExpression(Tokenizer& tokenizer, bool inUnknownOrFalseBlock)
12083
{
12084
TokenizerPosition pos = tokenizer.getPosition();
12085
12086
// parse expression, revert tokenizer to previous position
12087
// if it failed
12088
ExpressionInternal* exp = expression(tokenizer);
12089
if (exp == nullptr)
12090
tokenizer.setPosition(pos);
12091
12092
Expression result;
12093
result.setExpression(exp, inUnknownOrFalseBlock);
12094
return result;
12095
}
12096
12097
// file: Parser/Parser.cpp
12098
12099
inline bool isPartOfList(const std::wstring& value, const std::initializer_list<const wchar_t*>& terminators)
12100
{
12101
for (const wchar_t* term: terminators)
12102
{
12103
if (value == term)
12104
return true;
12105
}
12106
12107
return false;
12108
}
12109
12110
Parser::Parser()
12111
{
12112
initializingMacro = false;
12113
overrideFileInfo = false;
12114
conditionStack.push_back({true,false});
12115
clearError();
12116
}
12117
12118
void Parser::pushConditionalResult(ConditionalResult cond)
12119
{
12120
ConditionInfo info = conditionStack.back();
12121
info.inTrueBlock = info.inTrueBlock && cond != ConditionalResult::False;
12122
info.inUnknownBlock = info.inUnknownBlock || cond == ConditionalResult::Unknown;
12123
conditionStack.push_back(info);
12124
}
12125
12126
Expression Parser::parseExpression()
12127
{
12128
return ::parseExpression(*getTokenizer(), !isInsideTrueBlock() || isInsideUnknownBlock());
12129
}
12130
12131
bool Parser::parseExpressionList(std::vector<Expression>& list, int min, int max)
12132
{
12133
bool valid = true;
12134
list.clear();
12135
list.reserve(max >= 0 ? max : 32);
12136
12137
const Token& start = peekToken();
12138
12139
Expression exp = parseExpression();
12140
list.push_back(exp);
12141
12142
if (exp.isLoaded() == false)
12143
{
12144
printError(start,L"Parameter failure");
12145
getTokenizer()->skipLookahead();
12146
valid = false;
12147
}
12148
12149
while (peekToken().type == TokenType::Comma)
12150
{
12151
eatToken();
12152
12153
exp = parseExpression();
12154
list.push_back(exp);
12155
12156
if (exp.isLoaded() == false)
12157
{
12158
printError(start,L"Parameter failure");
12159
getTokenizer()->skipLookahead();
12160
valid = false;
12161
}
12162
}
12163
12164
if (list.size() < (size_t) min)
12165
{
12166
printError(start,L"Not enough parameters (min %d)",min);
12167
return false;
12168
}
12169
12170
if (max != -1 && (size_t) max < list.size())
12171
{
12172
printError(start,L"Too many parameters (max %d)",max);
12173
return false;
12174
}
12175
12176
return valid;
12177
}
12178
12179
bool Parser::parseIdentifier(std::wstring& dest)
12180
{
12181
const Token& tok = nextToken();
12182
if (tok.type != TokenType::Identifier)
12183
return false;
12184
12185
dest = tok.getStringValue();
12186
return true;
12187
}
12188
12189
std::unique_ptr<CAssemblerCommand> Parser::parseCommandSequence(wchar_t indicator, const std::initializer_list<const wchar_t*> terminators)
12190
{
12191
auto sequence = ::make_unique<CommandSequence>();
12192
12193
bool foundTermination = false;
12194
while (atEnd() == false)
12195
{
12196
const Token &next = peekToken();
12197
12198
if(next.type == TokenType::Separator)
12199
{
12200
eatToken();
12201
continue;
12202
}
12203
12204
if (next.stringValueStartsWith(indicator) && isPartOfList(next.getStringValue(), terminators))
12205
{
12206
foundTermination = true;
12207
break;
12208
}
12209
12210
bool foundSomething = false;
12211
while (checkEquLabel() || checkMacroDefinition())
12212
{
12213
// do nothing, just parse all the equs and macros there are
12214
if (hasError())
12215
sequence->addCommand(handleError());
12216
12217
foundSomething = true;
12218
}
12219
12220
if (foundSomething)
12221
continue;
12222
12223
std::unique_ptr<CAssemblerCommand> cmd = parseCommand();
12224
12225
// omit commands inside blocks that are trivially false
12226
if (isInsideTrueBlock() == false)
12227
{
12228
continue;
12229
}
12230
12231
sequence->addCommand(std::move(cmd));
12232
}
12233
12234
if (!foundTermination && terminators.size())
12235
{
12236
std::wstring expected;
12237
for (const wchar_t* terminator : terminators)
12238
{
12239
if (!expected.empty())
12240
expected += L", ";
12241
expected += terminator;
12242
}
12243
12244
Logger::printError(Logger::Error, L"Unterminated command sequence, expected any of %s.", expected);
12245
}
12246
12247
return sequence;
12248
}
12249
12250
std::unique_ptr<CAssemblerCommand> Parser::parseFile(TextFile& file, bool virtualFile)
12251
{
12252
FileTokenizer tokenizer;
12253
if (tokenizer.init(&file) == false)
12254
return nullptr;
12255
12256
std::unique_ptr<CAssemblerCommand> result = parse(&tokenizer,virtualFile,file.getFileName());
12257
12258
if (file.isFromMemory() == false)
12259
Global.FileInfo.TotalLineCount += file.getNumLines();
12260
12261
return result;
12262
}
12263
12264
std::unique_ptr<CAssemblerCommand> Parser::parseString(const std::wstring& text)
12265
{
12266
TextFile file;
12267
file.openMemory(text);
12268
return parseFile(file,true);
12269
}
12270
12271
std::unique_ptr<CAssemblerCommand> Parser::parseTemplate(const std::wstring& text, std::initializer_list<AssemblyTemplateArgument> variables)
12272
{
12273
std::wstring fullText = text;
12274
12275
overrideFileInfo = true;
12276
overrideFileNum = Global.FileInfo.FileNum;
12277
overrideLineNum = Global.FileInfo.LineNumber;
12278
12279
for (auto& arg: variables)
12280
{
12281
size_t count = replaceAll(fullText,arg.variableName,arg.value);
12282
(void)count;
12283
#ifdef _DEBUG
12284
if (count != 0 && arg.value.empty())
12285
Logger::printError(Logger::Warning,L"Empty replacement for %s",arg.variableName);
12286
#endif
12287
}
12288
12289
std::unique_ptr<CAssemblerCommand> result = parseString(fullText);
12290
overrideFileInfo = false;
12291
12292
return result;
12293
}
12294
12295
std::unique_ptr<CAssemblerCommand> Parser::parseDirective(const DirectiveMap &directiveSet)
12296
{
12297
const Token &tok = peekToken();
12298
if (tok.type != TokenType::Identifier)
12299
return nullptr;
12300
12301
const std::wstring stringValue = tok.getStringValue();
12302
12303
auto matchRange = directiveSet.equal_range(stringValue);
12304
for (auto it = matchRange.first; it != matchRange.second; ++it)
12305
{
12306
const DirectiveEntry &directive = it->second;
12307
12308
if (directive.flags & DIRECTIVE_DISABLED)
12309
continue;
12310
if ((directive.flags & DIRECTIVE_NOCASHOFF) && Global.nocash == true)
12311
continue;
12312
if ((directive.flags & DIRECTIVE_NOCASHON) && Global.nocash == false)
12313
continue;
12314
if ((directive.flags & DIRECTIVE_NOTINMEMORY) && Global.memoryMode == true)
12315
continue;
12316
12317
if (directive.flags & DIRECTIVE_MIPSRESETDELAY)
12318
Arch->NextSection();
12319
12320
eatToken();
12321
std::unique_ptr<CAssemblerCommand> result = directive.function(*this,directive.flags);
12322
if (result == nullptr)
12323
{
12324
if (hasError() == false)
12325
printError(tok,L"Directive parameter failure");
12326
return nullptr;
12327
} else if (!(directive.flags & DIRECTIVE_MANUALSEPARATOR) && nextToken().type != TokenType::Separator)
12328
{
12329
printError(tok,L"Directive not terminated");
12330
return nullptr;
12331
}
12332
12333
return result;
12334
}
12335
12336
return nullptr;
12337
}
12338
12339
bool Parser::matchToken(TokenType type, bool optional)
12340
{
12341
if (optional)
12342
{
12343
const Token& token = peekToken();
12344
if (token.type == type)
12345
eatToken();
12346
return true;
12347
}
12348
12349
return nextToken().type == type;
12350
}
12351
12352
std::unique_ptr<CAssemblerCommand> Parser::parse(Tokenizer* tokenizer, bool virtualFile, const std::wstring& name)
12353
{
12354
if (entries.size() >= 150)
12355
{
12356
Logger::queueError(Logger::Error, L"Max include/recursion depth reached");
12357
return nullptr;
12358
}
12359
12360
FileEntry entry;
12361
entry.tokenizer = tokenizer;
12362
entry.virtualFile = virtualFile;
12363
12364
if (virtualFile == false && name.empty() == false)
12365
{
12366
entry.fileNum = (int) Global.FileInfo.FileList.size();
12367
Global.FileInfo.FileList.push_back(name);
12368
} else {
12369
entry.fileNum = -1;
12370
}
12371
12372
entries.push_back(entry);
12373
12374
std::unique_ptr<CAssemblerCommand> sequence = parseCommandSequence();
12375
entries.pop_back();
12376
12377
return sequence;
12378
}
12379
12380
void Parser::addEquation(const Token& startToken, const std::wstring& name, const std::wstring& value)
12381
{
12382
// parse value string
12383
TextFile f;
12384
f.openMemory(value);
12385
12386
FileTokenizer tok;
12387
tok.init(&f);
12388
12389
TokenizerPosition start = tok.getPosition();
12390
while (tok.atEnd() == false && tok.peekToken().type != TokenType::Separator)
12391
{
12392
const Token& token = tok.nextToken();
12393
if (token.type == TokenType::Identifier && token.getStringValue() == name)
12394
{
12395
printError(startToken,L"Recursive equ definition for \"%s\" not allowed",name);
12396
return;
12397
}
12398
12399
if (token.type == TokenType::Equ)
12400
{
12401
printError(startToken,L"equ value must not contain another equ instance");
12402
return;
12403
}
12404
}
12405
12406
// extract tokens
12407
TokenizerPosition end = tok.getPosition();
12408
std::vector<Token> tokens = tok.getTokens(start, end);
12409
size_t index = Tokenizer::addEquValue(tokens);
12410
12411
for (FileEntry& entry : entries)
12412
entry.tokenizer->resetLookaheadCheckMarks();
12413
12414
// register equation
12415
Global.symbolTable.addEquation(name, Global.FileInfo.FileNum, Global.Section, index);
12416
}
12417
12418
bool Parser::checkEquLabel()
12419
{
12420
updateFileInfo();
12421
12422
const Token& start = peekToken();
12423
if (start.type == TokenType::Identifier)
12424
{
12425
int pos = 1;
12426
if (peekToken(pos).type == TokenType::Colon)
12427
pos++;
12428
12429
if (peekToken(pos).type == TokenType::Equ &&
12430
peekToken(pos+1).type == TokenType::EquValue)
12431
{
12432
std::wstring name = peekToken(0).getStringValue();
12433
std::wstring value = peekToken(pos+1).getStringValue();
12434
eatTokens(pos+2);
12435
12436
// skip the equ if it's inside a false conditional block
12437
if (isInsideTrueBlock() == false)
12438
return true;
12439
12440
// equs can't be inside blocks whose condition can only be
12441
// evaluated during validation
12442
if (isInsideUnknownBlock())
12443
{
12444
printError(start,L"equ not allowed inside of block with non-trivial condition");
12445
return true;
12446
}
12447
12448
// equs are not allowed in macros
12449
if (initializingMacro)
12450
{
12451
printError(start,L"equ not allowed in macro");
12452
return true;
12453
}
12454
12455
if (Global.symbolTable.isValidSymbolName(name) == false)
12456
{
12457
printError(start,L"Invalid equation name \"%s\"",name);
12458
return true;
12459
}
12460
12461
if (Global.symbolTable.symbolExists(name,Global.FileInfo.FileNum,Global.Section))
12462
{
12463
printError(start,L"Equation name \"%s\" already defined",name);
12464
return true;
12465
}
12466
12467
addEquation(start,name,value);
12468
return true;
12469
}
12470
}
12471
12472
return false;
12473
}
12474
12475
bool Parser::checkMacroDefinition()
12476
{
12477
const Token& first = peekToken();
12478
if (first.type != TokenType::Identifier)
12479
return false;
12480
12481
if (!first.stringValueStartsWith(L'.') || first.getStringValue() != L".macro")
12482
return false;
12483
12484
eatToken();
12485
12486
// nested macro definitions are not allowed
12487
if (initializingMacro)
12488
{
12489
printError(first,L"Nested macro definitions not allowed");
12490
while (!atEnd())
12491
{
12492
const Token& token = nextToken();
12493
if (token.type == TokenType::Identifier && token.getStringValue() == L".endmacro")
12494
break;
12495
}
12496
12497
return true;
12498
}
12499
12500
std::vector<Expression> parameters;
12501
if (parseExpressionList(parameters,1,-1) == false)
12502
return false;
12503
12504
ParserMacro macro;
12505
macro.counter = 0;
12506
12507
// load name
12508
if (parameters[0].evaluateIdentifier(macro.name) == false)
12509
return false;
12510
12511
// load parameters
12512
for (size_t i = 1; i < parameters.size(); i++)
12513
{
12514
std::wstring name;
12515
if (parameters[i].evaluateIdentifier(name) == false)
12516
return false;
12517
12518
macro.parameters.push_back(name);
12519
}
12520
12521
if(nextToken().type != TokenType::Separator)
12522
{
12523
printError(first,L"Macro directive not terminated");
12524
return false;
12525
}
12526
12527
// load macro content
12528
12529
TokenizerPosition start = getTokenizer()->getPosition();
12530
bool valid = false;
12531
while (atEnd() == false)
12532
{
12533
const Token& tok = nextToken();
12534
if (tok.type == TokenType::Identifier && tok.getStringValue() == L".endmacro")
12535
{
12536
valid = true;
12537
break;
12538
}
12539
}
12540
12541
// Macros have to be defined at parse time, so they can't be defined in blocks
12542
// with non-trivial conditions
12543
if (isInsideUnknownBlock())
12544
{
12545
printError(first, L"Macro definition not allowed inside of block with non-trivial condition");
12546
return false;
12547
}
12548
12549
// if we are in a known false block, don't define the macro
12550
if (!isInsideTrueBlock())
12551
return true;
12552
12553
// duplicate check
12554
if (macros.find(macro.name) != macros.end())
12555
{
12556
printError(first, L"Macro \"%s\" already defined", macro.name);
12557
return false;
12558
}
12559
12560
// no .endmacro, not valid
12561
if (valid == false)
12562
{
12563
printError(first, L"Macro \"%s\" not terminated", macro.name);
12564
return true;
12565
}
12566
12567
// get content
12568
TokenizerPosition end = getTokenizer()->getPosition().previous();
12569
macro.content = getTokenizer()->getTokens(start,end);
12570
12571
if(nextToken().type != TokenType::Separator)
12572
{
12573
printError(first,L"Endmacro directive not terminated");
12574
return false;
12575
}
12576
12577
macros[macro.name] = macro;
12578
return true;
12579
}
12580
12581
std::unique_ptr<CAssemblerCommand> Parser::parseMacroCall()
12582
{
12583
const Token& start = peekToken();
12584
if (start.type != TokenType::Identifier)
12585
return nullptr;
12586
12587
auto it = macros.find(start.getStringValue());
12588
if (it == macros.end())
12589
return nullptr;
12590
12591
ParserMacro& macro = it->second;
12592
eatToken();
12593
12594
// create a token stream for the macro content,
12595
// registering replacements for parameter values
12596
TokenStreamTokenizer macroTokenizer;
12597
12598
std::set<std::wstring> identifierParameters;
12599
for (size_t i = 0; i < macro.parameters.size(); i++)
12600
{
12601
if (peekToken().type == TokenType::Separator)
12602
{
12603
printError(start,L"Too few macro arguments (%d vs %d)",i,macro.parameters.size());
12604
return nullptr;
12605
}
12606
12607
if (i != 0)
12608
{
12609
if (nextToken().type != TokenType::Comma)
12610
{
12611
printError(start,L"Macro arguments not comma-separated");
12612
return nullptr;
12613
}
12614
}
12615
12616
TokenizerPosition startPos = getTokenizer()->getPosition();
12617
Expression exp = parseExpression();
12618
if (exp.isLoaded() == false)
12619
{
12620
printError(start,L"Invalid macro argument expression");
12621
return nullptr;
12622
}
12623
12624
TokenizerPosition endPos = getTokenizer()->getPosition();
12625
std::vector<Token> tokens = getTokenizer()->getTokens(startPos,endPos);
12626
12627
// remember any single identifier parameters for the label replacement
12628
if (tokens.size() == 1 && tokens[0].type == TokenType::Identifier)
12629
identifierParameters.insert(tokens[0].getStringValue());
12630
12631
// give them as a replacement to new tokenizer
12632
macroTokenizer.registerReplacement(macro.parameters[i],tokens);
12633
}
12634
12635
if (peekToken().type == TokenType::Comma)
12636
{
12637
size_t count = macro.parameters.size();
12638
while (peekToken().type == TokenType::Comma)
12639
{
12640
eatToken();
12641
parseExpression();
12642
count++;
12643
}
12644
12645
printError(start,L"Too many macro arguments (%d vs %d)",count,macro.parameters.size());
12646
return nullptr;
12647
}
12648
12649
if(nextToken().type != TokenType::Separator)
12650
{
12651
printError(start,L"Macro call not terminated");
12652
return nullptr;
12653
}
12654
12655
// skip macro instantiation in known false blocks
12656
if (!isInsideUnknownBlock() && !isInsideTrueBlock())
12657
return ::make_unique<DummyCommand>();
12658
12659
// a macro is fully parsed once when it's loaded
12660
// to gather all labels. it's not necessary to
12661
// instantiate other macros at that time
12662
if (initializingMacro)
12663
return ::make_unique<DummyCommand>();
12664
12665
// the first time a macro is instantiated, it needs to be analyzed
12666
// for labels
12667
if (macro.counter == 0)
12668
{
12669
initializingMacro = true;
12670
12671
// parse the short lived next command
12672
macroTokenizer.init(macro.content);
12673
Logger::suppressErrors();
12674
std::unique_ptr<CAssemblerCommand> command = parse(&macroTokenizer,true);
12675
Logger::unsuppressErrors();
12676
12677
macro.labels = macroLabels;
12678
macroLabels.clear();
12679
12680
initializingMacro = false;
12681
}
12682
12683
// register labels and replacements
12684
for (const std::wstring& label: macro.labels)
12685
{
12686
// check if the label is using the name of a parameter
12687
// in that case, don't register a unique replacement
12688
if (identifierParameters.find(label) != identifierParameters.end())
12689
continue;
12690
12691
// otherwise make sure the name is unique
12692
std::wstring fullName;
12693
if (Global.symbolTable.isLocalSymbol(label))
12694
fullName = formatString(L"@@%s_%s_%08X",macro.name,label.substr(2),macro.counter);
12695
else if (Global.symbolTable.isStaticSymbol(label))
12696
fullName = formatString(L"@%s_%s_%08X",macro.name,label.substr(1),macro.counter);
12697
else
12698
fullName = formatString(L"%s_%s_%08X",macro.name,label,macro.counter);
12699
12700
macroTokenizer.registerReplacement(label,fullName);
12701
}
12702
12703
macroTokenizer.init(macro.content);
12704
macro.counter++;
12705
12706
return parse(&macroTokenizer,true);
12707
12708
}
12709
12710
std::unique_ptr<CAssemblerCommand> Parser::parseLabel()
12711
{
12712
updateFileInfo();
12713
12714
const Token& start = peekToken(0);
12715
12716
if (peekToken(0).type == TokenType::Identifier &&
12717
peekToken(1).type == TokenType::Colon)
12718
{
12719
const std::wstring name = start.getStringValue();
12720
eatTokens(2);
12721
12722
if (initializingMacro)
12723
macroLabels.insert(name);
12724
12725
if (Global.symbolTable.isValidSymbolName(name) == false)
12726
{
12727
printError(start,L"Invalid label name \"%s\"",name);
12728
return nullptr;
12729
}
12730
12731
return ::make_unique<CAssemblerLabel>(name,start.getOriginalText());
12732
}
12733
12734
return nullptr;
12735
}
12736
12737
std::unique_ptr<CAssemblerCommand> Parser::handleError()
12738
{
12739
// skip the rest of the statement
12740
while (!atEnd() && nextToken().type != TokenType::Separator);
12741
12742
clearError();
12743
return ::make_unique<InvalidCommand>();
12744
}
12745
12746
12747
void Parser::updateFileInfo()
12748
{
12749
if (overrideFileInfo)
12750
{
12751
Global.FileInfo.FileNum = overrideFileNum;
12752
Global.FileInfo.LineNumber = overrideLineNum;
12753
return;
12754
}
12755
12756
for (size_t i = entries.size(); i > 0; i--)
12757
{
12758
size_t index = i-1;
12759
12760
if (entries[index].virtualFile == false && entries[index].fileNum != -1)
12761
{
12762
Global.FileInfo.FileNum = entries[index].fileNum;
12763
12764
// if it's not the topmost file, then the command to instantiate the
12765
// following files was already parsed -> take the previous command's line
12766
if (index != entries.size() - 1)
12767
Global.FileInfo.LineNumber = entries[index].previousCommandLine;
12768
else
12769
{
12770
Global.FileInfo.LineNumber = (int)entries[index].tokenizer->peekToken().line;
12771
entries[index].previousCommandLine = Global.FileInfo.LineNumber;
12772
}
12773
return;
12774
}
12775
}
12776
}
12777
12778
std::unique_ptr<CAssemblerCommand> Parser::parseCommand()
12779
{
12780
std::unique_ptr<CAssemblerCommand> command;
12781
12782
updateFileInfo();
12783
12784
if (atEnd())
12785
return ::make_unique<DummyCommand>();
12786
12787
if ((command = parseLabel()) != nullptr)
12788
return command;
12789
if (hasError())
12790
return handleError();
12791
12792
if ((command = parseMacroCall()) != nullptr)
12793
return command;
12794
if (hasError())
12795
return handleError();
12796
12797
if ((command = Arch->parseDirective(*this)) != nullptr)
12798
return command;
12799
if (hasError())
12800
return handleError();
12801
12802
if ((command = parseDirective(directives)) != nullptr)
12803
return command;
12804
if (hasError())
12805
return handleError();
12806
12807
if ((command = Arch->parseOpcode(*this)) != nullptr)
12808
return command;
12809
if (hasError())
12810
return handleError();
12811
12812
const Token& token = peekToken();
12813
printError(token,L"Parse error '%s'",token.getOriginalText());
12814
return handleError();
12815
}
12816
12817
void TokenSequenceParser::addEntry(int result, TokenSequence tokens, TokenValueSequence values)
12818
{
12819
Entry entry = { tokens, values, result };
12820
entries.push_back(entry);
12821
}
12822
12823
bool TokenSequenceParser::parse(Parser& parser, int& result)
12824
{
12825
for (Entry& entry: entries)
12826
{
12827
TokenizerPosition pos = parser.getTokenizer()->getPosition();
12828
auto values = entry.values.begin();
12829
12830
bool valid = true;
12831
for (TokenType type: entry.tokens)
12832
{
12833
// check of token type matches
12834
const Token& token = parser.nextToken();
12835
if (token.type != type)
12836
{
12837
valid = false;
12838
break;
12839
}
12840
12841
// if necessary, check if the value of the token also matches
12842
if (type == TokenType::Identifier)
12843
{
12844
if (values == entry.values.end() || values->textValue != token.getStringValue())
12845
{
12846
valid = false;
12847
break;
12848
}
12849
12850
values++;
12851
} else if (type == TokenType::Integer)
12852
{
12853
if (values == entry.values.end() || values->intValue != token.intValue)
12854
{
12855
valid = false;
12856
break;
12857
}
12858
12859
values++;
12860
}
12861
}
12862
12863
if (valid && values == entry.values.end())
12864
{
12865
result = entry.result;
12866
return true;
12867
}
12868
12869
parser.getTokenizer()->setPosition(pos);
12870
}
12871
12872
return false;
12873
}
12874
12875
// file: Parser/Tokenizer.cpp
12876
#include <algorithm>
12877
12878
12879
//
12880
// Tokenizer
12881
//
12882
12883
std::vector<std::vector<Token>> Tokenizer::equValues;
12884
12885
Tokenizer::Tokenizer()
12886
{
12887
position.it = tokens.begin();
12888
invalidToken.type = TokenType::Invalid;
12889
invalidToken.setOriginalText(L"Unexpected end of token stream");
12890
}
12891
12892
bool Tokenizer::processElement(TokenList::iterator& it)
12893
{
12894
if (it == tokens.end())
12895
return false;
12896
12897
while ((*it).checked == false)
12898
{
12899
bool replaced = false;
12900
if ((*it).type == TokenType::Identifier)
12901
{
12902
const std::wstring stringValue = (*it).getStringValue();
12903
for (const Replacement& replacement: replacements)
12904
{
12905
// if the identifier matches, add all of its tokens
12906
if (replacement.identifier == stringValue)
12907
{
12908
TokenList::iterator insertIt = it;
12909
insertIt++;
12910
12911
// replace old token with the new tokens
12912
// replace the first token manually so that any iterators
12913
// are still guaranteed to be valid
12914
(*it) = replacement.value[0];
12915
tokens.insert(insertIt,replacement.value.begin()+1, replacement.value.end());
12916
12917
// If the value at this position didn't change, then just keep going.
12918
// Otherwise we'd be stuck in an endless replace loop
12919
if (stringValue != (*it).getStringValue())
12920
replaced = true;
12921
break;
12922
}
12923
}
12924
12925
if (replaced)
12926
continue;
12927
12928
// check for equs
12929
size_t index;
12930
if (Global.symbolTable.findEquation(stringValue,Global.FileInfo.FileNum,Global.Section,index))
12931
{
12932
TokenList::iterator nextIt = it;
12933
std::advance(nextIt, 1);
12934
12935
// check if this is another equ with the same name.
12936
// if so, keep equ redefinitions for later error handling
12937
if (nextIt != tokens.end() && nextIt->type == TokenType::Equ)
12938
break;
12939
12940
// make room for the replacement tokens
12941
const std::vector<Token>& replacement = equValues[index];
12942
tokens.insert(nextIt, replacement.size()-1, {});
12943
12944
// insert replacement tokens, while keeping the file info of the original token
12945
Token originalToken = *it;
12946
12947
TokenList::iterator insertIt = it;
12948
for (const Token& token: replacement)
12949
{
12950
(*insertIt) = token;
12951
insertIt->line = originalToken.line;
12952
insertIt->column = originalToken.column;
12953
std::advance(insertIt, 1);
12954
}
12955
12956
replaced = true;
12957
continue;
12958
}
12959
}
12960
12961
if (replaced == false)
12962
(*it).checked = true;
12963
}
12964
12965
return true;
12966
}
12967
12968
const Token& Tokenizer::nextToken()
12969
{
12970
if (processElement(position.it) == false)
12971
return invalidToken;
12972
12973
return *position.it++;
12974
}
12975
12976
const Token& Tokenizer::peekToken(int ahead)
12977
{
12978
auto it = position.it;
12979
for (int i = 0; i < ahead; i++)
12980
{
12981
if (processElement(it) == false)
12982
return invalidToken;
12983
12984
it++;
12985
}
12986
12987
if (processElement(it) == false)
12988
return invalidToken;
12989
12990
return *it;
12991
}
12992
12993
void Tokenizer::eatTokens(int num)
12994
{
12995
for (int i = 0; i < num; i++)
12996
{
12997
if (processElement(position.it) == false)
12998
break;
12999
position.it++;
13000
}
13001
}
13002
13003
void Tokenizer::skipLookahead()
13004
{
13005
//position.index = tokens.size();
13006
}
13007
13008
std::vector<Token> Tokenizer::getTokens(TokenizerPosition start, TokenizerPosition end) const
13009
{
13010
std::vector<Token> result;
13011
13012
for (auto it = start.it; it != end.it; it++)
13013
{
13014
Token tok = *it;
13015
tok.checked = false;
13016
result.push_back(tok);
13017
}
13018
13019
return result;
13020
}
13021
13022
void Tokenizer::registerReplacement(const std::wstring& identifier, std::vector<Token>& tokens)
13023
{
13024
Replacement replacement { identifier, tokens };
13025
replacements.push_back(replacement);
13026
}
13027
13028
void Tokenizer::registerReplacement(const std::wstring& identifier, const std::wstring& newValue)
13029
{
13030
// Ensure the new identifier is lower case as it would be as a normally parsed string
13031
std::wstring lowerCase = newValue;
13032
std::transform(lowerCase.begin(), lowerCase.end(), lowerCase.begin(), ::towlower);
13033
13034
Token tok;
13035
tok.type = TokenType::Identifier;
13036
tok.setStringValue(lowerCase);
13037
tok.setOriginalText(newValue);
13038
13039
Replacement replacement;
13040
replacement.identifier = identifier;
13041
replacement.value.push_back(tok);
13042
13043
replacements.push_back(replacement);
13044
}
13045
13046
void Tokenizer::addToken(Token token)
13047
{
13048
tokens.push_back(std::move(token));
13049
}
13050
13051
size_t Tokenizer::addEquValue(const std::vector<Token>& tokens)
13052
{
13053
size_t index = equValues.size();
13054
equValues.push_back(tokens);
13055
return index;
13056
}
13057
13058
void Tokenizer::resetLookaheadCheckMarks()
13059
{
13060
auto it = position.it;
13061
while (it != tokens.end() && it->checked)
13062
{
13063
it->checked = false;
13064
it++;
13065
}
13066
}
13067
13068
//
13069
// FileTokenizer
13070
//
13071
13072
inline bool isWhitespace(const std::wstring& text, size_t pos)
13073
{
13074
if (pos >= text.size())
13075
return false;
13076
13077
return text[pos] == ' ' || text[pos] == '\t';
13078
}
13079
13080
inline bool isComment(const std::wstring& text, size_t pos)
13081
{
13082
if (pos < text.size() && text[pos] == ';')
13083
return true;
13084
13085
if (pos+1 < text.size() && text[pos+0] == '/' && text[pos+1] == '/')
13086
return true;
13087
13088
return false;
13089
}
13090
13091
inline bool isContinuation(const std::wstring& text, size_t pos)
13092
{
13093
if (pos >= text.size())
13094
return false;
13095
13096
return text[pos] == '\\';
13097
}
13098
13099
inline bool isBlockComment(const std::wstring& text, size_t pos){
13100
if (pos+1 < text.size() && text[pos+0] == '/' && text[pos+1] == '*')
13101
return true;
13102
13103
return false;
13104
}
13105
13106
inline bool isBlockCommentEnd(const std::wstring& text, size_t pos){
13107
if (pos+1 < text.size() && text[pos+0] == '*' && text[pos+1] == '/')
13108
return true;
13109
13110
return false;
13111
}
13112
13113
void FileTokenizer::skipWhitespace()
13114
{
13115
while (true)
13116
{
13117
if (isWhitespace(currentLine,linePos))
13118
{
13119
do { linePos++; } while (isWhitespace(currentLine,linePos));
13120
} else if (isComment(currentLine,linePos))
13121
{
13122
linePos = currentLine.size();
13123
} else if (isBlockComment(currentLine,linePos))
13124
{
13125
linePos += 2;
13126
while(!isBlockCommentEnd(currentLine,linePos))
13127
{
13128
linePos++;
13129
if (linePos >= currentLine.size())
13130
{
13131
if (isInputAtEnd())
13132
{
13133
createToken(TokenType::Invalid,linePos,L"Unexpected end of file in block comment");
13134
addToken(token);
13135
return;
13136
}
13137
currentLine = input->readLine();
13138
linePos = 0;
13139
lineNumber++;
13140
}
13141
}
13142
linePos += 2;
13143
} else
13144
{
13145
break;
13146
}
13147
}
13148
}
13149
13150
void FileTokenizer::createToken(TokenType type, size_t length)
13151
{
13152
token.type = type;
13153
token.line = lineNumber;
13154
token.column = linePos+1;
13155
token.setOriginalText(currentLine,linePos,length);
13156
13157
linePos += length;
13158
}
13159
13160
void FileTokenizer::createToken(TokenType type, size_t length, int64_t value)
13161
{
13162
token.type = type;
13163
token.line = lineNumber;
13164
token.column = linePos+1;
13165
token.setOriginalText(currentLine,linePos,length);
13166
token.intValue = value;
13167
13168
linePos += length;
13169
}
13170
13171
void FileTokenizer::createToken(TokenType type, size_t length, double value)
13172
{
13173
token.type = type;
13174
token.line = lineNumber;
13175
token.column = linePos+1;
13176
token.setOriginalText(currentLine,linePos,length);
13177
token.floatValue = value;
13178
13179
linePos += length;
13180
}
13181
13182
void FileTokenizer::createToken(TokenType type, size_t length, const std::wstring& value)
13183
{
13184
createToken(type, length, value, 0, value.length());
13185
}
13186
13187
void FileTokenizer::createToken(TokenType type, size_t length, const std::wstring& value, size_t valuePos, size_t valueLength)
13188
{
13189
token.type = type;
13190
token.line = lineNumber;
13191
token.column = linePos+1;
13192
token.setOriginalText(currentLine,linePos,length);
13193
token.setStringValue(value,valuePos,valueLength);
13194
13195
linePos += length;
13196
}
13197
13198
void FileTokenizer::createTokenCurrentString(TokenType type, size_t length)
13199
{
13200
token.type = type;
13201
token.line = lineNumber;
13202
token.column = linePos+1;
13203
token.setStringAndOriginalValue(currentLine,linePos,length);
13204
13205
linePos += length;
13206
}
13207
13208
bool FileTokenizer::parseOperator()
13209
{
13210
wchar_t first = currentLine[linePos];
13211
wchar_t second = linePos+1 >= currentLine.size() ? '\0' : currentLine[linePos+1];
13212
13213
switch (first)
13214
{
13215
case '(':
13216
createToken(TokenType::LParen,1);
13217
return true;
13218
case ')':
13219
createToken(TokenType::RParen,1);
13220
return true;
13221
case '+':
13222
createToken(TokenType::Plus,1);
13223
return true;
13224
case '-':
13225
createToken(TokenType::Minus,1);
13226
return true;
13227
case '*':
13228
createToken(TokenType::Mult,1);
13229
return true;
13230
case '/':
13231
createToken(TokenType::Div,1);
13232
return true;
13233
case '%':
13234
createToken(TokenType::Mod,1);
13235
return true;
13236
case '^':
13237
createToken(TokenType::Caret,1);
13238
return true;
13239
case '~':
13240
createToken(TokenType::Tilde,1);
13241
return true;
13242
case '<':
13243
if (second == '<')
13244
createToken(TokenType::LeftShift,2);
13245
else if (second == '=')
13246
createToken(TokenType::LessEqual,2);
13247
else
13248
createToken(TokenType::Less,1);
13249
return true;
13250
case '>':
13251
if (second == '>')
13252
createToken(TokenType::RightShift,2);
13253
else if (second == '=')
13254
createToken(TokenType::GreaterEqual,2);
13255
else
13256
createToken(TokenType::Greater,1);
13257
return true;
13258
case '=':
13259
if (second == '=')
13260
createToken(TokenType::Equal,2);
13261
else
13262
createToken(TokenType::Assign,1);
13263
return true;
13264
case '!':
13265
if (second == '=')
13266
createToken(TokenType::NotEqual,2);
13267
else
13268
createToken(TokenType::Exclamation,1);
13269
return true;
13270
case '&':
13271
if (second == '&')
13272
createToken(TokenType::LogAnd,2);
13273
else
13274
createToken(TokenType::BitAnd,1);
13275
return true;
13276
case '|':
13277
if (second == '|')
13278
createToken(TokenType::LogOr,2);
13279
else
13280
createToken(TokenType::BitOr,1);
13281
return true;
13282
case '?':
13283
createToken(TokenType::Question,1);
13284
return true;
13285
case ':':
13286
if (second == ':')
13287
createToken(TokenType::Separator,2);
13288
else
13289
createToken(TokenType::Colon,1);
13290
return true;
13291
case ',':
13292
createToken(TokenType::Comma,1);
13293
return true;
13294
case '[':
13295
createToken(TokenType::LBrack,1);
13296
return true;
13297
case ']':
13298
createToken(TokenType::RBrack,1);
13299
return true;
13300
case '#':
13301
createToken(TokenType::Hash,1);
13302
return true;
13303
case '{':
13304
createToken(TokenType::LBrace,1);
13305
return true;
13306
case '}':
13307
createToken(TokenType::RBrace,1);
13308
return true;
13309
case '$':
13310
createToken(TokenType::Dollar,1);
13311
return true;
13312
case L'\U000000B0': // degree sign
13313
createToken(TokenType::Degree,1);
13314
return true;
13315
}
13316
13317
return false;
13318
}
13319
13320
bool FileTokenizer::convertInteger(size_t start, size_t end, int64_t& result)
13321
{
13322
return stringToInt(currentLine, start, end, result);
13323
}
13324
13325
bool FileTokenizer::convertFloat(size_t start, size_t end, double& result)
13326
{
13327
std::wstring str = currentLine.substr(start, end - start);
13328
wchar_t* end_ptr;
13329
13330
result = wcstod(str.c_str(), &end_ptr);
13331
return str.c_str() + str.size() == end_ptr;
13332
}
13333
13334
Token FileTokenizer::loadToken()
13335
{
13336
if (isInputAtEnd())
13337
{
13338
createToken(TokenType::Invalid,0);
13339
return std::move(token);
13340
}
13341
13342
size_t pos = linePos;
13343
13344
if (equActive)
13345
{
13346
while (pos < currentLine.size() && !isComment(currentLine,pos))
13347
pos++;
13348
13349
createTokenCurrentString(TokenType::EquValue,pos-linePos);
13350
13351
equActive = false;
13352
return std::move(token);
13353
}
13354
13355
if (parseOperator())
13356
return std::move(token);
13357
13358
wchar_t first = currentLine[pos];
13359
13360
// character constants
13361
if (first == '\'' && pos+2 < currentLine.size() && currentLine[pos+2] == '\'')
13362
{
13363
createToken(TokenType::Integer,3,(int64_t)currentLine[pos+1]);
13364
return std::move(token);
13365
}
13366
13367
// strings
13368
if (first == '"')
13369
{
13370
std::wstring text;
13371
pos++;
13372
13373
bool valid = false;
13374
while (pos < currentLine.size())
13375
{
13376
if (pos+1 < currentLine.size() && currentLine[pos] == '\\')
13377
{
13378
if (currentLine[pos+1] == '"')
13379
{
13380
text += '"';
13381
pos += 2;
13382
continue;
13383
}
13384
13385
if (currentLine[pos+1] == '\\')
13386
{
13387
text += '\\';
13388
pos += 2;
13389
continue;
13390
}
13391
}
13392
13393
if (currentLine[pos] == '"')
13394
{
13395
pos++;
13396
valid = true;
13397
break;
13398
}
13399
13400
text += currentLine[pos++];
13401
}
13402
13403
if (!valid)
13404
{
13405
createToken(TokenType::Invalid,pos-linePos,L"Unexpected end of line in string constant");
13406
return std::move(token);
13407
}
13408
13409
createToken(TokenType::String,pos-linePos,text);
13410
return std::move(token);
13411
}
13412
13413
// numbers
13414
if (first >= '0' && first <= '9')
13415
{
13416
// find end of number
13417
size_t start = pos;
13418
size_t end = pos;
13419
bool isValid = true;
13420
bool foundPoint = false;
13421
bool foundExp = false;
13422
bool foundExpSign = false;
13423
bool isHex = start+1 < currentLine.size() && currentLine[start] == '0' && towlower(currentLine[start+1]) == 'x';
13424
13425
while (end < currentLine.size() && (iswalnum(currentLine[end]) || currentLine[end] == '.'))
13426
{
13427
if (currentLine[end] == '.')
13428
{
13429
if (foundExp || foundPoint)
13430
isValid = false;
13431
foundPoint = true;
13432
} else if (towlower(currentLine[end]) == 'h' && !foundExpSign) {
13433
isHex = true;
13434
} else if (towlower(currentLine[end]) == 'e' && !isHex)
13435
{
13436
if (foundExp)
13437
{
13438
isValid = false;
13439
} else if (end+1 < currentLine.size() && (currentLine[end+1] == '+' || currentLine[end+1] == '-')){
13440
end++;
13441
if (end+1 >= currentLine.size() || !iswalnum(currentLine[end+1]))
13442
isValid = false;
13443
foundExpSign = true;
13444
}
13445
foundExp = true;
13446
}
13447
13448
end++;
13449
}
13450
13451
bool isFloat = foundPoint || (foundExp && !isHex);
13452
13453
if (!isFloat)
13454
{
13455
int64_t value;
13456
if (convertInteger(start,end,value) == false)
13457
{
13458
createTokenCurrentString(TokenType::NumberString,end-start);
13459
return std::move(token);
13460
}
13461
13462
createToken(TokenType::Integer,end-start,value);
13463
} else { // isFloat
13464
double value;
13465
if (isValid == false)
13466
{
13467
createToken(TokenType::Invalid,end-start,L"Invalid floating point number");
13468
return std::move(token);
13469
}
13470
13471
if (convertFloat(start,end,value) == false)
13472
{
13473
createTokenCurrentString(TokenType::NumberString,end-start);
13474
return std::move(token);
13475
}
13476
13477
createToken(TokenType::Float,end-start,value);
13478
}
13479
13480
return std::move(token);
13481
}
13482
13483
// identifiers
13484
bool isFirst = true;
13485
while (pos < currentLine.size() && Global.symbolTable.isValidSymbolCharacter(currentLine[pos],isFirst))
13486
{
13487
pos++;
13488
isFirst = false;
13489
}
13490
13491
if (pos == linePos)
13492
{
13493
std::wstring text = formatString(L"Invalid input '%c'",currentLine[pos]);
13494
createToken(TokenType::Invalid,1,text);
13495
return std::move(token);
13496
}
13497
13498
std::wstring text = currentLine.substr(linePos,pos-linePos);
13499
bool textLowered = false;
13500
// Lowercase is common, let's try to avoid a copy.
13501
if (std::any_of(text.begin(), text.end(), ::iswupper))
13502
{
13503
std::transform(text.begin(), text.end(), text.begin(), ::towlower);
13504
textLowered = true;
13505
}
13506
13507
if (text == L"equ")
13508
{
13509
createToken(TokenType::Equ,pos-linePos);
13510
equActive = true;
13511
} else if (textLowered) {
13512
createToken(TokenType::Identifier,pos-linePos,text);
13513
} else {
13514
createTokenCurrentString(TokenType::Identifier,pos-linePos);
13515
}
13516
13517
return std::move(token);
13518
}
13519
13520
bool FileTokenizer::init(TextFile* input)
13521
{
13522
clearTokens();
13523
13524
lineNumber = 1;
13525
linePos = 0;
13526
equActive = false;
13527
currentLine = input->readLine();
13528
13529
this->input = input;
13530
if (input != nullptr && input->isOpen())
13531
{
13532
while (!isInputAtEnd())
13533
{
13534
bool addSeparator = true;
13535
13536
skipWhitespace();
13537
if (isContinuation(currentLine, linePos))
13538
{
13539
linePos++;
13540
skipWhitespace();
13541
if (linePos < currentLine.size())
13542
{
13543
createToken(TokenType::Invalid,0,
13544
L"Unexpected character after line continuation character");
13545
addToken(token);
13546
}
13547
13548
addSeparator = false;
13549
} else if(linePos < currentLine.size())
13550
{
13551
addToken(std::move(loadToken()));
13552
}
13553
13554
if (linePos >= currentLine.size())
13555
{
13556
if (addSeparator)
13557
{
13558
createToken(TokenType::Separator,0);
13559
addToken(token);
13560
}
13561
13562
if (input->atEnd())
13563
break;
13564
13565
currentLine = input->readLine();
13566
linePos = 0;
13567
lineNumber++;
13568
}
13569
}
13570
13571
resetPosition();
13572
return true;
13573
}
13574
13575
return false;
13576
}
13577
13578
// file: Util/ByteArray.cpp
13579
13580
ByteArray::ByteArray()
13581
{
13582
data_ = nullptr;
13583
size_ = allocatedSize_ = 0;
13584
}
13585
13586
ByteArray::ByteArray(const ByteArray& other)
13587
{
13588
data_ = nullptr;
13589
size_ = allocatedSize_ = 0;
13590
append(other);
13591
}
13592
13593
ByteArray::ByteArray(byte* data, size_t size)
13594
{
13595
data_ = nullptr;
13596
size_ = allocatedSize_ = 0;
13597
append(data,size);
13598
}
13599
13600
ByteArray::ByteArray(ByteArray&& other)
13601
{
13602
data_ = other.data_;
13603
size_ = other.size_;
13604
allocatedSize_ = other.allocatedSize_;
13605
other.data_ = nullptr;
13606
other.allocatedSize_ = other.size_ = 0;
13607
}
13608
13609
ByteArray::~ByteArray()
13610
{
13611
free(data_);
13612
}
13613
13614
ByteArray& ByteArray::operator=(ByteArray& other)
13615
{
13616
free(data_);
13617
data_ = nullptr;
13618
size_ = allocatedSize_ = 0;
13619
append(other);
13620
13621
return *this;
13622
}
13623
13624
ByteArray& ByteArray::operator=(ByteArray&& other)
13625
{
13626
data_ = other.data_;
13627
size_ = other.size_;
13628
allocatedSize_ = other.allocatedSize_;
13629
other.data_ = nullptr;
13630
other.allocatedSize_ = other.size_ = 0;
13631
return *this;
13632
}
13633
13634
void ByteArray::grow(size_t neededSize)
13635
{
13636
if (neededSize < allocatedSize_) return;
13637
13638
// align to next 0.5kb... it's a start
13639
allocatedSize_ = ((neededSize+511)/512)*512;
13640
if (data_ == nullptr)
13641
{
13642
data_ = (byte*) malloc(allocatedSize_);
13643
} else {
13644
data_ = (byte*) realloc(data_,allocatedSize_);
13645
}
13646
}
13647
13648
size_t ByteArray::append(const ByteArray& other)
13649
{
13650
size_t oldSize = size();
13651
size_t otherSize = other.size();
13652
grow(size()+otherSize);
13653
memcpy(&data_[size_],other.data(),otherSize);
13654
size_ += otherSize;
13655
return oldSize;
13656
}
13657
13658
size_t ByteArray::append(void* data, size_t size)
13659
{
13660
size_t oldSize = this->size();
13661
grow(this->size()+size);
13662
memcpy(&data_[size_],data,size);
13663
this->size_ += size;
13664
return oldSize;
13665
}
13666
13667
void ByteArray::replaceBytes(size_t pos, byte* data, size_t size)
13668
{
13669
for (size_t i = 0; i < size; i++)
13670
{
13671
replaceByte(pos+i,data[i]);
13672
}
13673
}
13674
13675
void ByteArray::reserveBytes(size_t count, byte value)
13676
{
13677
grow(this->size()+count);
13678
memset(&data_[size_],value,count);
13679
size_ += count;
13680
}
13681
13682
void ByteArray::alignSize(size_t alignment)
13683
{
13684
if (alignment <= 0) return;
13685
13686
while (size_ % alignment)
13687
{
13688
appendByte(0);
13689
}
13690
}
13691
13692
void ByteArray::resize(size_t newSize)
13693
{
13694
grow(newSize);
13695
size_ = newSize;
13696
}
13697
13698
ByteArray ByteArray::mid(size_t start, ssize_t length)
13699
{
13700
ByteArray ret;
13701
13702
if (length < 0)
13703
length = size_-start;
13704
13705
if (start >= size_)
13706
return ret;
13707
13708
ret.grow(length);
13709
ret.size_ = length;
13710
memcpy(ret.data_,&data_[start],length);
13711
return ret;
13712
}
13713
13714
ByteArray ByteArray::fromFile(const std::wstring& fileName, long start, size_t size)
13715
{
13716
ByteArray ret;
13717
13718
FILE* input = openFile(fileName,OpenFileMode::ReadBinary);
13719
if (input == nullptr)
13720
return ret;
13721
13722
fseek(input,0,SEEK_END);
13723
long fileSize = ftell(input);
13724
13725
if (start >= fileSize)
13726
{
13727
fclose(input);
13728
return ret;
13729
}
13730
13731
if (size == 0 || start+(long)size > fileSize)
13732
size = fileSize-start;
13733
13734
fseek(input,start,SEEK_SET);
13735
13736
ret.grow(size);
13737
ret.size_ = fread(ret.data(),1,size,input);
13738
fclose(input);
13739
13740
return ret;
13741
}
13742
13743
bool ByteArray::toFile(const std::wstring& fileName)
13744
{
13745
FILE* output = openFile(fileName,OpenFileMode::WriteBinary);
13746
if (output == nullptr) return false;
13747
size_t length = fwrite(data_,1,size_,output);
13748
fclose(output);
13749
return length == size_;
13750
}
13751
13752
// file: Util/CRC.cpp
13753
#include <stdio.h>
13754
13755
const unsigned short Crc16Table[] = /* CRC lookup table */
13756
{
13757
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
13758
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
13759
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
13760
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
13761
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
13762
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
13763
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
13764
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
13765
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
13766
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
13767
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
13768
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
13769
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
13770
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
13771
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
13772
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
13773
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
13774
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
13775
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
13776
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
13777
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
13778
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
13779
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
13780
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
13781
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
13782
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
13783
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
13784
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
13785
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
13786
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
13787
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
13788
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
13789
};
13790
13791
const unsigned int Crc32Table[256] = {
13792
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,
13793
0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
13794
0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
13795
0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
13796
0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,
13797
0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
13798
0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
13799
0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
13800
0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
13801
0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
13802
0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,
13803
0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
13804
0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,
13805
0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
13806
0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
13807
0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
13808
0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,
13809
0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
13810
0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,
13811
0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
13812
0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
13813
0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
13814
0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,
13815
0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
13816
0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,
13817
0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
13818
0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
13819
0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
13820
0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,
13821
0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
13822
0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,
13823
0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D
13824
};
13825
13826
unsigned short getCrc16(unsigned char* Source, size_t len)
13827
{
13828
unsigned short crc = 0xFFFF;
13829
13830
while (len--)
13831
{
13832
crc = (crc >> 8) ^ Crc16Table[(crc ^ *Source++) & 0xFF];
13833
}
13834
return crc;
13835
}
13836
13837
unsigned int getCrc32(unsigned char* Source, size_t len)
13838
{
13839
unsigned int crc = 0xFFFFFFFF;
13840
13841
while (len--)
13842
{
13843
crc = (crc >> 8) ^ Crc32Table[(crc & 0xFF) ^ *Source++];
13844
}
13845
13846
return crc ^ 0xffffffff;
13847
}
13848
13849
13850
unsigned int getChecksum(unsigned char* Source, size_t len)
13851
{
13852
int checksum = 0;
13853
for (size_t i = 0; i < len; i++)
13854
checksum += *Source++;
13855
return checksum;
13856
}
13857
13858
// file: Util/EncodingTable.cpp
13859
13860
#define MAXHEXLENGTH 32
13861
13862
Trie::Trie()
13863
{
13864
Node root { 0, false, 0 };
13865
nodes.push_back(root);
13866
}
13867
13868
void Trie::insert(const wchar_t* text, size_t value)
13869
{
13870
size_t node = 0; // root node
13871
13872
// traverse existing nodes
13873
while (*text != 0)
13874
{
13875
LookupEntry lookupEntry { node, *text };
13876
auto it = lookup.find(lookupEntry);
13877
if (it == lookup.end())
13878
break;
13879
13880
node = it->second;
13881
text++;
13882
}
13883
13884
// add new nodes as necessary
13885
while (*text != 0)
13886
{
13887
Node newNode { nodes.size(), false, 0 };
13888
nodes.push_back(newNode);
13889
13890
LookupEntry lookupEntry { node, *text };
13891
lookup[lookupEntry] = newNode.index;
13892
node = newNode.index;
13893
text++;
13894
}
13895
13896
// set value
13897
nodes[node].hasValue = true;
13898
nodes[node].value = value;
13899
}
13900
13901
void Trie::insert(wchar_t character, size_t value)
13902
{
13903
wchar_t str[2];
13904
str[0] = character;
13905
str[1] = 0;
13906
insert(str,value);
13907
}
13908
13909
bool Trie::findLongestPrefix(const wchar_t* text, size_t& result)
13910
{
13911
size_t node = 0; // root node
13912
size_t valueNode = 0; // remember last node that had a value
13913
13914
while (*text != 0)
13915
{
13916
if (nodes[node].hasValue)
13917
valueNode = node;
13918
13919
LookupEntry lookupEntry { node, *text++ };
13920
auto it = lookup.find(lookupEntry);
13921
13922
if (it == lookup.end())
13923
break;
13924
13925
node = it->second;
13926
}
13927
13928
if (nodes[node].hasValue)
13929
valueNode = node;
13930
13931
result = nodes[valueNode].value;
13932
return nodes[valueNode].hasValue;
13933
}
13934
13935
EncodingTable::EncodingTable()
13936
{
13937
13938
}
13939
13940
EncodingTable::~EncodingTable()
13941
{
13942
13943
}
13944
13945
void EncodingTable::clear()
13946
{
13947
hexData.clear();
13948
entries.clear();
13949
}
13950
13951
int parseHexString(std::wstring& hex, unsigned char* dest)
13952
{
13953
for (size_t i = 0; i < hex.size(); i++)
13954
{
13955
wchar_t source = towlower(hex[i]);
13956
int value;
13957
13958
if (source >= 'a' && source <= 'f')
13959
{
13960
value = source-'a'+10;
13961
} else if (source >= '0' && source <= '9')
13962
{
13963
value = source-'0';
13964
} else {
13965
return -1;
13966
}
13967
13968
size_t index = i/2;
13969
if (i % 2)
13970
dest[index] = (dest[index] << 4) | value;
13971
else
13972
dest[index] = value;
13973
}
13974
13975
return (int) hex.size()/2;
13976
}
13977
13978
bool EncodingTable::load(const std::wstring& fileName, TextFile::Encoding encoding)
13979
{
13980
unsigned char hexBuffer[MAXHEXLENGTH];
13981
13982
TextFile input;
13983
if (input.open(fileName,TextFile::Read,encoding) == false)
13984
return false;
13985
13986
hexData.clear();
13987
entries.clear();
13988
setTerminationEntry((unsigned char*)"\0",1);
13989
13990
while (!input.atEnd())
13991
{
13992
std::wstring line = input.readLine();
13993
if (line.empty() || line[0] == '*') continue;
13994
13995
if (line[0] == '/')
13996
{
13997
std::wstring hex = line.substr(1);
13998
if (hex.empty() || hex.length() > 2*MAXHEXLENGTH)
13999
{
14000
// error
14001
continue;
14002
}
14003
14004
int length = parseHexString(hex,hexBuffer);
14005
if (length == -1)
14006
{
14007
// error
14008
continue;
14009
}
14010
14011
setTerminationEntry(hexBuffer,length);
14012
} else {
14013
size_t pos = line.find(L'=');
14014
std::wstring hex = line.substr(0,pos);
14015
std::wstring value = line.substr(pos+1);
14016
14017
if (hex.empty() || value.empty() || hex.length() > 2*MAXHEXLENGTH)
14018
{
14019
// error
14020
continue;
14021
}
14022
14023
int length = parseHexString(hex,hexBuffer);
14024
if (length == -1)
14025
{
14026
// error
14027
continue;
14028
}
14029
14030
addEntry(hexBuffer,length,value);
14031
}
14032
}
14033
14034
return true;
14035
}
14036
14037
void EncodingTable::addEntry(unsigned char* hex, size_t hexLength, const std::wstring& value)
14038
{
14039
if (value.size() == 0)
14040
return;
14041
14042
// insert into trie
14043
size_t index = entries.size();
14044
lookup.insert(value.c_str(),index);
14045
14046
// add entry
14047
TableEntry entry;
14048
entry.hexPos = hexData.append(hex,hexLength);
14049
entry.hexLen = hexLength;
14050
entry.valueLen = value.size();
14051
14052
entries.push_back(entry);
14053
}
14054
14055
void EncodingTable::addEntry(unsigned char* hex, size_t hexLength, wchar_t value)
14056
{
14057
if (value == '\0')
14058
return;
14059
14060
// insert into trie
14061
size_t index = entries.size();
14062
lookup.insert(value,index);
14063
14064
// add entry
14065
TableEntry entry;
14066
entry.hexPos = hexData.append(hex,hexLength);
14067
entry.hexLen = hexLength;
14068
entry.valueLen = 1;
14069
14070
entries.push_back(entry);
14071
14072
}
14073
14074
void EncodingTable::setTerminationEntry(unsigned char* hex, size_t hexLength)
14075
{
14076
terminationEntry.hexPos = hexData.append(hex,hexLength);
14077
terminationEntry.hexLen = hexLength;
14078
terminationEntry.valueLen = 0;
14079
}
14080
14081
ByteArray EncodingTable::encodeString(const std::wstring& str, bool writeTermination)
14082
{
14083
ByteArray result;
14084
14085
size_t pos = 0;
14086
while (pos < str.size())
14087
{
14088
size_t index;
14089
if (lookup.findLongestPrefix(str.c_str()+pos,index) == false)
14090
{
14091
// error
14092
return ByteArray();
14093
}
14094
14095
TableEntry& entry = entries[index];
14096
for (size_t i = 0; i < entry.hexLen; i++)
14097
{
14098
result.appendByte(hexData[entry.hexPos+i]);
14099
}
14100
14101
pos += entry.valueLen;
14102
}
14103
14104
if (writeTermination)
14105
{
14106
TableEntry& entry = terminationEntry;
14107
for (size_t i = 0; i < entry.hexLen; i++)
14108
{
14109
result.appendByte(hexData[entry.hexPos+i]);
14110
}
14111
}
14112
14113
return result;
14114
}
14115
14116
ByteArray EncodingTable::encodeTermination()
14117
{
14118
ByteArray result;
14119
14120
TableEntry& entry = terminationEntry;
14121
for (size_t i = 0; i < entry.hexLen; i++)
14122
{
14123
result.appendByte(hexData[entry.hexPos+i]);
14124
}
14125
14126
return result;
14127
}
14128
14129
// file: Util/FileClasses.cpp
14130
14131
const wchar_t SjisToUnicodeTable1[] =
14132
{
14133
// 0X0080 to 0X00FF
14134
0x0080, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14135
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14136
0xFFFF, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
14137
0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
14138
0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
14139
0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
14140
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14141
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14142
};
14143
14144
const wchar_t SjisToUnicodeTable2[] =
14145
{
14146
// 0X8100 to 0X81FF
14147
0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E,
14148
0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD, 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C,
14149
0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C, 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B,
14150
0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0xFFFF,
14151
0x00F7, 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5,
14152
0xFF04, 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7, 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7, 0x25C6,
14153
0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0xFFFF, 0xFFFF, 0xFFFF,
14154
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283, 0x222A, 0x2229,
14155
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x2227, 0x2228, 0xFFE2, 0x21D2, 0x21D4, 0x2200, 0x2203, 0xFFFF,
14156
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207, 0x2261,
14157
0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235, 0x222B, 0x222C, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14158
0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, 0x2021, 0x00B6, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x25EF, 0xFFFF, 0xFFFF, 0xFFFF,
14159
// 0X8200 to 0X82FF
14160
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFF10,
14161
0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14162
0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30,
14163
0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14164
0xFFFF, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
14165
0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x3041,
14166
0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050, 0x3051,
14167
0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, 0x3061,
14168
0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070, 0x3071,
14169
0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, 0x3080, 0x3081,
14170
0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, 0x3090, 0x3091,
14171
0x3092, 0x3093, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14172
// 0X8300 to 0X83FF
14173
0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7, 0x30A8, 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF, 0x30B0,
14174
0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7, 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF, 0x30C0,
14175
0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7, 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D0,
14176
0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7, 0x30D8, 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF, 0xFFFF,
14177
0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF,
14178
0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0391,
14179
0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1,
14180
0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x03B1,
14181
0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1,
14182
0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14183
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14184
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14185
// 0X8400 to 0X84FF
14186
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
14187
0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E,
14188
0x042F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14189
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0xFFFF,
14190
0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D,
14191
0x044E, 0x044F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x2500,
14192
0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C, 0x252C, 0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513, 0x251B, 0x2517,
14193
0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520, 0x252F, 0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538, 0x2542, 0xFFFF,
14194
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14195
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14196
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14197
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14198
};
14199
14200
const wchar_t SjisToUnicodeTable3[] =
14201
{
14202
// 0X8700 to 0X87FF
14203
0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F,
14204
0x2470, 0x2471, 0x2472, 0x2473, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0xFFFF, 0x3349,
14205
0x3314, 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336, 0x3351, 0x3357, 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B, 0x339C,
14206
0x339D, 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x337B, 0xFFFF,
14207
0x301D, 0x301F, 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6, 0x32A7, 0x32A8, 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C,
14208
0x2252, 0x2261, 0x222B, 0x222E, 0x2211, 0x221A, 0x22A5, 0x2220, 0x221F, 0x22BF, 0x2235, 0x2229, 0x222A, 0xFFFF, 0xFFFF, 0xFFFF,
14209
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14210
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14211
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14212
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14213
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14214
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14215
// 0X8800 to 0X88FF
14216
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14217
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14218
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14219
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14220
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14221
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x4E9C,
14222
0x5516, 0x5A03, 0x963F, 0x54C0, 0x611B, 0x6328, 0x59F6, 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25, 0x65ED, 0x8466,
14223
0x82A6, 0x9BF5, 0x6893, 0x5727, 0x65A1, 0x6271, 0x5B9B, 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, 0x9B8E, 0x6216, 0x7C9F, 0x88B7,
14224
0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7, 0x978D, 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, 0x5049, 0x56F2, 0x5937, 0x59D4,
14225
0x5A01, 0x5C09, 0x60DF, 0x610F, 0x6170, 0x6613, 0x6905, 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3, 0x840E, 0x8863,
14226
0x8B02, 0x9055, 0x907A, 0x533B, 0x4E95, 0x4EA5, 0x57DF, 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, 0x6EA2, 0x9038, 0x7A32, 0x8328,
14227
0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1, 0x56E0, 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, 0x852D, 0xFFFF, 0xFFFF, 0xFFFF,
14228
// 0X8900 to 0X89FF
14229
0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, 0x70CF, 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11, 0x7893,
14230
0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B, 0x59E5, 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, 0x96F2,
14231
0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620, 0x66F3, 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E, 0x9834,
14232
0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, 0x99C5, 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186, 0xFFFF,
14233
0x5712, 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4, 0x6CBF, 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01,
14234
0x8276, 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC, 0x6C5A, 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC, 0x62BC,
14235
0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, 0x9D2C, 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B, 0x61B6,
14236
0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069, 0x6E29, 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, 0x4FA1,
14237
0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6, 0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B, 0x73C2,
14238
0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, 0x8377, 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6, 0x904E,
14239
0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B, 0x81E5, 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, 0x4F1A,
14240
0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A, 0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539, 0xFFFF, 0xFFFF, 0xFFFF,
14241
// 0X8A00 to 0X8AFF
14242
0x9B41, 0x6666, 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, 0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916,
14243
0x54B3, 0x5BB3, 0x5D16, 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB, 0x8857, 0x8A72, 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3,
14244
0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1, 0x64B9, 0x683C, 0x6838, 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A,
14245
0x89D2, 0x8D6B, 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, 0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, 0x6A2B, 0xFFFF,
14246
0x6A7F, 0x68B6, 0x9C0D, 0x6F5F, 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, 0x6E07, 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39,
14247
0x53F6, 0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC, 0x938C, 0x565B, 0x9D28, 0x6822, 0x8305, 0x8431, 0x7CA5,
14248
0x5208, 0x82C5, 0x74E6, 0x4E7E, 0x4F83, 0x51A0, 0x5BD2, 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6, 0x5B8C, 0x5B98,
14249
0x5BDB, 0x5E72, 0x5E79, 0x60A3, 0x611F, 0x6163, 0x61BE, 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, 0x6B3E, 0x6B53, 0x6C57, 0x6F22,
14250
0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B, 0x7AFF, 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, 0x809D, 0x8266, 0x839E, 0x89B3,
14251
0x8ACC, 0x8CAB, 0x9084, 0x9451, 0x9593, 0x9591, 0x95A2, 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8, 0x5DCC, 0x73A9,
14252
0x764C, 0x773C, 0x5CA9, 0x7FEB, 0x8D0B, 0x96C1, 0x9811, 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, 0x559C, 0x5668, 0x57FA, 0x5947,
14253
0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC, 0x63EE, 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, 0x68C4, 0xFFFF, 0xFFFF, 0xFFFF,
14254
// 0X8B00 to 0X8BFF
14255
0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, 0x5B63, 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77, 0x8ECC,
14256
0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100, 0x5993, 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, 0x7947,
14257
0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0, 0x5409, 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775, 0x9ECD,
14258
0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, 0x4EC7, 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551, 0xFFFF,
14259
0x673D, 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE, 0x7B08, 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45,
14260
0x5DE8, 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD, 0x92F8, 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC, 0x4F9B,
14261
0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, 0x5321, 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A, 0x602F,
14262
0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2, 0x72ED, 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, 0x97FF,
14263
0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D, 0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4, 0x5747,
14264
0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, 0x79BD, 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39, 0x8FD1,
14265
0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A, 0x72D7, 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, 0x5177,
14266
0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047, 0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48, 0xFFFF, 0xFFFF, 0xFFFF,
14267
// 0X8C00 to 0X8CFF
14268
0x6398, 0x7A9F, 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, 0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB,
14269
0x8A13, 0x7FA4, 0x8ECD, 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2, 0x50BE, 0x5211, 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951,
14270
0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A, 0x656C, 0x666F, 0x6842, 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C,
14271
0x7D99, 0x7E4B, 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, 0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0xFFFF,
14272
0x5287, 0x621F, 0x6483, 0x6FC0, 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, 0x6F54, 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6,
14273
0x5039, 0x5026, 0x5065, 0x517C, 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805, 0x5ACC, 0x5EFA, 0x61B2, 0x61F8, 0x62F3, 0x6372, 0x691C,
14274
0x6A29, 0x727D, 0x72AC, 0x732E, 0x7814, 0x786F, 0x7D79, 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063, 0x9375, 0x967A,
14275
0x9855, 0x9A13, 0x9E78, 0x5143, 0x539F, 0x53B3, 0x5E7B, 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, 0x7D43, 0x8237, 0x8A00, 0x8AFA,
14276
0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA, 0x59D1, 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, 0x6545, 0x67AF, 0x6E56, 0x72D0,
14277
0x7CCA, 0x88B4, 0x80A1, 0x80E1, 0x83F0, 0x864E, 0x8A87, 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92, 0x4F0D, 0x5348,
14278
0x5449, 0x543E, 0x5A2F, 0x5F8C, 0x5FA1, 0x609F, 0x68A7, 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, 0x8B77, 0x9190, 0x4E5E, 0x9BC9,
14279
0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149, 0x516C, 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, 0x5411, 0xFFFF, 0xFFFF, 0xFFFF,
14280
// 0X8D00 to 0X8DFF
14281
0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, 0x5B8F, 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7, 0x5F18,
14282
0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602, 0x6643, 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, 0x6D69,
14283
0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0, 0x7D05, 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1, 0x8154,
14284
0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, 0x8CFC, 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D, 0xFFFF,
14285
0x9805, 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408, 0x58D5, 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B,
14286
0x544A, 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09, 0x8170, 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC, 0x6B64,
14287
0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, 0x61C7, 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A, 0x826E,
14288
0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6, 0x5DEE, 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, 0x5750,
14289
0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9, 0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73, 0x6E08,
14290
0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, 0x7D30, 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750, 0x7F6A,
14291
0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4, 0x54B2, 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, 0x643E,
14292
0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F, 0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237, 0xFFFF, 0xFFFF, 0xFFFF,
14293
// 0X8E00 to 0X8EFF
14294
0x5BDF, 0x62F6, 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, 0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09,
14295
0x5098, 0x53C2, 0x5C71, 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6, 0x73CA, 0x7523, 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178,
14296
0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F, 0x523A, 0x53F8, 0x53F2, 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9,
14297
0x59FF, 0x5B50, 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, 0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, 0x6B62, 0xFFFF,
14298
0x6B7B, 0x6C0F, 0x7345, 0x7949, 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, 0x8102, 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C,
14299
0x8AEE, 0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D, 0x5150, 0x5B57, 0x5BFA, 0x6148, 0x6301, 0x6642, 0x6B21,
14300
0x6ECB, 0x6CBB, 0x723E, 0x74BD, 0x75D4, 0x78C1, 0x793A, 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F, 0x5F0F, 0x8B58,
14301
0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, 0x96EB, 0x4E03, 0x53F1, 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, 0x6E7F, 0x6F06, 0x75BE, 0x8CEA,
14302
0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D, 0x5C61, 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, 0x6368, 0x8D66, 0x659C, 0x716E,
14303
0x793E, 0x7D17, 0x8005, 0x8B1D, 0x8ECA, 0x906E, 0x86C7, 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235, 0x914C, 0x91C8,
14304
0x932B, 0x82E5, 0x5BC2, 0x5F31, 0x60F9, 0x4E3B, 0x53D6, 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, 0x73E0, 0x7A2E, 0x816B, 0x8DA3,
14305
0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF, 0x6388, 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, 0x5468, 0xFFFF, 0xFFFF, 0xFFFF,
14306
// 0X8F00 to 0X8FFF
14307
0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, 0x79C0, 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490, 0x8846,
14308
0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C, 0x96C6, 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, 0x67D4,
14309
0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4, 0x5919, 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F, 0x51FA,
14310
0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, 0x821C, 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3, 0xFFFF,
14311
0x6E96, 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806, 0x51E6, 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2,
14312
0x7F72, 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973, 0x5E8F, 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F, 0x52DD,
14313
0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, 0x5968, 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A, 0x5E84,
14314
0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C, 0x6377, 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, 0x6A35,
14315
0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167, 0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11, 0x7CA7,
14316
0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, 0x8A1F, 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266, 0x937E,
14317
0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57, 0x5197, 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, 0x64FE,
14318
0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8, 0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE, 0xFFFF, 0xFFFF, 0xFFFF,
14319
// 0X9000 to 0X90FF
14320
0x62ED, 0x690D, 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, 0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507,
14321
0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B, 0x68EE, 0x699B, 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E,
14322
0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB, 0x8F9B, 0x9032, 0x91DD, 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875,
14323
0x58EC, 0x5C0B, 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, 0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, 0x53A8, 0xFFFF,
14324
0x9017, 0x5439, 0x5782, 0x5E25, 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, 0x7FE0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F,
14325
0x745E, 0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E, 0x6749, 0x6919, 0x83C5, 0x9817, 0x96C0, 0x88FE, 0x6F84,
14326
0x647A, 0x5BF8, 0x4E16, 0x702C, 0x755D, 0x662F, 0x51C4, 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F, 0x6574, 0x661F,
14327
0x6674, 0x68F2, 0x6816, 0x6B63, 0x6E05, 0x7272, 0x751F, 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, 0x897F, 0x8AA0, 0x8A93, 0x8ACB,
14328
0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E, 0x8106, 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, 0x6614, 0x6790, 0x77F3, 0x7A4D,
14329
0x7C4D, 0x7E3E, 0x810A, 0x8CAC, 0x8D64, 0x8DE1, 0x8E5F, 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D, 0x7A83, 0x7BC0,
14330
0x8AAC, 0x96EA, 0x7D76, 0x820C, 0x8749, 0x4ED9, 0x5148, 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, 0x5DDD, 0x6226, 0x6247, 0x64B0,
14331
0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3, 0x6F5C, 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, 0x7DDA, 0xFFFF, 0xFFFF, 0xFFFF,
14332
// 0X9100 to 0X91FF
14333
0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, 0x8CCE, 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE, 0x524D,
14334
0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3, 0x7CCE, 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, 0x72D9,
14335
0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20, 0x7D44, 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275, 0x53CC,
14336
0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, 0x5C64, 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB, 0xFFFF,
14337
0x64CD, 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5, 0x4E89, 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061,
14338
0x8349, 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001, 0x906D, 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E, 0x81D3,
14339
0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, 0x606F, 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E, 0x8CCA,
14340
0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58, 0x5B6B, 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, 0x6C70,
14341
0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1, 0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE, 0x8010,
14342
0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, 0x6CF0, 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000, 0x902E,
14343
0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C, 0x918D, 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, 0x6258,
14344
0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438, 0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA, 0xFFFF, 0xFFFF, 0xFFFF,
14345
// 0X9200 to 0X92FF
14346
0x53E9, 0x4F46, 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, 0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39,
14347
0x5358, 0x5606, 0x5766, 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, 0x6E5B, 0x70AD, 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6,
14348
0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696, 0x6A80, 0x6BB5, 0x7537, 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B,
14349
0x6065, 0x667A, 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, 0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0xFFFF,
14350
0x9010, 0x79E9, 0x7A92, 0x8336, 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, 0x5FE0, 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877,
14351
0x8A3B, 0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457, 0x8CAF, 0x4E01, 0x5146, 0x51CB, 0x558B, 0x5BF5, 0x5E16,
14352
0x5E33, 0x5E81, 0x5F14, 0x5F35, 0x5F6B, 0x5FB4, 0x61F2, 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A, 0x8074, 0x8139,
14353
0x8178, 0x8776, 0x8ABF, 0x8ADC, 0x8D85, 0x8DF3, 0x929A, 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, 0x76F4, 0x6715, 0x6C88, 0x73CD,
14354
0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E, 0x69CC, 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, 0x6802, 0x63B4, 0x69FB, 0x4F43,
14355
0x6F2C, 0x67D8, 0x8FBB, 0x8526, 0x7DB4, 0x9354, 0x693F, 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A, 0x91E3, 0x9DB4,
14356
0x4EAD, 0x4F4E, 0x505C, 0x5075, 0x5243, 0x8C9E, 0x5448, 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F, 0x608C, 0x62B5,
14357
0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E, 0x7A0B, 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, 0x9013, 0xFFFF, 0xFFFF, 0xFFFF,
14358
// 0X9300 to 0X93FF
14359
0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, 0x6575, 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2, 0x5FB9,
14360
0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929, 0x5C55, 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, 0x70B9,
14361
0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410, 0x5835, 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21, 0x767B,
14362
0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, 0x52AA, 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC, 0xFFFF,
14363
0x51CD, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6, 0x5D8B, 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF,
14364
0x76D7, 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8, 0x7977, 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230, 0x8463,
14365
0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, 0x900F, 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5, 0x540C,
14366
0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5, 0x80F4, 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, 0x5FB3,
14367
0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC, 0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6, 0x82EB,
14368
0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, 0x6C8C, 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948, 0x90A3,
14369
0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A, 0x934B, 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, 0x96E3,
14370
0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1, 0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165, 0xFFFF, 0xFFFF, 0xFFFF,
14371
// 0X9400 to 0X94FF
14372
0x5982, 0x5C3F, 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, 0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5,
14373
0x637B, 0x649A, 0x71C3, 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, 0x56A2, 0x60A9, 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2,
14374
0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2, 0x6D3E, 0x7436, 0x7834, 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3,
14375
0x5EC3, 0x62DD, 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, 0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, 0x6885, 0xFFFF,
14376
0x6973, 0x7164, 0x72FD, 0x8CB7, 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, 0x79E4, 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD,
14377
0x67CF, 0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD, 0x6F20, 0x7206, 0x7E1B, 0x83AB, 0x99C1, 0x9EA6, 0x51FD,
14378
0x7BB1, 0x7872, 0x7BB8, 0x8087, 0x7B48, 0x6AE8, 0x5E61, 0x808C, 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A, 0x9197, 0x9AEA,
14379
0x4F10, 0x7F70, 0x629C, 0x7B4F, 0x95A5, 0x9CE9, 0x567A, 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, 0x534A, 0x53CD, 0x53DB, 0x5E06,
14380
0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248, 0x72AF, 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, 0x8CA9, 0x7BC4, 0x91C6, 0x7169,
14381
0x9812, 0x98EF, 0x633D, 0x6669, 0x756A, 0x76E4, 0x78D0, 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87, 0x5F7C, 0x60B2,
14382
0x6249, 0x6279, 0x62AB, 0x6590, 0x6BD4, 0x6CCC, 0x75B2, 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, 0x80A5, 0x88AB, 0x8AB9, 0x8CBB,
14383
0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099, 0x5C3E, 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, 0x7F8E, 0xFFFF, 0xFFFF, 0xFFFF,
14384
// 0X9500 to 0X95FF
14385
0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, 0x819D, 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C, 0x6867,
14386
0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A, 0x6A19, 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, 0x5EDF,
14387
0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C, 0x86ED, 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7, 0x8CD3,
14388
0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, 0x5A66, 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577, 0xFFFF,
14389
0x65A7, 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299, 0x8B5C, 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB,
14390
0x6B66, 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8, 0x847A, 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D, 0x798F,
14391
0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, 0x4ECF, 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4, 0x626E,
14392
0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587, 0x805E, 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, 0x67C4,
14393
0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB, 0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F, 0x5909,
14394
0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, 0x52C9, 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703, 0x6355,
14395
0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893, 0x6155, 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, 0x5305,
14396
0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29, 0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B, 0xFFFF, 0xFFFF, 0xFFFF,
14397
// 0X9600 to 0X96FF
14398
0x6CD5, 0x6CE1, 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, 0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD,
14399
0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8, 0x5E3D, 0x5FD8, 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2,
14400
0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E, 0x9632, 0x5420, 0x982C, 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2,
14401
0x6734, 0x7267, 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, 0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0xFFFF,
14402
0x6469, 0x78E8, 0x9B54, 0x9EBB, 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, 0x54E9, 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE,
14403
0x9C52, 0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4, 0x4FAD, 0x7E6D, 0x9EBF, 0x4E07, 0x6162, 0x6E80, 0x6F2B,
14404
0x8513, 0x5473, 0x672A, 0x9B45, 0x5DF3, 0x7B95, 0x5CAC, 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999, 0x7C8D, 0x6C11,
14405
0x7720, 0x52D9, 0x5922, 0x7121, 0x725F, 0x77DB, 0x9727, 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, 0x540D, 0x547D, 0x660E, 0x76DF,
14406
0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5, 0x514D, 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, 0x6478, 0x6A21, 0x8302, 0x5984,
14407
0x5B5F, 0x6BDB, 0x731B, 0x76F2, 0x7DB2, 0x8017, 0x8499, 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905, 0x5C24, 0x623B,
14408
0x7C7E, 0x8CB0, 0x554F, 0x60B6, 0x7D0B, 0x9580, 0x5301, 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, 0x91CE, 0x5F25, 0x77E2, 0x5384,
14409
0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756, 0x67F3, 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, 0x7652, 0xFFFF, 0xFFFF, 0xFFFF,
14410
// 0X9700 to 0X97FF
14411
0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, 0x5BA5, 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67, 0x6D8C,
14412
0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A, 0x9091, 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, 0x8A89,
14413
0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8, 0x63DA, 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6, 0x7194,
14414
0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, 0x8B21, 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32, 0xFFFF,
14415
0x6C83, 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8, 0x6765, 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A,
14416
0x4E71, 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7, 0x5229, 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483, 0x75E2,
14417
0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, 0x7ACB, 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409, 0x7559,
14418
0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E, 0x65C5, 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, 0x6599,
14419
0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7, 0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1, 0x502B,
14420
0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, 0x96A3, 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E, 0x4EE4,
14421
0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2, 0x793C, 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, 0x66A6,
14422
0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B, 0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F, 0xFFFF, 0xFFFF, 0xFFFF,
14423
// 0X9800 to 0X98FF
14424
0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C,
14425
0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E, 0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6,
14426
0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0, 0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900,
14427
0x6E7E, 0x7897, 0x8155, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14428
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14429
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x5F0C,
14430
0x4E10, 0x4E15, 0x4E2A, 0x4E31, 0x4E36, 0x4E3C, 0x4E3F, 0x4E42, 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A, 0x8212, 0x5F0D,
14431
0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, 0x4EA2, 0x4EB0, 0x4EB3, 0x4EB6, 0x4ECE, 0x4ECD, 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7, 0x4EDE, 0x4EED,
14432
0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B, 0x4F5D, 0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, 0x4F98, 0x4F7B, 0x4F69, 0x4F70,
14433
0x4F91, 0x4F6F, 0x4F86, 0x4F96, 0x5118, 0x4FD4, 0x4FDF, 0x4FCE, 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4, 0x4FE5, 0x501A,
14434
0x5028, 0x5014, 0x502A, 0x5025, 0x5005, 0x4F1C, 0x4FF6, 0x5021, 0x5029, 0x502C, 0x4FFE, 0x4FEF, 0x5011, 0x5006, 0x5043, 0x5047,
14435
0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056, 0x506C, 0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, 0x50B2, 0xFFFF, 0xFFFF, 0xFFFF,
14436
// 0X9900 to 0X99FF
14437
0x50C9, 0x50CA, 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5, 0x50ED, 0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, 0x5102, 0x5116,
14438
0x5115, 0x5114, 0x511A, 0x5121, 0x513A, 0x5137, 0x513C, 0x513B, 0x513F, 0x5140, 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8, 0x5169,
14439
0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, 0x5189, 0x518F, 0x5191, 0x5193, 0x5195, 0x5196, 0x51A4, 0x51A6, 0x51A2, 0x51A9,
14440
0x51AA, 0x51AB, 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5, 0x51BD, 0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, 0x51ED, 0xFFFF,
14441
0x51F0, 0x51F5, 0x51FE, 0x5204, 0x520B, 0x5214, 0x520E, 0x5227, 0x522A, 0x522E, 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C,
14442
0x525E, 0x5254, 0x526A, 0x5274, 0x5269, 0x5273, 0x527F, 0x527D, 0x528D, 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8FA8, 0x8FA7,
14443
0x52AC, 0x52AD, 0x52BC, 0x52B5, 0x52C1, 0x52CD, 0x52D7, 0x52DE, 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5, 0x52F8, 0x52F9,
14444
0x5306, 0x5308, 0x7538, 0x530D, 0x5310, 0x530F, 0x5315, 0x531A, 0x5323, 0x532F, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, 0x5345,
14445
0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369, 0x536E, 0x5918, 0x537B, 0x5377, 0x5382, 0x5396, 0x53A0, 0x53A6, 0x53A5, 0x53AE,
14446
0x53B0, 0x53B6, 0x53C3, 0x7C12, 0x96D9, 0x53DF, 0x66FC, 0x71EE, 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D, 0x5440, 0x542C,
14447
0x542D, 0x543C, 0x542E, 0x5436, 0x5429, 0x541D, 0x544E, 0x548F, 0x5475, 0x548E, 0x545F, 0x5471, 0x5477, 0x5470, 0x5492, 0x547B,
14448
0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7, 0x54A2, 0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, 0x54A8, 0xFFFF, 0xFFFF, 0xFFFF,
14449
// 0X9A00 to 0X9AFF
14450
0x54AB, 0x54C2, 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5, 0x54E6, 0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, 0x54E2, 0x5539,
14451
0x5540, 0x5563, 0x554C, 0x552E, 0x555C, 0x5545, 0x5556, 0x5557, 0x5538, 0x5533, 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A, 0x559F,
14452
0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, 0x5583, 0x55A9, 0x5587, 0x55A8, 0x55DA, 0x55C5, 0x55DF, 0x55C4, 0x55DC, 0x55E4,
14453
0x55D4, 0x5614, 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B, 0x55F9, 0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, 0x5638, 0xFFFF,
14454
0x566B, 0x5664, 0x562F, 0x566C, 0x566A, 0x5686, 0x5680, 0x568A, 0x56A0, 0x5694, 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2,
14455
0x56BC, 0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, 0x56D1, 0x56D3, 0x56D7, 0x56EE, 0x56F9, 0x5700, 0x56FF, 0x5704, 0x5709, 0x5708,
14456
0x570B, 0x570D, 0x5713, 0x5718, 0x5716, 0x55C7, 0x571C, 0x5726, 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F, 0x5769, 0x57C0,
14457
0x5788, 0x5761, 0x577F, 0x5789, 0x5793, 0x57A0, 0x57B3, 0x57A4, 0x57AA, 0x57B0, 0x57C3, 0x57C6, 0x57D4, 0x57D2, 0x57D3, 0x580A,
14458
0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872, 0x5821, 0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, 0x583D, 0x5879, 0x5885, 0x58B9,
14459
0x589F, 0x58AB, 0x58BA, 0x58DE, 0x58BB, 0x58B8, 0x58AE, 0x58C5, 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5, 0x58DC, 0x58E4,
14460
0x58DF, 0x58EF, 0x58FA, 0x58F9, 0x58FB, 0x58FC, 0x58FD, 0x5902, 0x590A, 0x5910, 0x591B, 0x68A6, 0x5925, 0x592C, 0x592D, 0x5932,
14461
0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E, 0x595A, 0x5958, 0x5962, 0x5960, 0x5967, 0x596C, 0x5969, 0xFFFF, 0xFFFF, 0xFFFF,
14462
// 0X9B00 to 0X9BFF
14463
0x5978, 0x5981, 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2, 0x59C6, 0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, 0x5A1F, 0x5A11,
14464
0x5A1C, 0x5A09, 0x5A1A, 0x5A40, 0x5A6C, 0x5A49, 0x5A35, 0x5A36, 0x5A62, 0x5A6A, 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2, 0x5ABD,
14465
0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, 0x5AFB, 0x5B0C, 0x5B0B, 0x5B16, 0x5B32, 0x5AD0, 0x5B2A, 0x5B36, 0x5B3E, 0x5B43,
14466
0x5B45, 0x5B40, 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65, 0x5B69, 0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, 0x5B80, 0xFFFF,
14467
0x5B83, 0x5BA6, 0x5BB8, 0x5BC3, 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0, 0x5BE4, 0x5BE6, 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6,
14468
0x5BF3, 0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, 0x5C20, 0x5C22, 0x5C28, 0x5C38, 0x5C39, 0x5C41, 0x5C46, 0x5C4E, 0x5C53, 0x5C50,
14469
0x5C4F, 0x5B71, 0x5C6C, 0x5C6E, 0x4E62, 0x5C76, 0x5C79, 0x5C8C, 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6, 0x5CBC, 0x5CB7,
14470
0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, 0x5CE9, 0x5CFD, 0x5CFA, 0x5CED, 0x5D8C, 0x5CEA, 0x5D0B, 0x5D15, 0x5D17, 0x5D5C, 0x5D1F, 0x5D1B,
14471
0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18, 0x5D4C, 0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, 0x5D76, 0x5D87, 0x5D84, 0x5D82,
14472
0x5DA2, 0x5D9D, 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90, 0x5DB7, 0x5DBC, 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB, 0x5DEB, 0x5DF2,
14473
0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, 0x5E11, 0x5E1B, 0x5E36, 0x5E37, 0x5E44, 0x5E43, 0x5E40, 0x5E4E, 0x5E57, 0x5E54, 0x5E5F, 0x5E62,
14474
0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC, 0x5E7F, 0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, 0x5ECF, 0xFFFF, 0xFFFF, 0xFFFF,
14475
// 0X9C00 to 0X9CFF
14476
0x5ED6, 0x5EE3, 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1, 0x5EE8, 0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, 0x5EF8, 0x5EFE,
14477
0x5F03, 0x5F09, 0x5F5D, 0x5F5C, 0x5F0B, 0x5F11, 0x5F16, 0x5F29, 0x5F2D, 0x5F38, 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F, 0x5F51,
14478
0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, 0x5F77, 0x5F83, 0x5F82, 0x5F7F, 0x5F8A, 0x5F88, 0x5F91, 0x5F87, 0x5F9E, 0x5F99,
14479
0x5F98, 0x5FA0, 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB, 0x5FE4, 0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, 0x6060, 0xFFFF,
14480
0x6019, 0x6010, 0x6029, 0x600E, 0x6031, 0x601B, 0x6015, 0x602B, 0x6026, 0x600F, 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F,
14481
0x604A, 0x6046, 0x604D, 0x6063, 0x6043, 0x6064, 0x6042, 0x606C, 0x606B, 0x6059, 0x6081, 0x608D, 0x60E7, 0x6083, 0x609A, 0x6084,
14482
0x609B, 0x6096, 0x6097, 0x6092, 0x60A7, 0x608B, 0x60E1, 0x60B8, 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6, 0x60B5, 0x60D8,
14483
0x614D, 0x6115, 0x6106, 0x60F6, 0x60F7, 0x6100, 0x60F4, 0x60FA, 0x6103, 0x6121, 0x60FB, 0x60F1, 0x610D, 0x610E, 0x6147, 0x613E,
14484
0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C, 0x6134, 0x613D, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615A, 0x616B,
14485
0x6174, 0x616F, 0x6165, 0x6171, 0x615F, 0x615D, 0x6153, 0x6175, 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A, 0x618A, 0x6191,
14486
0x61AB, 0x61AE, 0x61CC, 0x61CA, 0x61C9, 0x61F7, 0x61C8, 0x61C3, 0x61C6, 0x61BA, 0x61CB, 0x7F79, 0x61CD, 0x61E6, 0x61E3, 0x61F6,
14487
0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE, 0x6200, 0x6208, 0x6209, 0x620D, 0x620C, 0x6214, 0x621B, 0xFFFF, 0xFFFF, 0xFFFF,
14488
// 0X9D00 to 0X9DFF
14489
0x621E, 0x6221, 0x622A, 0x622E, 0x6230, 0x6232, 0x6233, 0x6241, 0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, 0x627C, 0x6282,
14490
0x6289, 0x627E, 0x6292, 0x6293, 0x6296, 0x62D4, 0x6283, 0x6294, 0x62D7, 0x62D1, 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4, 0x62C8,
14491
0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, 0x62C9, 0x630C, 0x62EE, 0x62F1, 0x6327, 0x6302, 0x6308, 0x62EF, 0x62F5, 0x6350,
14492
0x633E, 0x634D, 0x641C, 0x634F, 0x6396, 0x638E, 0x6380, 0x63AB, 0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, 0x636B, 0xFFFF,
14493
0x6369, 0x63BE, 0x63E9, 0x63C0, 0x63C6, 0x63E3, 0x63C9, 0x63D2, 0x63F6, 0x63C4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436,
14494
0x651D, 0x6417, 0x6428, 0x640F, 0x6467, 0x646F, 0x6476, 0x644E, 0x652A, 0x6495, 0x6493, 0x64A5, 0x64A9, 0x6488, 0x64BC, 0x64DA,
14495
0x64D2, 0x64C5, 0x64C7, 0x64BB, 0x64D8, 0x64C2, 0x64F1, 0x64E7, 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF, 0x652C, 0x64F6,
14496
0x64F4, 0x64F2, 0x64FA, 0x6500, 0x64FD, 0x6518, 0x651C, 0x6505, 0x6524, 0x6523, 0x652B, 0x6534, 0x6535, 0x6537, 0x6536, 0x6538,
14497
0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558, 0x655E, 0x655D, 0x6572, 0x6578, 0x6582, 0x6583, 0x8B8A, 0x659B, 0x659F, 0x65AB,
14498
0x65B7, 0x65C3, 0x65C6, 0x65C1, 0x65C4, 0x65CC, 0x65D2, 0x65DB, 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A, 0x6603, 0x65FB,
14499
0x6773, 0x6635, 0x6636, 0x6634, 0x661C, 0x664F, 0x6644, 0x6649, 0x6641, 0x665E, 0x665D, 0x6664, 0x6667, 0x6668, 0x665F, 0x6662,
14500
0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684, 0x6698, 0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, 0x66BC, 0xFFFF, 0xFFFF, 0xFFFF,
14501
// 0X9E00 to 0X9EFF
14502
0x66C4, 0x66B8, 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6, 0x66E9, 0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, 0x6726, 0x6727,
14503
0x9738, 0x672E, 0x673F, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746, 0x675E, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67A9,
14504
0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, 0x6785, 0x67B7, 0x67EF, 0x67B4, 0x67EC, 0x67B3, 0x67E9, 0x67B8, 0x67E4, 0x67DE,
14505
0x67DD, 0x67E2, 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7, 0x6A9C, 0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, 0x684E, 0xFFFF,
14506
0x68B3, 0x682B, 0x6859, 0x6863, 0x6877, 0x687F, 0x689F, 0x688F, 0x68AD, 0x6894, 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874,
14507
0x68B5, 0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, 0x6901, 0x68CA, 0x6908, 0x68D8, 0x6922, 0x6926, 0x68E1, 0x690C, 0x68CD, 0x68D4,
14508
0x68E7, 0x68D5, 0x6936, 0x6912, 0x6904, 0x68D7, 0x68E3, 0x6925, 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A, 0x6923, 0x6921,
14509
0x68C6, 0x6979, 0x6977, 0x695C, 0x6978, 0x696B, 0x6954, 0x697E, 0x696E, 0x6939, 0x6974, 0x693D, 0x6959, 0x6930, 0x6961, 0x695E,
14510
0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0, 0x69BF, 0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, 0x69CA, 0x69DD, 0x69BB, 0x69C3,
14511
0x69A7, 0x6A2E, 0x6991, 0x69A0, 0x699C, 0x6995, 0x69B4, 0x69DE, 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9, 0x69F2, 0x69E7,
14512
0x6A05, 0x69B1, 0x6A1E, 0x69ED, 0x6A14, 0x69EB, 0x6A0A, 0x6A12, 0x6AC1, 0x6A23, 0x6A13, 0x6A44, 0x6A0C, 0x6A72, 0x6A36, 0x6A78,
14513
0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38, 0x6A22, 0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, 0x6AA3, 0xFFFF, 0xFFFF, 0xFFFF,
14514
// 0X9F00 to 0X9FFF
14515
0x6A97, 0x8617, 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3, 0x6AAC, 0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, 0x6AFB, 0x6B05,
14516
0x8616, 0x6AFA, 0x6B12, 0x6B16, 0x9B31, 0x6B1F, 0x6B38, 0x6B37, 0x76DC, 0x6B39, 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50, 0x6B59,
14517
0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, 0x6B7F, 0x6B80, 0x6B84, 0x6B83, 0x6B8D, 0x6B98, 0x6B95, 0x6B9E, 0x6BA4, 0x6BAA,
14518
0x6BAB, 0x6BAF, 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC, 0x6BC6, 0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, 0x6BEF, 0xFFFF,
14519
0x9EBE, 0x6C08, 0x6C13, 0x6C14, 0x6C1B, 0x6C24, 0x6C23, 0x6C5E, 0x6C55, 0x6C62, 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B,
14520
0x6C7E, 0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, 0x6CF1, 0x6CD3, 0x6CBD, 0x6CD7, 0x6CC5, 0x6CDD, 0x6CAE, 0x6CB1, 0x6CBE, 0x6CBA,
14521
0x6CDB, 0x6CEF, 0x6CD9, 0x6CEA, 0x6D1F, 0x884D, 0x6D36, 0x6D2B, 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12, 0x6D0C, 0x6D63,
14522
0x6D93, 0x6D64, 0x6D5A, 0x6D79, 0x6D59, 0x6D8E, 0x6D95, 0x6FE4, 0x6D85, 0x6DF9, 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7, 0x6DE6, 0x6DB8,
14523
0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2, 0x6DC5, 0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, 0x6DEE, 0x6E2D, 0x6E6E, 0x6E2E,
14524
0x6E19, 0x6E72, 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B, 0x6E2B, 0x6E76, 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24, 0x6EFF, 0x6E1D,
14525
0x6E38, 0x6E82, 0x6EAA, 0x6E98, 0x6EC9, 0x6EB7, 0x6ED3, 0x6EBD, 0x6EAF, 0x6EC4, 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F, 0x6EA5, 0x6EC2,
14526
0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8, 0x6EFE, 0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, 0x6ECC, 0xFFFF, 0xFFFF, 0xFFFF,
14527
};
14528
14529
const wchar_t SjisToUnicodeTable4[] =
14530
{
14531
// 0XE000 to 0XE0FF
14532
0x6F3E, 0x6F13, 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81, 0x6F80, 0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, 0x6F58, 0x6F8E,
14533
0x6F91, 0x6FC2, 0x6F66, 0x6FB3, 0x6FA3, 0x6FA1, 0x6FA4, 0x6FB9, 0x6FC6, 0x6FAA, 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8, 0x6FF1,
14534
0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, 0x7001, 0x700F, 0x6FFE, 0x701B, 0x701A, 0x6F74, 0x701D, 0x7018, 0x701F, 0x7030,
14535
0x703E, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF, 0x70F1, 0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, 0x70DD, 0xFFFF,
14536
0x70D9, 0x7109, 0x70FD, 0x711C, 0x7119, 0x7165, 0x7155, 0x7188, 0x7166, 0x7162, 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184,
14537
0x7195, 0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, 0x71D2, 0x71C9, 0x71D4, 0x71CE, 0x71E0, 0x71EC, 0x71E7, 0x71F5, 0x71FC, 0x71F9,
14538
0x71FF, 0x720D, 0x7210, 0x721B, 0x7228, 0x722D, 0x722C, 0x7230, 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246, 0x724B, 0x7258,
14539
0x7274, 0x727E, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296, 0x72A2, 0x72A7, 0x72B9, 0x72B2, 0x72C3, 0x72C6, 0x72C4, 0x72CE, 0x72D2,
14540
0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F, 0x7317, 0x730A, 0x731C, 0x7316, 0x731D, 0x7334, 0x732F, 0x7329, 0x7325, 0x733E,
14541
0x734E, 0x734F, 0x9ED8, 0x7357, 0x736A, 0x7368, 0x7370, 0x7378, 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE, 0x73BB, 0x73C0,
14542
0x73E5, 0x73EE, 0x73DE, 0x74A2, 0x7405, 0x746F, 0x7425, 0x73F8, 0x7432, 0x743A, 0x7455, 0x743F, 0x745F, 0x7459, 0x7441, 0x745C,
14543
0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E, 0x748B, 0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, 0x73F1, 0xFFFF, 0xFFFF, 0xFFFF,
14544
// 0XE100 to 0XE1FF
14545
0x74E0, 0x74E3, 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0, 0x74F1, 0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, 0x750E, 0x750D,
14546
0x7515, 0x7513, 0x751E, 0x7526, 0x752C, 0x753C, 0x7544, 0x754D, 0x754A, 0x7549, 0x755B, 0x7546, 0x755A, 0x7569, 0x7564, 0x7567,
14547
0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758A, 0x7589, 0x7582, 0x7594, 0x759A, 0x759D, 0x75A5, 0x75A3, 0x75C2,
14548
0x75B3, 0x75C3, 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1, 0x75CD, 0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, 0x75FF, 0xFFFF,
14549
0x75FC, 0x7601, 0x75F0, 0x75FA, 0x75F2, 0x75F3, 0x760B, 0x760D, 0x7609, 0x761F, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634,
14550
0x7630, 0x763B, 0x7647, 0x7648, 0x7646, 0x765C, 0x7658, 0x7661, 0x7662, 0x7668, 0x7669, 0x766A, 0x7667, 0x766C, 0x7670, 0x7672,
14551
0x7676, 0x7678, 0x767C, 0x7680, 0x7683, 0x7688, 0x768B, 0x768E, 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4, 0x76B8, 0x76B9,
14552
0x76BA, 0x76C2, 0x76CD, 0x76D6, 0x76D2, 0x76DE, 0x76E1, 0x76E5, 0x76E7, 0x76EA, 0x862F, 0x76FB, 0x7708, 0x7707, 0x7704, 0x7729,
14553
0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737, 0x7738, 0x7747, 0x775A, 0x7768, 0x776B, 0x775B, 0x7765, 0x777F, 0x777E, 0x7779,
14554
0x778E, 0x778B, 0x7791, 0x77A0, 0x779E, 0x77B0, 0x77B6, 0x77B9, 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD, 0x77D7, 0x77DA,
14555
0x77DC, 0x77E3, 0x77EE, 0x77FC, 0x780C, 0x7812, 0x7926, 0x7820, 0x792A, 0x7845, 0x788E, 0x7874, 0x7886, 0x787C, 0x789A, 0x788C,
14556
0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6, 0x78CB, 0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, 0x78EC, 0xFFFF, 0xFFFF, 0xFFFF,
14557
// 0XE200 to 0XE2FF
14558
0x78E7, 0x78DA, 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911, 0x7919, 0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, 0x795A, 0x7955,
14559
0x7953, 0x797A, 0x797F, 0x798A, 0x799D, 0x79A7, 0x9F4B, 0x79AA, 0x79AE, 0x79B3, 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7, 0x79EC,
14560
0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, 0x7A20, 0x7A1F, 0x7980, 0x7A31, 0x7A3B, 0x7A3E, 0x7A37, 0x7A43, 0x7A57, 0x7A49,
14561
0x7A61, 0x7A62, 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D, 0x7A88, 0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, 0x7AB0, 0xFFFF,
14562
0x7AB6, 0x7AC5, 0x7AC4, 0x7ABF, 0x9083, 0x7AC7, 0x7ACA, 0x7ACD, 0x7ACF, 0x7AD5, 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2,
14563
0x7AE6, 0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, 0x7B06, 0x7B33, 0x7B18, 0x7B19, 0x7B1E, 0x7B35, 0x7B28, 0x7B36, 0x7B50, 0x7B7A,
14564
0x7B04, 0x7B4D, 0x7B0B, 0x7B4C, 0x7B45, 0x7B75, 0x7B65, 0x7B74, 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D, 0x7B98, 0x7B9F,
14565
0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, 0x7B92, 0x7B8F, 0x7B5D, 0x7B99, 0x7BCB, 0x7BC1, 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6, 0x7BDD, 0x7BE9,
14566
0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00, 0x7C07, 0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, 0x7BF6, 0x7C23, 0x7C27, 0x7C2A,
14567
0x7C1F, 0x7C37, 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43, 0x7C54, 0x7C4F, 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56, 0x7C65, 0x7C6C,
14568
0x7C75, 0x7C83, 0x7C90, 0x7CA4, 0x7CAD, 0x7CA2, 0x7CAB, 0x7CA1, 0x7CA8, 0x7CB3, 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9, 0x7CBD, 0x7CC0,
14569
0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2, 0x9B3B, 0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, 0x7D06, 0xFFFF, 0xFFFF, 0xFFFF,
14570
// 0XE300 to 0XE3FF
14571
0x7D02, 0x7D1C, 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E, 0x7D32, 0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, 0x7D72, 0x7D68,
14572
0x7D6E, 0x7D4F, 0x7D63, 0x7D93, 0x7D89, 0x7D5B, 0x7D8F, 0x7D7D, 0x7D9B, 0x7DBA, 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD, 0x7DAB,
14573
0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, 0x7DB0, 0x7DD8, 0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, 0x7DF2, 0x7DE1, 0x7E05, 0x7E0A,
14574
0x7E23, 0x7E21, 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B, 0x7E22, 0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, 0x7E37, 0xFFFF,
14575
0x7E32, 0x7E3A, 0x7E67, 0x7E5D, 0x7E56, 0x7E5E, 0x7E59, 0x7E5A, 0x7E79, 0x7E6A, 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D,
14576
0x8FAE, 0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, 0x7E90, 0x7E93, 0x7E94, 0x7E96, 0x7E8E, 0x7E9B, 0x7E9C, 0x7F38, 0x7F3A, 0x7F45,
14577
0x7F4C, 0x7F4D, 0x7F4E, 0x7F50, 0x7F51, 0x7F55, 0x7F54, 0x7F58, 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78, 0x7F82, 0x7F86,
14578
0x7F83, 0x7F88, 0x7F87, 0x7F8C, 0x7F94, 0x7F9E, 0x7F9D, 0x7F9A, 0x7FA3, 0x7FAF, 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6, 0x7FB8, 0x8B71,
14579
0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1, 0x7FE6, 0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, 0x8004, 0x800B, 0x8012, 0x8018,
14580
0x8019, 0x801C, 0x8021, 0x8028, 0x803F, 0x803B, 0x804A, 0x8046, 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068, 0x8073, 0x8072,
14581
0x8070, 0x8076, 0x8079, 0x807D, 0x807F, 0x8084, 0x8086, 0x8085, 0x809B, 0x8093, 0x809A, 0x80AD, 0x5190, 0x80AC, 0x80DB, 0x80E5,
14582
0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109, 0x80EF, 0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, 0x814B, 0xFFFF, 0xFFFF, 0xFFFF,
14583
// 0XE400 to 0XE4FF
14584
0x968B, 0x8146, 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171, 0x816E, 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, 0x8180, 0x8182,
14585
0x81A0, 0x8195, 0x81A4, 0x81A3, 0x815F, 0x8193, 0x81A9, 0x81B0, 0x81B5, 0x81BE, 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA, 0x81C9,
14586
0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, 0x81DF, 0x81E0, 0x81E7, 0x81FA, 0x81FB, 0x81FE, 0x8201, 0x8202, 0x8205, 0x8207,
14587
0x820A, 0x820D, 0x8210, 0x8216, 0x8229, 0x822B, 0x8238, 0x8233, 0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, 0x8264, 0xFFFF,
14588
0x8262, 0x8268, 0x826A, 0x826B, 0x822E, 0x8271, 0x8277, 0x8278, 0x827E, 0x828D, 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1,
14589
0x82E3, 0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, 0x8393, 0x8303, 0x82FB, 0x82F9, 0x82DE, 0x8306, 0x82DC, 0x8309, 0x82D9, 0x8335,
14590
0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, 0x8345, 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A, 0x83AA, 0x839F,
14591
0x83A2, 0x8396, 0x8323, 0x838E, 0x8387, 0x838A, 0x837C, 0x83B5, 0x8373, 0x8375, 0x83A0, 0x8389, 0x83A8, 0x83F4, 0x8413, 0x83EB,
14592
0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1, 0x83F7, 0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, 0x8420, 0x83BD, 0x8438, 0x8506,
14593
0x83FB, 0x846D, 0x842A, 0x843C, 0x855A, 0x8484, 0x8477, 0x846B, 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C, 0x846F, 0x8479,
14594
0x8435, 0x84CA, 0x8462, 0x84B9, 0x84BF, 0x849F, 0x84D9, 0x84CD, 0x84BB, 0x84DA, 0x84D0, 0x84C1, 0x84C6, 0x84D6, 0x84A1, 0x8521,
14595
0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F, 0x8515, 0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, 0x8548, 0xFFFF, 0xFFFF, 0xFFFF,
14596
// 0XE500 to 0XE5FF
14597
0x8541, 0x8602, 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588, 0x8591, 0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, 0x8587, 0x859C,
14598
0x8577, 0x857E, 0x8590, 0x85C9, 0x85BA, 0x85CF, 0x85B9, 0x85D0, 0x85D5, 0x85DD, 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613, 0x860B,
14599
0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, 0x863F, 0x864D, 0x4E55, 0x8654, 0x865F, 0x8667, 0x8671, 0x8693, 0x86A3, 0x86A9,
14600
0x86AA, 0x868B, 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6, 0x86B0, 0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, 0x86EC, 0xFFFF,
14601
0x86DF, 0x86DB, 0x86EF, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703, 0x86FB, 0x8711, 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F,
14602
0x8737, 0x873B, 0x8725, 0x8729, 0x871A, 0x8760, 0x875F, 0x8778, 0x874C, 0x874E, 0x8774, 0x8757, 0x8768, 0x876E, 0x8759, 0x8753,
14603
0x8763, 0x876A, 0x8805, 0x87A2, 0x879F, 0x8782, 0x87AF, 0x87CB, 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4, 0x87B3, 0x87C7,
14604
0x87C6, 0x87BB, 0x87EF, 0x87F2, 0x87E0, 0x880F, 0x880D, 0x87FE, 0x87F6, 0x87F7, 0x880E, 0x87D2, 0x8811, 0x8816, 0x8815, 0x8822,
14605
0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B, 0x8844, 0x8842, 0x8852, 0x8859, 0x885E, 0x8862, 0x886B, 0x8881, 0x887E, 0x889E,
14606
0x8875, 0x887D, 0x88B5, 0x8872, 0x8882, 0x8897, 0x8892, 0x88AE, 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF, 0x88B1, 0x88C3,
14607
0x88C4, 0x88D4, 0x88D8, 0x88D9, 0x88DD, 0x88F9, 0x8902, 0x88FC, 0x88F4, 0x88E8, 0x88F2, 0x8904, 0x890C, 0x890A, 0x8913, 0x8943,
14608
0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944, 0x893B, 0x8936, 0x8938, 0x894C, 0x891D, 0x8960, 0x895E, 0xFFFF, 0xFFFF, 0xFFFF,
14609
// 0XE600 to 0XE6FF
14610
0x8966, 0x8964, 0x896D, 0x896A, 0x896F, 0x8974, 0x8977, 0x897E, 0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, 0x89A9, 0x89A6,
14611
0x89AC, 0x89AF, 0x89B2, 0x89BA, 0x89BD, 0x89BF, 0x89C0, 0x89DA, 0x89DC, 0x89DD, 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16, 0x8A10,
14612
0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, 0x8A5B, 0x8A52, 0x8A46, 0x8A48, 0x8A7C, 0x8A6D, 0x8A6C, 0x8A62, 0x8A85, 0x8A82,
14613
0x8A84, 0x8AA8, 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A, 0x8AA3, 0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, 0x8AE7, 0xFFFF,
14614
0x8AE4, 0x8AF1, 0x8B14, 0x8AE0, 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB, 0x8B0C, 0x8B07, 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20,
14615
0x8B33, 0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, 0x8B41, 0x8B4C, 0x8B4F, 0x8B4E, 0x8B49, 0x8B56, 0x8B5B, 0x8B5A, 0x8B6B, 0x8B5F,
14616
0x8B6C, 0x8B6F, 0x8B74, 0x8B7D, 0x8B80, 0x8B8C, 0x8B8E, 0x8B92, 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41, 0x8C3F, 0x8C48,
14617
0x8C4C, 0x8C4E, 0x8C50, 0x8C55, 0x8C62, 0x8C6C, 0x8C78, 0x8C7A, 0x8C82, 0x8C89, 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E, 0x8C94, 0x8C7C,
14618
0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2, 0x8CB3, 0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, 0x8CE3, 0x8CDA, 0x8CFD, 0x8CFA,
14619
0x8CFB, 0x8D04, 0x8D05, 0x8D0A, 0x8D07, 0x8D0F, 0x8D0D, 0x8D10, 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67, 0x8D6D, 0x8D71,
14620
0x8D73, 0x8D81, 0x8D99, 0x8DC2, 0x8DBE, 0x8DBA, 0x8DCF, 0x8DDA, 0x8DD6, 0x8DCC, 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB, 0x8DDF, 0x8DE3,
14621
0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E, 0x8E10, 0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, 0x8E4A, 0xFFFF, 0xFFFF, 0xFFFF,
14622
// 0XE700 to 0XE7FF
14623
0x8E47, 0x8E49, 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64, 0x8E60, 0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, 0x8E81, 0x8E87,
14624
0x8E85, 0x8E84, 0x8E8B, 0x8E8A, 0x8E93, 0x8E91, 0x8E94, 0x8E99, 0x8EAA, 0x8EA1, 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE, 0x8EC5,
14625
0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, 0x8EEB, 0x8EFE, 0x8F0A, 0x8F05, 0x8F15, 0x8F12, 0x8F19, 0x8F13, 0x8F1C, 0x8F1F,
14626
0x8F1B, 0x8F0C, 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45, 0x8F42, 0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, 0x8F5C, 0xFFFF,
14627
0x8F62, 0x8F63, 0x8F64, 0x8F9C, 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF, 0x8FB7, 0x8FDA, 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4,
14628
0x9005, 0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, 0x900D, 0x901E, 0x9016, 0x900B, 0x9027, 0x9036, 0x9035, 0x9039, 0x8FF8, 0x904F,
14629
0x9050, 0x9051, 0x9052, 0x900E, 0x9049, 0x903E, 0x9056, 0x9058, 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072, 0x9082, 0x907D,
14630
0x9081, 0x9080, 0x908A, 0x9089, 0x908F, 0x90A8, 0x90AF, 0x90B1, 0x90B5, 0x90E2, 0x90E4, 0x6248, 0x90DB, 0x9102, 0x9112, 0x9119,
14631
0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163, 0x9165, 0x9169, 0x9173, 0x9172, 0x918B, 0x9189, 0x9182, 0x91A2, 0x91AB, 0x91AF,
14632
0x91AA, 0x91B5, 0x91B4, 0x91BA, 0x91C0, 0x91C1, 0x91C9, 0x91CB, 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC, 0x91F5, 0x91F6,
14633
0x921E, 0x91FF, 0x9214, 0x922C, 0x9215, 0x9211, 0x925E, 0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923F, 0x924B, 0x9250,
14634
0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF, 0x92B9, 0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, 0x932E, 0xFFFF, 0xFFFF, 0xFFFF,
14635
// 0XE800 to 0XE8FF
14636
0x9319, 0x9322, 0x931A, 0x9323, 0x933A, 0x9335, 0x933B, 0x935C, 0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, 0x93AD, 0x9394,
14637
0x93B9, 0x93D6, 0x93D7, 0x93E8, 0x93E5, 0x93D8, 0x93C3, 0x93DD, 0x93D0, 0x93C8, 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403, 0x9407,
14638
0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, 0x9441, 0x9452, 0x9444, 0x945B, 0x9460, 0x9462, 0x945E, 0x946A, 0x9229, 0x9470,
14639
0x9475, 0x9477, 0x947D, 0x945A, 0x947C, 0x947E, 0x9481, 0x947F, 0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, 0x9599, 0xFFFF,
14640
0x95A0, 0x95A8, 0x95A7, 0x95AD, 0x95BC, 0x95BB, 0x95B9, 0x95BE, 0x95CA, 0x6FF6, 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6,
14641
0x95DC, 0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, 0x962E, 0x962F, 0x9642, 0x964C, 0x964F, 0x964B, 0x9677, 0x965C, 0x965E, 0x965D,
14642
0x965F, 0x9666, 0x9672, 0x966C, 0x968D, 0x9698, 0x9695, 0x9697, 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4, 0x96B6, 0x96B8,
14643
0x96B9, 0x96CE, 0x96CB, 0x96C9, 0x96CD, 0x894D, 0x96DC, 0x970D, 0x96D5, 0x96F9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970E, 0x9711,
14644
0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730, 0x9739, 0x973D, 0x973E, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975C, 0x9760,
14645
0x9764, 0x9766, 0x9768, 0x52D2, 0x976B, 0x9771, 0x9779, 0x9785, 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F, 0x9790, 0x979C,
14646
0x97A8, 0x97A6, 0x97A3, 0x97B3, 0x97B4, 0x97C3, 0x97C6, 0x97C8, 0x97CB, 0x97DC, 0x97ED, 0x9F4F, 0x97F2, 0x7ADF, 0x97F6, 0x97F5,
14647
0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837, 0x983D, 0x9846, 0x984F, 0x984B, 0x986B, 0x986F, 0x9870, 0xFFFF, 0xFFFF, 0xFFFF,
14648
// 0XE900 to 0XE9FF
14649
0x9871, 0x9874, 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6, 0x98C4, 0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, 0x9912, 0x9914,
14650
0x9918, 0x9921, 0x991D, 0x991E, 0x9924, 0x9920, 0x992C, 0x992E, 0x993D, 0x993E, 0x9942, 0x9949, 0x9945, 0x9950, 0x994B, 0x9951,
14651
0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, 0x99AD, 0x99AE, 0x99BC, 0x99DF, 0x99DB, 0x99DD, 0x99D8, 0x99D1, 0x99ED, 0x99EE,
14652
0x99F1, 0x99F2, 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05, 0x99E2, 0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, 0x9A43, 0xFFFF,
14653
0x9A3E, 0x9A55, 0x9A4D, 0x9A5B, 0x9A57, 0x9A5F, 0x9A62, 0x9A65, 0x9A64, 0x9A69, 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0,
14654
0x9ACF, 0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, 0x9AE2, 0x9AE3, 0x9AE6, 0x9AEF, 0x9AEB, 0x9AEE, 0x9AF4, 0x9AF1, 0x9AF7, 0x9AFB,
14655
0x9B06, 0x9B18, 0x9B1A, 0x9B1F, 0x9B22, 0x9B23, 0x9B25, 0x9B27, 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32, 0x9B44, 0x9B43,
14656
0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, 0x9B58, 0x9B74, 0x9B93, 0x9B83, 0x9B91, 0x9B96, 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8, 0x9BB4, 0x9BC0,
14657
0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2, 0x9BE3, 0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, 0x9BF2, 0x9BF1, 0x9BF0, 0x9C15,
14658
0x9C14, 0x9C09, 0x9C13, 0x9C0C, 0x9C06, 0x9C08, 0x9C12, 0x9C0A, 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21, 0x9C30, 0x9C47,
14659
0x9C32, 0x9C46, 0x9C3E, 0x9C5A, 0x9C60, 0x9C67, 0x9C76, 0x9C78, 0x9CE7, 0x9CEC, 0x9CF0, 0x9D09, 0x9D08, 0x9CEB, 0x9D03, 0x9D06,
14660
0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44, 0x9D15, 0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, 0x9D48, 0xFFFF, 0xFFFF, 0xFFFF,
14661
// 0XEA00 to 0XEAFF
14662
0x9D5D, 0x9D5E, 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72, 0x9D89, 0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, 0x9DA9, 0x9DB2,
14663
0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, 0x9DBA, 0x9DC6, 0x9DCF, 0x9DC2, 0x9DD9, 0x9DD3, 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD, 0x9E1A,
14664
0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, 0x9E88, 0x9E8B, 0x9E8C, 0x9E92, 0x9E95, 0x9E91, 0x9E9D, 0x9EA5, 0x9EA9, 0x9EB8,
14665
0x9EAA, 0x9EAD, 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0, 0x9ED4, 0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, 0x9EEF, 0xFFFF,
14666
0x9EF4, 0x9EF6, 0x9EF7, 0x9EF9, 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07, 0x9F08, 0x76B7, 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52,
14667
0x9F54, 0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, 0x9F67, 0x9F6C, 0x9F6A, 0x9F77, 0x9F72, 0x9F76, 0x9F95, 0x9F9C, 0x9FA0, 0x582F,
14668
0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14669
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14670
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14671
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14672
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14673
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
14674
};
14675
14676
const wchar_t SjisToUnicodeTable5[] =
14677
{
14678
// 0XED00 to 0XEDFF
14679
0x7E8A, 0x891C, 0x9348, 0x9288, 0x84DC, 0x4FC9, 0x70BB, 0x6631, 0x68C8, 0x92F9, 0x66FB, 0x5F45, 0x4E28, 0x4EE1, 0x4EFC, 0x4F00,
14680
0x4F03, 0x4F39, 0x4F56, 0x4F92, 0x4F8A, 0x4F9A, 0x4F94, 0x4FCD, 0x5040, 0x5022, 0x4FFF, 0x501E, 0x5046, 0x5070, 0x5042, 0x5094,
14681
0x50F4, 0x50D8, 0x514A, 0x5164, 0x519D, 0x51BE, 0x51EC, 0x5215, 0x529C, 0x52A6, 0x52C0, 0x52DB, 0x5300, 0x5307, 0x5324, 0x5372,
14682
0x5393, 0x53B2, 0x53DD, 0xFA0E, 0x549C, 0x548A, 0x54A9, 0x54FF, 0x5586, 0x5759, 0x5765, 0x57AC, 0x57C8, 0x57C7, 0xFA0F, 0xFFFF,
14683
0xFA10, 0x589E, 0x58B2, 0x590B, 0x5953, 0x595B, 0x595D, 0x5963, 0x59A4, 0x59BA, 0x5B56, 0x5BC0, 0x752F, 0x5BD8, 0x5BEC, 0x5C1E,
14684
0x5CA6, 0x5CBA, 0x5CF5, 0x5D27, 0x5D53, 0xFA11, 0x5D42, 0x5D6D, 0x5DB8, 0x5DB9, 0x5DD0, 0x5F21, 0x5F34, 0x5F67, 0x5FB7, 0x5FDE,
14685
0x605D, 0x6085, 0x608A, 0x60DE, 0x60D5, 0x6120, 0x60F2, 0x6111, 0x6137, 0x6130, 0x6198, 0x6213, 0x62A6, 0x63F5, 0x6460, 0x649D,
14686
0x64CE, 0x654E, 0x6600, 0x6615, 0x663B, 0x6609, 0x662E, 0x661E, 0x6624, 0x6665, 0x6657, 0x6659, 0xFA12, 0x6673, 0x6699, 0x66A0,
14687
0x66B2, 0x66BF, 0x66FA, 0x670E, 0xF929, 0x6766, 0x67BB, 0x6852, 0x67C0, 0x6801, 0x6844, 0x68CF, 0xFA13, 0x6968, 0xFA14, 0x6998,
14688
0x69E2, 0x6A30, 0x6A6B, 0x6A46, 0x6A73, 0x6A7E, 0x6AE2, 0x6AE4, 0x6BD6, 0x6C3F, 0x6C5C, 0x6C86, 0x6C6F, 0x6CDA, 0x6D04, 0x6D87,
14689
0x6D6F, 0x6D96, 0x6DAC, 0x6DCF, 0x6DF8, 0x6DF2, 0x6DFC, 0x6E39, 0x6E5C, 0x6E27, 0x6E3C, 0x6EBF, 0x6F88, 0x6FB5, 0x6FF5, 0x7005,
14690
0x7007, 0x7028, 0x7085, 0x70AB, 0x710F, 0x7104, 0x715C, 0x7146, 0x7147, 0xFA15, 0x71C1, 0x71FE, 0x72B1, 0xFFFF, 0xFFFF, 0xFFFF,
14691
// 0XEE00 to 0XEEFF
14692
0x72BE, 0x7324, 0xFA16, 0x7377, 0x73BD, 0x73C9, 0x73D6, 0x73E3, 0x73D2, 0x7407, 0x73F5, 0x7426, 0x742A, 0x7429, 0x742E, 0x7462,
14693
0x7489, 0x749F, 0x7501, 0x756F, 0x7682, 0x769C, 0x769E, 0x769B, 0x76A6, 0xFA17, 0x7746, 0x52AF, 0x7821, 0x784E, 0x7864, 0x787A,
14694
0x7930, 0xFA18, 0xFA19, 0xFA1A, 0x7994, 0xFA1B, 0x799B, 0x7AD1, 0x7AE7, 0xFA1C, 0x7AEB, 0x7B9E, 0xFA1D, 0x7D48, 0x7D5C, 0x7DB7,
14695
0x7DA0, 0x7DD6, 0x7E52, 0x7F47, 0x7FA1, 0xFA1E, 0x8301, 0x8362, 0x837F, 0x83C7, 0x83F6, 0x8448, 0x84B4, 0x8553, 0x8559, 0xFFFF,
14696
0x856B, 0xFA1F, 0x85B0, 0xFA20, 0xFA21, 0x8807, 0x88F5, 0x8A12, 0x8A37, 0x8A79, 0x8AA7, 0x8ABE, 0x8ADF, 0xFA22, 0x8AF6, 0x8B53,
14697
0x8B7F, 0x8CF0, 0x8CF4, 0x8D12, 0x8D76, 0xFA23, 0x8ECF, 0xFA24, 0xFA25, 0x9067, 0x90DE, 0xFA26, 0x9115, 0x9127, 0x91DA, 0x91D7,
14698
0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206, 0x9210, 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251, 0x9239, 0x9267,
14699
0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9, 0x92D0, 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB, 0xFA28, 0x931E,
14700
0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4, 0x93C6, 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC, 0xFA29, 0x969D,
14701
0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F, 0x9751, 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C, 0x999E, 0x9A4E,
14702
0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1, 0x9BBB, 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0xFFFF, 0xFFFF, 0x2170,
14703
0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0xFFE2, 0xFFE4, 0xFF07, 0xFF02, 0xFFFF, 0xFFFF, 0xFFFF,
14704
};
14705
14706
wchar_t sjisToUnicode(unsigned short SjisCharacter)
14707
{
14708
if (SjisCharacter < 0x80)
14709
{
14710
return SjisCharacter;
14711
} else if (SjisCharacter < 0x100)
14712
{
14713
return SjisToUnicodeTable1[SjisCharacter-0x80];
14714
}
14715
14716
if ((SjisCharacter & 0xFF) < 0x40) return 0xFFFF;
14717
14718
if (SjisCharacter >= 0x8100 && SjisCharacter < 0x8500)
14719
{
14720
SjisCharacter -= 0x8140;
14721
SjisCharacter -= (SjisCharacter >> 8) * 0x40;
14722
return SjisToUnicodeTable2[SjisCharacter];
14723
} else if (SjisCharacter >= 0x8700 && SjisCharacter < 0xA000)
14724
{
14725
SjisCharacter -= 0x8740;
14726
SjisCharacter -= (SjisCharacter >> 8) * 0x40;
14727
return SjisToUnicodeTable3[SjisCharacter];
14728
} else if (SjisCharacter >= 0xE000 && SjisCharacter < 0xEB00)
14729
{
14730
SjisCharacter -= 0xE040;
14731
SjisCharacter -= (SjisCharacter >> 8) * 0x40;
14732
return SjisToUnicodeTable4[SjisCharacter];
14733
} else if (SjisCharacter >= 0xED00 && SjisCharacter < 0xEF00)
14734
{
14735
SjisCharacter -= 0xED40;
14736
SjisCharacter -= (SjisCharacter >> 8) * 0x40;
14737
return SjisToUnicodeTable5[SjisCharacter];
14738
} else {
14739
return 0xFFFF;
14740
}
14741
}
14742
14743
BinaryFile::BinaryFile()
14744
{
14745
handle = nullptr;
14746
}
14747
14748
BinaryFile::~BinaryFile()
14749
{
14750
close();
14751
}
14752
14753
bool BinaryFile::open(const std::wstring& fileName, Mode mode)
14754
{
14755
setFileName(fileName);
14756
return open(mode);
14757
}
14758
14759
bool BinaryFile::open(Mode mode)
14760
{
14761
if (isOpen())
14762
close();
14763
14764
this->mode = mode;
14765
14766
// open all files as binary due to unicode
14767
switch (mode)
14768
{
14769
case Read:
14770
handle = openFile(fileName,OpenFileMode::ReadBinary);
14771
break;
14772
case Write:
14773
handle = openFile(fileName,OpenFileMode::WriteBinary);
14774
break;
14775
case ReadWrite:
14776
handle = openFile(fileName,OpenFileMode::ReadWriteBinary);
14777
break;
14778
default:
14779
return false;
14780
}
14781
14782
if (handle == nullptr)
14783
return false;
14784
14785
if (mode != Write)
14786
{
14787
fseek(handle,0,SEEK_END);
14788
size_ = ftell(handle);
14789
fseek(handle,0,SEEK_SET);
14790
}
14791
14792
return true;
14793
}
14794
14795
void BinaryFile::close()
14796
{
14797
if (isOpen())
14798
{
14799
fclose(handle);
14800
handle = nullptr;
14801
}
14802
}
14803
14804
size_t BinaryFile::read(void* dest, size_t length)
14805
{
14806
if (isOpen() == false || mode == Write)
14807
return 0;
14808
14809
return fread(dest,1,length,handle);
14810
}
14811
14812
size_t BinaryFile::write(void* source, size_t length)
14813
{
14814
if (isOpen() == false || mode == Read)
14815
return 0;
14816
14817
return fwrite(source,1,length,handle);
14818
}
14819
14820
const size_t TEXTFILE_BUF_MAX_SIZE = 4096;
14821
14822
TextFile::TextFile()
14823
{
14824
handle = nullptr;
14825
recursion = false;
14826
errorRetrieved = false;
14827
fromMemory = false;
14828
bufPos = 0;
14829
lineCount = 0;
14830
}
14831
14832
TextFile::~TextFile()
14833
{
14834
close();
14835
}
14836
14837
void TextFile::openMemory(const std::wstring& content)
14838
{
14839
fromMemory = true;
14840
this->content = content;
14841
contentPos = 0;
14842
size_ = (long) content.size();
14843
encoding = UTF16LE;
14844
mode = Read;
14845
lineCount = 0;
14846
}
14847
14848
bool TextFile::open(const std::wstring& fileName, Mode mode, Encoding defaultEncoding)
14849
{
14850
setFileName(fileName);
14851
return open(mode,defaultEncoding);
14852
}
14853
14854
bool TextFile::open(Mode mode, Encoding defaultEncoding)
14855
{
14856
if (fileName.empty())
14857
return false;
14858
14859
if (isOpen())
14860
close();
14861
14862
fromMemory = false;
14863
guessedEncoding = false;
14864
encoding = defaultEncoding;
14865
this->mode = mode;
14866
14867
// open all files as binary due to unicode
14868
switch (mode)
14869
{
14870
case Read:
14871
handle = openFile(fileName,OpenFileMode::ReadBinary);
14872
break;
14873
case Write:
14874
handle = openFile(fileName,OpenFileMode::WriteBinary);
14875
if (handle == nullptr)
14876
return false;
14877
14878
buf.resize(TEXTFILE_BUF_MAX_SIZE);
14879
if (encoding != ASCII)
14880
{
14881
encoding = UTF8;
14882
writeCharacter(0xFEFF);
14883
}
14884
break;
14885
default:
14886
return false;
14887
}
14888
14889
if (handle == nullptr)
14890
return false;
14891
14892
// detect encoding
14893
unsigned short num;
14894
contentPos = 0;
14895
14896
if (mode == Read)
14897
{
14898
fseek(handle,0,SEEK_END);
14899
size_ = ftell(handle);
14900
fseek(handle,0,SEEK_SET);
14901
14902
if (fread(&num,2,1,handle) == 1)
14903
{
14904
switch (num)
14905
{
14906
case 0xFFFE:
14907
encoding = UTF16BE;
14908
contentPos += 2;
14909
break;
14910
case 0xFEFF:
14911
encoding = UTF16LE;
14912
contentPos += 2;
14913
break;
14914
case 0xBBEF:
14915
if (fgetc(handle) == 0xBF)
14916
{
14917
encoding = UTF8;
14918
contentPos += 3;
14919
break;
14920
} // fallthrough
14921
default:
14922
if (defaultEncoding == GUESS)
14923
{
14924
encoding = UTF8;
14925
guessedEncoding = true;
14926
}
14927
fseek(handle,0,SEEK_SET);
14928
break;
14929
}
14930
} else {
14931
if (defaultEncoding == GUESS)
14932
{
14933
encoding = UTF8;
14934
guessedEncoding = true;
14935
}
14936
}
14937
}
14938
14939
return true;
14940
}
14941
14942
void TextFile::close()
14943
{
14944
if (isOpen() && !fromMemory)
14945
{
14946
bufDrainWrite();
14947
fclose(handle);
14948
handle = nullptr;
14949
}
14950
bufPos = 0;
14951
}
14952
14953
long TextFile::tell()
14954
{
14955
return (long) contentPos;
14956
}
14957
14958
void TextFile::seek(long pos)
14959
{
14960
if (fromMemory)
14961
contentPos = pos;
14962
else
14963
fseek(handle,pos,SEEK_SET);
14964
}
14965
14966
void TextFile::bufFillRead()
14967
{
14968
assert(mode == Read);
14969
14970
buf.resize(TEXTFILE_BUF_MAX_SIZE);
14971
size_t read = fread(&buf[0], 1, TEXTFILE_BUF_MAX_SIZE, handle);
14972
buf.resize(read);
14973
14974
bufPos = 0;
14975
}
14976
14977
wchar_t TextFile::readCharacter()
14978
{
14979
wchar_t value;
14980
14981
switch (encoding)
14982
{
14983
case UTF8:
14984
{
14985
value = bufGetChar();
14986
contentPos++;
14987
14988
int extraBytes = 0;
14989
if ((value & 0xE0) == 0xC0)
14990
{
14991
extraBytes = 1;
14992
value &= 0x1F;
14993
} else if ((value & 0xF0) == 0xE0)
14994
{
14995
extraBytes = 2;
14996
value &= 0x0F;
14997
} else if (value > 0x7F)
14998
{
14999
errorText = formatString(L"One or more invalid UTF-8 characters in this file");
15000
}
15001
15002
for (int i = 0; i < extraBytes; i++)
15003
{
15004
int b = bufGetChar();
15005
contentPos++;
15006
15007
if ((b & 0xC0) != 0x80)
15008
{
15009
errorText = formatString(L"One or more invalid UTF-8 characters in this file");
15010
}
15011
15012
value = (value << 6) | (b & 0x3F);
15013
}
15014
}
15015
break;
15016
case UTF16LE:
15017
if (fromMemory)
15018
{
15019
value = content[contentPos++];
15020
} else {
15021
value = bufGet16LE();
15022
contentPos += 2;
15023
}
15024
break;
15025
case UTF16BE:
15026
value = bufGet16BE();
15027
contentPos += 2;
15028
break;
15029
case SJIS:
15030
{
15031
unsigned short sjis = bufGetChar();
15032
contentPos++;
15033
if (sjis >= 0x80)
15034
{
15035
sjis = (sjis << 8) | bufGetChar();
15036
contentPos++;
15037
}
15038
value = sjisToUnicode(sjis);
15039
if (value == (wchar_t)-1)
15040
{
15041
errorText = formatString(L"One or more invalid Shift-JIS characters in this file");
15042
}
15043
}
15044
break;
15045
case ASCII:
15046
value = bufGetChar();
15047
contentPos++;
15048
break;
15049
case GUESS:
15050
errorText = formatString(L"Cannot read from GUESS encoding");
15051
break;
15052
}
15053
15054
// convert \r\n to \n
15055
if (value == L'\r' && recursion == false && atEnd() == false)
15056
{
15057
recursion = true;
15058
long pos = tell();
15059
wchar_t nextValue = readCharacter();
15060
recursion = false;
15061
15062
if (nextValue == L'\n')
15063
return nextValue;
15064
seek(pos);
15065
}
15066
15067
return value;
15068
}
15069
15070
std::wstring TextFile::readLine()
15071
{
15072
std::wstring result;
15073
wchar_t value;
15074
15075
if (isOpen())
15076
{
15077
while (tell() < size() && (value = readCharacter()) != L'\n')
15078
{
15079
result += value;
15080
}
15081
}
15082
15083
lineCount++;
15084
return result;
15085
}
15086
15087
StringList TextFile::readAll()
15088
{
15089
StringList result;
15090
while (!atEnd())
15091
{
15092
result.push_back(readLine());
15093
}
15094
15095
return result;
15096
}
15097
15098
void TextFile::bufPut(const void *p, const size_t len)
15099
{
15100
assert(mode == Write);
15101
15102
if (len > TEXTFILE_BUF_MAX_SIZE)
15103
{
15104
// Lots of data. Let's write directly.
15105
bufDrainWrite();
15106
fwrite(p, 1, len, handle);
15107
}
15108
else
15109
{
15110
if (bufPos + len > TEXTFILE_BUF_MAX_SIZE)
15111
bufDrainWrite();
15112
15113
memcpy(&buf[bufPos], p, len);
15114
bufPos += len;
15115
}
15116
}
15117
15118
void TextFile::bufPut(const char c)
15119
{
15120
assert(mode == Write);
15121
15122
if (bufPos >= TEXTFILE_BUF_MAX_SIZE)
15123
bufDrainWrite();
15124
15125
buf[bufPos++] = c;
15126
}
15127
15128
void TextFile::bufDrainWrite()
15129
{
15130
fwrite(&buf[0], 1, bufPos, handle);
15131
bufPos = 0;
15132
}
15133
15134
void TextFile::writeCharacter(wchar_t character)
15135
{
15136
if (mode != Write) return;
15137
15138
// only support utf8 for now
15139
if (character < 0x80)
15140
{
15141
#ifdef _WIN32
15142
if (character == L'\n')
15143
{
15144
bufPut('\r');
15145
}
15146
#endif
15147
bufPut(character & 0x7F);
15148
} else if (encoding != ASCII)
15149
{
15150
if (character < 0x800)
15151
{
15152
bufPut(0xC0 | ((character >> 6) & 0x1F));
15153
bufPut(0x80 | (character & 0x3F));
15154
} else {
15155
bufPut(0xE0 | ((character >> 12) & 0xF));
15156
bufPut(0x80 | ((character >> 6) & 0x3F));
15157
bufPut(0x80 | (character & 0x3F));
15158
}
15159
}
15160
}
15161
15162
void TextFile::write(const wchar_t* line)
15163
{
15164
if (mode != Write) return;
15165
while (*line != 0)
15166
{
15167
writeCharacter(*line);
15168
line++;
15169
}
15170
}
15171
15172
void TextFile::write(const std::wstring& line)
15173
{
15174
write(line.c_str());
15175
}
15176
15177
void TextFile::write(const char* line)
15178
{
15179
if (mode != Write) return;
15180
while (*line != 0)
15181
{
15182
writeCharacter(*line);
15183
line++;
15184
}
15185
}
15186
15187
void TextFile::write(const std::string& line)
15188
{
15189
write(line.c_str());
15190
}
15191
15192
void TextFile::writeLine(const wchar_t* line)
15193
{
15194
if (mode != Write) return;
15195
write(line);
15196
writeCharacter(L'\n');
15197
}
15198
15199
void TextFile::writeLine(const std::wstring& line)
15200
{
15201
writeLine(line.c_str());
15202
}
15203
15204
void TextFile::writeLine(const char* line)
15205
{
15206
if (mode != Write) return;
15207
write(line);
15208
writeCharacter(L'\n');
15209
}
15210
15211
void TextFile::writeLine(const std::string& line)
15212
{
15213
writeLine(line.c_str());
15214
}
15215
15216
void TextFile::writeLines(StringList& list)
15217
{
15218
for (size_t i = 0; i < list.size(); i++)
15219
{
15220
writeLine(list[i]);
15221
}
15222
}
15223
15224
struct EncodingValue
15225
{
15226
const wchar_t* name;
15227
TextFile::Encoding value;
15228
};
15229
15230
const EncodingValue encodingValues[] = {
15231
{ L"sjis", TextFile::SJIS },
15232
{ L"shift-jis", TextFile::SJIS },
15233
{ L"utf8", TextFile::UTF8 },
15234
{ L"utf-8", TextFile::UTF8 },
15235
{ L"utf16", TextFile::UTF16LE },
15236
{ L"utf-16", TextFile::UTF16LE },
15237
{ L"utf16-be", TextFile::UTF16BE },
15238
{ L"utf-16-be", TextFile::UTF16BE },
15239
{ L"ascii", TextFile::ASCII },
15240
};
15241
15242
TextFile::Encoding getEncodingFromString(const std::wstring& str)
15243
{
15244
for (size_t i = 0; i < sizeof(encodingValues)/sizeof(EncodingValue); i++)
15245
{
15246
if (str.compare(encodingValues[i].name) == 0)
15247
return encodingValues[i].value;
15248
}
15249
15250
return TextFile::GUESS;
15251
}
15252
15253
// file: Util/Util.cpp
15254
#include <sys/stat.h>
15255
#ifdef _WIN32
15256
#include <windows.h>
15257
#include <shlwapi.h>
15258
#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PARTITION)
15259
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
15260
#define ARMIPS_WINDOWS_UWP
15261
#endif
15262
#endif
15263
#else
15264
#include <unistd.h>
15265
#endif
15266
15267
std::wstring convertUtf8ToWString(const char* source)
15268
{
15269
std::wstring result;
15270
15271
int index = 0;
15272
while (source[index] != 0)
15273
{
15274
int extraBytes = 0;
15275
int value = source[index++];
15276
15277
if ((value & 0xE0) == 0xC0)
15278
{
15279
extraBytes = 1;
15280
value &= 0x1F;
15281
} else if ((value & 0xF0) == 0xE0)
15282
{
15283
extraBytes = 2;
15284
value &= 0x0F;
15285
} else if (value > 0x7F)
15286
{
15287
// error
15288
return std::wstring();
15289
}
15290
15291
for (int i = 0; i < extraBytes; i++)
15292
{
15293
int b = source[index++];
15294
if ((b & 0xC0) != 0x80)
15295
{
15296
// error
15297
return std::wstring();
15298
}
15299
15300
value = (value << 6) | (b & 0x3F);
15301
}
15302
15303
result += value;
15304
}
15305
15306
return result;
15307
}
15308
15309
std::string convertWCharToUtf8(wchar_t character)
15310
{
15311
std::string result;
15312
15313
if (character < 0x80)
15314
{
15315
result += character & 0x7F;
15316
} else if (character < 0x800)
15317
{
15318
result += 0xC0 | ((character >> 6) & 0x1F);
15319
result += (0x80 | (character & 0x3F));
15320
} else {
15321
result += 0xE0 | ((character >> 12) & 0xF);
15322
result += 0x80 | ((character >> 6) & 0x3F);
15323
result += 0x80 | (character & 0x3F);
15324
}
15325
15326
return result;
15327
}
15328
15329
std::string convertWStringToUtf8(const std::wstring& source)
15330
{
15331
std::string result;
15332
15333
for (size_t i = 0; i < source.size(); i++)
15334
{
15335
wchar_t character = source[i];
15336
if (character < 0x80)
15337
{
15338
result += character & 0x7F;
15339
} else if (character < 0x800)
15340
{
15341
result += 0xC0 | ((character >> 6) & 0x1F);
15342
result += (0x80 | (character & 0x3F));
15343
} else {
15344
result += 0xE0 | ((character >> 12) & 0xF);
15345
result += 0x80 | ((character >> 6) & 0x3F);
15346
result += 0x80 | (character & 0x3F);
15347
}
15348
}
15349
15350
return result;
15351
}
15352
15353
std::wstring intToHexString(unsigned int value, int digits, bool prefix)
15354
{
15355
std::wstring result;
15356
result.reserve((digits+prefix) ? 2 : 0);
15357
15358
if (prefix)
15359
{
15360
result += '0';
15361
result += 'x';
15362
}
15363
15364
while (digits > 8)
15365
{
15366
result += '0';
15367
digits--;
15368
}
15369
15370
wchar_t buf[9];
15371
swprintf(buf,9,L"%0*X",digits,value);
15372
result += buf;
15373
15374
return result;
15375
}
15376
15377
std::wstring intToString(unsigned int value, int digits)
15378
{
15379
std::wstring result;
15380
result.reserve(digits);
15381
15382
while (digits > 8)
15383
{
15384
result += ' ';
15385
digits--;
15386
}
15387
15388
wchar_t buf[9];
15389
swprintf(buf,9,L"%*d",digits,value);
15390
result += buf;
15391
15392
return result;
15393
}
15394
15395
bool stringToInt(const std::wstring& line, size_t start, size_t end, int64_t& result)
15396
{
15397
// find base of number
15398
int32_t base = 10;
15399
if (line[start] == '0')
15400
{
15401
if (towlower(line[start+1]) == 'x')
15402
{
15403
base = 16;
15404
start += 2;
15405
} else if (towlower(line[start+1]) == 'o')
15406
{
15407
base = 8;
15408
start += 2;
15409
} else if (towlower(line[start+1]) == 'b' && towlower(line[end-1]) != 'h')
15410
{
15411
base = 2;
15412
start += 2;
15413
}
15414
}
15415
15416
if (base == 10)
15417
{
15418
if (towlower(line[end-1]) == 'h')
15419
{
15420
base = 16;
15421
end--;
15422
} else if (towlower(line[end-1]) == 'b')
15423
{
15424
base = 2;
15425
end--;
15426
} else if (towlower(line[end-1]) == 'o')
15427
{
15428
base = 8;
15429
end--;
15430
}
15431
}
15432
15433
// convert number
15434
result = 0;
15435
while (start < end)
15436
{
15437
wchar_t c = towlower(line[start++]);
15438
15439
int32_t value = c >= 'a' ? c-'a'+10 : c-'0';
15440
15441
if (value >= base)
15442
return false;
15443
15444
result = (result*base) + value;
15445
}
15446
15447
return true;
15448
}
15449
15450
int32_t getFloatBits(float value)
15451
{
15452
union { float f; int32_t i; } u;
15453
u.f = value;
15454
return u.i;
15455
}
15456
15457
float bitsToFloat(int32_t value)
15458
{
15459
union { float f; int32_t i; } u;
15460
u.i = value;
15461
return u.f;
15462
}
15463
15464
int64_t getDoubleBits(double value)
15465
{
15466
union { double f; int64_t i; } u;
15467
u.f = value;
15468
return u.i;
15469
}
15470
15471
StringList getStringListFromArray(wchar_t** source, int count)
15472
{
15473
StringList result;
15474
for (int i = 0; i < count; i++)
15475
{
15476
result.push_back(std::wstring(source[i]));
15477
}
15478
15479
return result;
15480
}
15481
15482
StringList splitString(const std::wstring& str, const wchar_t delim, bool skipEmpty)
15483
{
15484
StringList result;
15485
std::wstringstream stream(str);
15486
std::wstring arg;
15487
while (std::getline(stream,arg,delim))
15488
{
15489
if (arg.empty() && skipEmpty) continue;
15490
result.push_back(arg);
15491
}
15492
15493
return result;
15494
}
15495
15496
int64_t fileSize(const std::wstring& fileName)
15497
{
15498
#ifdef _WIN32
15499
WIN32_FILE_ATTRIBUTE_DATA attr;
15500
if (!GetFileAttributesEx(fileName.c_str(),GetFileExInfoStandard,&attr)
15501
|| (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
15502
return 0;
15503
return ((int64_t) attr.nFileSizeHigh << 32) | (int64_t) attr.nFileSizeLow;
15504
#else
15505
std::string utf8 = convertWStringToUtf8(fileName);
15506
struct stat fileStat;
15507
int err = stat(utf8.c_str(),&fileStat);
15508
if (0 != err)
15509
return 0;
15510
return fileStat.st_size;
15511
#endif
15512
}
15513
15514
bool fileExists(const std::wstring& strFilename)
15515
{
15516
#ifdef _WIN32
15517
#ifdef ARMIPS_WINDOWS_UWP
15518
return GetFileAttributes(strFilename.c_str()) != INVALID_FILE_ATTRIBUTES;
15519
#else
15520
int OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
15521
bool success = GetFileAttributes(strFilename.c_str()) != INVALID_FILE_ATTRIBUTES;
15522
SetErrorMode(OldMode);
15523
return success;
15524
#endif
15525
#else
15526
std::string utf8 = convertWStringToUtf8(strFilename);
15527
struct stat stFileInfo;
15528
int intStat = stat(utf8.c_str(),&stFileInfo);
15529
return intStat == 0;
15530
#endif
15531
}
15532
15533
bool copyFile(const std::wstring& existingFile, const std::wstring& newFile)
15534
{
15535
#ifdef _WIN32
15536
return CopyFileW(existingFile.c_str(),newFile.c_str(),false) != FALSE;
15537
#else
15538
unsigned char buffer[BUFSIZ];
15539
bool error = false;
15540
15541
std::string existingUtf8 = convertWStringToUtf8(existingFile);
15542
std::string newUtf8 = convertWStringToUtf8(newFile);
15543
15544
FILE* input = fopen(existingUtf8.c_str(),"rb");
15545
FILE* output = fopen(newUtf8.c_str(),"wb");
15546
15547
if (input == nullptr || output == nullptr)
15548
return false;
15549
15550
size_t n;
15551
while ((n = fread(buffer,1,BUFSIZ,input)) > 0)
15552
{
15553
if (fwrite(buffer,1,n,output) != n)
15554
error = true;
15555
}
15556
15557
fclose(input);
15558
fclose(output);
15559
return !error;
15560
#endif
15561
}
15562
15563
bool deleteFile(const std::wstring& fileName)
15564
{
15565
#ifdef _WIN32
15566
return DeleteFileW(fileName.c_str()) != FALSE;
15567
#else
15568
std::string utf8 = convertWStringToUtf8(fileName);
15569
return unlink(utf8.c_str()) == 0;
15570
#endif
15571
}
15572
15573
FILE* openFile(const std::wstring& fileName, OpenFileMode mode)
15574
{
15575
#ifdef _WIN32
15576
switch (mode)
15577
{
15578
case OpenFileMode::ReadBinary:
15579
return _wfopen(fileName.c_str(),L"rb");
15580
case OpenFileMode::WriteBinary:
15581
return _wfopen(fileName.c_str(),L"wb");
15582
case OpenFileMode::ReadWriteBinary:
15583
return _wfopen(fileName.c_str(),L"rb+");
15584
}
15585
#else
15586
std::string nameUtf8 = convertWStringToUtf8(fileName);
15587
15588
switch (mode)
15589
{
15590
case OpenFileMode::ReadBinary:
15591
return fopen(nameUtf8.c_str(),"rb");
15592
case OpenFileMode::WriteBinary:
15593
return fopen(nameUtf8.c_str(),"wb");
15594
case OpenFileMode::ReadWriteBinary:
15595
return fopen(nameUtf8.c_str(),"rb+");
15596
}
15597
#endif
15598
15599
return nullptr;
15600
}
15601
15602
std::wstring getCurrentDirectory()
15603
{
15604
#ifdef _WIN32
15605
wchar_t dir[MAX_PATH];
15606
_wgetcwd(dir,MAX_PATH-1);
15607
return dir;
15608
#else
15609
char* dir = getcwd(nullptr,0);
15610
std::wstring result = convertUtf8ToWString(dir);
15611
free(dir);
15612
return result;
15613
#endif
15614
}
15615
15616
bool changeDirectory(const std::wstring& dir)
15617
{
15618
#ifdef _WIN32
15619
return _wchdir(dir.c_str()) == 0;
15620
#else
15621
std::string utf8 = convertWStringToUtf8(dir);
15622
return chdir(utf8.c_str()) == 0;
15623
#endif
15624
}
15625
15626
std::wstring toWLowercase(const std::string& str)
15627
{
15628
std::wstring result;
15629
for (size_t i = 0; i < str.size(); i++)
15630
{
15631
result += tolower(str[i]);
15632
}
15633
15634
return result;
15635
}
15636
15637
std::wstring getFileNameFromPath(const std::wstring& path)
15638
{
15639
size_t n = path.find_last_of(L"/\\");
15640
if (n == path.npos)
15641
return path;
15642
return path.substr(n);
15643
}
15644
15645
size_t replaceAll(std::wstring& str, const wchar_t* oldValue,const std::wstring& newValue)
15646
{
15647
size_t pos = 0;
15648
size_t len = wcslen(oldValue);
15649
15650
size_t count = 0;
15651
while ((pos = str.find(oldValue, pos)) != std::string::npos)
15652
{
15653
str.replace(pos,len,newValue);
15654
pos += newValue.length();
15655
count++;
15656
}
15657
15658
return count;
15659
}
15660
15661
bool startsWith(const std::wstring& str, const wchar_t* value, size_t stringPos)
15662
{
15663
while (*value != 0 && stringPos < str.size())
15664
{
15665
if (str[stringPos++] != *value++)
15666
return false;
15667
}
15668
15669
return *value == 0;
15670
}
15671
15672
bool isAbsolutePath(const std::wstring& path)
15673
{
15674
#ifdef _WIN32
15675
return path.size() > 2 && (path[1] == ':' || (path[0] == '\\' && path[1] == '\\'));
15676
#else
15677
return path.size() >= 1 && path[0] == '/';
15678
#endif
15679
}
15680
15681
// file: Main/CommandLineInterface.h
15682
15683
int runFromCommandLine(const StringList& arguments, ArmipsArguments settings = {});
15684
15685
// file: Main/CommandLineInterface.cpp
15686
15687
static void printUsage(std::wstring executableName)
15688
{
15689
Logger::printLine(L"armips assembler v%d.%d.%d (%s %s) by Kingcom",
15690
ARMIPS_VERSION_MAJOR, ARMIPS_VERSION_MINOR, ARMIPS_VERSION_REVISION, __DATE__, __TIME__);
15691
Logger::printLine(L"Usage: %s [optional parameters] <FILE>", executableName);
15692
Logger::printLine(L"");
15693
Logger::printLine(L"Optional parameters:");
15694
Logger::printLine(L" -temp <TEMP> Output temporary assembly data to <TEMP> file");
15695
Logger::printLine(L" -sym <SYM> Output symbol data in the sym format to <SYM> file");
15696
Logger::printLine(L" -sym2 <SYM2> Output symbol data in the sym2 format to <SYM2> file");
15697
Logger::printLine(L" -root <ROOT> Use <ROOT> as working directory during execution");
15698
Logger::printLine(L" -equ <NAME> <VAL> Equivalent to \'<NAME> equ <VAL>\' in code");
15699
Logger::printLine(L" -strequ <NAME> <VAL> Equivalent to \'<NAME> equ \"<VAL>\"\' in code");
15700
Logger::printLine(L" -definelabel <NAME> <VAL> Equivalent to \'.definelabel <NAME>, <VAL>\' in code");
15701
Logger::printLine(L" -erroronwarning Treat all warnings like errors");
15702
Logger::printLine(L"");
15703
Logger::printLine(L"File arguments:");
15704
Logger::printLine(L" <FILE> Main assembly code file");
15705
}
15706
15707
static bool parseArguments(const StringList& arguments, ArmipsArguments& settings)
15708
{
15709
size_t argpos = 1;
15710
bool readflags = true;
15711
while (argpos < arguments.size())
15712
{
15713
if (readflags && arguments[argpos][0] == L'-')
15714
{
15715
if (arguments[argpos] == L"--")
15716
{
15717
readflags = false;
15718
argpos += 1;
15719
}
15720
else if (arguments[argpos] == L"-temp" && argpos + 1 < arguments.size())
15721
{
15722
settings.tempFileName = arguments[argpos + 1];
15723
argpos += 2;
15724
}
15725
else if (arguments[argpos] == L"-sym" && argpos + 1 < arguments.size())
15726
{
15727
settings.symFileName = arguments[argpos + 1];
15728
settings.symFileVersion = 1;
15729
argpos += 2;
15730
}
15731
else if (arguments[argpos] == L"-sym2" && argpos + 1 < arguments.size())
15732
{
15733
settings.symFileName = arguments[argpos + 1];
15734
settings.symFileVersion = 2;
15735
argpos += 2;
15736
}
15737
else if (arguments[argpos] == L"-erroronwarning")
15738
{
15739
settings.errorOnWarning = true;
15740
argpos += 1;
15741
}
15742
else if (arguments[argpos] == L"-equ" && argpos + 2 < arguments.size())
15743
{
15744
EquationDefinition def;
15745
15746
def.name = arguments[argpos+1];
15747
std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);
15748
15749
if (!checkValidLabelName(def.name))
15750
{
15751
Logger::printError(Logger::Error, L"Invalid equation name \"%s\"", def.name);
15752
return false;
15753
}
15754
15755
auto it = std::find_if(settings.equList.begin(), settings.equList.end(),
15756
[&def](EquationDefinition x) -> bool {return def.name == x.name;});
15757
if(it != settings.equList.end())
15758
{
15759
Logger::printError(Logger::Error, L"Equation name \"%s\" already defined", def.name);
15760
return false;
15761
}
15762
15763
def.value = arguments[argpos + 2];
15764
settings.equList.push_back(def);
15765
argpos += 3;
15766
}
15767
else if (arguments[argpos] == L"-strequ" && argpos + 2 < arguments.size())
15768
{
15769
EquationDefinition def;
15770
15771
def.name = arguments[argpos+1];
15772
std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);
15773
15774
if (!checkValidLabelName(def.name))
15775
{
15776
Logger::printError(Logger::Error, L"Invalid equation name \"%s\"", def.name);
15777
return false;
15778
}
15779
15780
auto it = std::find_if(settings.equList.begin(), settings.equList.end(),
15781
[&def](EquationDefinition x) -> bool {return def.name == x.name;});
15782
if(it != settings.equList.end())
15783
{
15784
Logger::printError(Logger::Error, L"Equation name \"%s\" already defined", def.name);
15785
return false;
15786
}
15787
15788
def.value = formatString(L"\"%s\"", arguments[argpos + 2]);
15789
settings.equList.push_back(def);
15790
argpos += 3;
15791
}
15792
else if (arguments[argpos] == L"-time")
15793
{
15794
Logger::printError(Logger::Warning, L"-time flag is deprecated");
15795
argpos += 1;
15796
}
15797
else if (arguments[argpos] == L"-root" && argpos + 1 < arguments.size())
15798
{
15799
if(!changeDirectory(arguments[argpos + 1]))
15800
{
15801
Logger::printError(Logger::Error, L"Could not open directory \"%s\"", arguments[argpos + 1]);
15802
return false;
15803
}
15804
argpos += 2;
15805
}
15806
else if (arguments[argpos] == L"-definelabel" && argpos + 2 < arguments.size())
15807
{
15808
LabelDefinition def;
15809
15810
def.originalName = arguments[argpos + 1];
15811
def.name = def.originalName;
15812
std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);
15813
15814
if (!checkValidLabelName(def.name))
15815
{
15816
Logger::printError(Logger::Error, L"Invalid label name \"%s\"", def.name);
15817
return false;
15818
}
15819
15820
auto it = std::find_if(settings.labels.begin(), settings.labels.end(),
15821
[&def](LabelDefinition x) -> bool {return def.name == x.name;});
15822
if(it != settings.labels.end())
15823
{
15824
Logger::printError(Logger::Error, L"Label name \"%s\" already defined", def.name);
15825
return false;
15826
}
15827
15828
int64_t value;
15829
if (!stringToInt(arguments[argpos + 2], 0, arguments[argpos + 2].size(), value))
15830
{
15831
Logger::printError(Logger::Error, L"Invalid label value \"%s\"", arguments[argpos + 2]);
15832
return false;
15833
}
15834
def.value = value;
15835
15836
settings.labels.push_back(def);
15837
argpos += 3;
15838
}
15839
else {
15840
Logger::printError(Logger::Error, L"Invalid command line argument \"%s\"\n", arguments[argpos]);
15841
printUsage(arguments[0]);
15842
return false;
15843
}
15844
}
15845
else {
15846
// only allow one input filename
15847
if (settings.inputFileName == L"")
15848
{
15849
settings.inputFileName = arguments[argpos];
15850
argpos++;
15851
}
15852
else {
15853
Logger::printError(Logger::Error, L"Multiple input assembly files specified\n");
15854
printUsage(arguments[0]);
15855
return false;
15856
}
15857
}
15858
}
15859
15860
// ensure input file was specified
15861
if (settings.inputFileName == L"")
15862
{
15863
if (arguments.size() > 1)
15864
Logger::printError(Logger::Error, L"Missing input assembly file\n");
15865
15866
printUsage(arguments[0]);
15867
return false;
15868
}
15869
15870
// turn input filename into an absolute path
15871
if (settings.useAbsoluteFileNames && isAbsolutePath(settings.inputFileName) == false)
15872
settings.inputFileName = formatString(L"%s/%s", getCurrentDirectory(), settings.inputFileName);
15873
15874
if (fileExists(settings.inputFileName) == false)
15875
{
15876
Logger::printError(Logger::Error, L"File \"%s\" not found", settings.inputFileName);
15877
return false;
15878
}
15879
return true;
15880
}
15881
15882
int runFromCommandLine(const StringList& arguments, ArmipsArguments settings)
15883
{
15884
if (parseArguments(arguments, settings) == false)
15885
{
15886
if (arguments.size() > 1 && !settings.silent)
15887
Logger::printLine(L"Cannot parse arguments; aborting.");
15888
15889
return 1;
15890
}
15891
15892
if (runArmips(settings) == false)
15893
{
15894
if (!settings.silent)
15895
Logger::printLine(L"Aborting.");
15896
15897
return 1;
15898
}
15899
15900
return 0;
15901
}
15902
15903
// file: Core/ELF/ElfFile.cpp
15904
#include <vector>
15905
#include <algorithm>
15906
15907
#ifndef _WIN32
15908
#include <strings.h>
15909
#define _stricmp strcasecmp
15910
#endif
15911
15912
static bool stringEqualInsensitive(const std::string& a, const std::string& b)
15913
{
15914
if (a.size() != b.size())
15915
return false;
15916
return _stricmp(a.c_str(),b.c_str()) == 0;
15917
}
15918
15919
bool compareSection(ElfSection* a, ElfSection* b)
15920
{
15921
return a->getOffset() < b->getOffset();
15922
}
15923
15924
ElfSection::ElfSection(Elf32_Shdr header): header(header)
15925
{
15926
owner = nullptr;
15927
}
15928
15929
void ElfSection::setOwner(ElfSegment* segment)
15930
{
15931
header.sh_offset -= segment->getOffset();
15932
owner = segment;
15933
}
15934
15935
void ElfSection::writeHeader(ByteArray& data, int pos, Endianness endianness)
15936
{
15937
data.replaceDoubleWord(pos + 0x00, header.sh_name, endianness);
15938
data.replaceDoubleWord(pos + 0x04, header.sh_type, endianness);
15939
data.replaceDoubleWord(pos + 0x08, header.sh_flags, endianness);
15940
data.replaceDoubleWord(pos + 0x0C, header.sh_addr, endianness);
15941
data.replaceDoubleWord(pos + 0x10, header.sh_offset, endianness);
15942
data.replaceDoubleWord(pos + 0x14, header.sh_size, endianness);
15943
data.replaceDoubleWord(pos + 0x18, header.sh_link, endianness);
15944
data.replaceDoubleWord(pos + 0x1C, header.sh_info, endianness);
15945
data.replaceDoubleWord(pos + 0x20, header.sh_addralign, endianness);
15946
data.replaceDoubleWord(pos + 0x24, header.sh_entsize, endianness);
15947
}
15948
15949
// only called for segmentless sections
15950
void ElfSection::writeData(ByteArray& output)
15951
{
15952
if (header.sh_type == SHT_NULL) return;
15953
15954
// nobits sections still get a provisional file address
15955
if (header.sh_type == SHT_NOBITS)
15956
{
15957
header.sh_offset = (Elf32_Off) output.size();
15958
}
15959
15960
if (header.sh_addralign != (unsigned) -1)
15961
output.alignSize(header.sh_addralign);
15962
header.sh_offset = (Elf32_Off) output.size();
15963
output.append(data);
15964
}
15965
15966
void ElfSection::setOffsetBase(int base)
15967
{
15968
header.sh_offset += base;
15969
}
15970
15971
ElfSegment::ElfSegment(Elf32_Phdr header, ByteArray& segmentData): header(header)
15972
{
15973
data = segmentData;
15974
paddrSection = nullptr;
15975
}
15976
15977
bool ElfSegment::isSectionPartOf(ElfSection* section)
15978
{
15979
int sectionStart = section->getOffset();
15980
int sectionSize = section->getType() == SHT_NOBITS ? 0 : section->getSize();
15981
int sectionEnd = sectionStart+sectionSize;
15982
15983
int segmentStart = header.p_offset;
15984
int segmentEnd = segmentStart+header.p_filesz;
15985
15986
// exclusive > in case the size is 0
15987
if (sectionStart < (int)header.p_offset || sectionStart > segmentEnd) return false;
15988
15989
// does an empty section belong to this or the next segment? hm...
15990
if (sectionStart == segmentEnd) return sectionSize == 0;
15991
15992
// the start is inside the section and the size is not 0, so the end should be in here too
15993
if (sectionEnd > segmentEnd)
15994
{
15995
Logger::printError(Logger::Error,L"Section partially contained in segment");
15996
return false;
15997
}
15998
15999
return true;
16000
}
16001
16002
void ElfSegment::addSection(ElfSection* section)
16003
{
16004
if (header.p_paddr != 0)
16005
{
16006
if (section->getOffset() == header.p_paddr)
16007
{
16008
paddrSection = section;
16009
}
16010
}
16011
16012
section->setOwner(this);
16013
sections.push_back(section);
16014
}
16015
16016
void ElfSegment::writeData(ByteArray& output)
16017
{
16018
if (sections.size() == 0)
16019
{
16020
output.alignSize(header.p_align);
16021
if (header.p_offset == header.p_paddr)
16022
header.p_paddr = (Elf32_Addr) output.size();
16023
16024
header.p_offset = (Elf32_Off) output.size();
16025
return;
16026
}
16027
16028
// align segment to alignment of first section
16029
int align = std::max<int>(sections[0]->getAlignment(),16);
16030
output.alignSize(align);
16031
16032
header.p_offset = (Elf32_Off) output.size();
16033
for (int i = 0; i < (int)sections.size(); i++)
16034
{
16035
sections[i]->setOffsetBase(header.p_offset);
16036
}
16037
16038
if (paddrSection)
16039
{
16040
header.p_paddr = paddrSection->getOffset();
16041
}
16042
16043
output.append(data);
16044
}
16045
16046
void ElfSegment::writeHeader(ByteArray& data, int pos, Endianness endianness)
16047
{
16048
data.replaceDoubleWord(pos + 0x00, header.p_type, endianness);
16049
data.replaceDoubleWord(pos + 0x04, header.p_offset, endianness);
16050
data.replaceDoubleWord(pos + 0x08, header.p_vaddr, endianness);
16051
data.replaceDoubleWord(pos + 0x0C, header.p_paddr, endianness);
16052
data.replaceDoubleWord(pos + 0x10, header.p_filesz, endianness);
16053
data.replaceDoubleWord(pos + 0x14, header.p_memsz, endianness);
16054
data.replaceDoubleWord(pos + 0x18, header.p_flags, endianness);
16055
data.replaceDoubleWord(pos + 0x1C, header.p_align, endianness);
16056
}
16057
16058
void ElfSegment::splitSections()
16059
{
16060
16061
}
16062
16063
int ElfSegment::findSection(const std::string& name)
16064
{
16065
for (size_t i = 0; i < sections.size(); i++)
16066
{
16067
if (stringEqualInsensitive(name,sections[i]->getName()))
16068
return i;
16069
}
16070
16071
return -1;
16072
}
16073
16074
void ElfSegment::writeToData(size_t offset, void* src, size_t size)
16075
{
16076
for (size_t i = 0; i < size; i++)
16077
{
16078
data[offset+i] = ((byte*)src)[i];
16079
}
16080
}
16081
16082
void ElfSegment::sortSections()
16083
{
16084
std::sort(sections.begin(),sections.end(),compareSection);
16085
}
16086
16087
void ElfFile::loadSectionNames()
16088
{
16089
if (fileHeader.e_shstrndx == SHN_UNDEF) return;
16090
16091
// check if the string table is actually a string table
16092
// sometimes it gives the wrong section id
16093
size_t strTablePos = sections[fileHeader.e_shstrndx]->getOffset();
16094
size_t strTableSize = sections[fileHeader.e_shstrndx]->getSize();
16095
for (size_t i = 0; i < strTableSize; i++)
16096
{
16097
if (fileData[strTablePos+i] != 0 && fileData[strTablePos+i] < 0x20)
16098
return;
16099
if (fileData[strTablePos+i] > 0x7F)
16100
return;
16101
}
16102
16103
for (size_t i = 0; i < sections.size(); i++)
16104
{
16105
ElfSection* section = sections[i];
16106
if (section->getType() == SHT_NULL) continue;
16107
16108
int strTablePos = sections[fileHeader.e_shstrndx]->getOffset();
16109
int offset = strTablePos+section->getNameOffset();
16110
16111
char* name = (char*) fileData.data(offset);
16112
std::string strName = name;
16113
section->setName(strName);
16114
}
16115
}
16116
16117
void ElfFile::determinePartOrder()
16118
{
16119
size_t segmentTable = fileHeader.e_phoff;
16120
size_t sectionTable = fileHeader.e_shoff;
16121
16122
// segments
16123
size_t firstSegmentStart = fileData.size(), lastSegmentEnd = 0;
16124
for (size_t i = 0; i < fileHeader.e_phnum; i++)
16125
{
16126
size_t pos = fileHeader.e_phoff+i*fileHeader.e_phentsize;
16127
16128
Elf32_Phdr segmentHeader;
16129
loadProgramHeader(segmentHeader, fileData, pos);
16130
size_t end = segmentHeader.p_offset + segmentHeader.p_filesz;
16131
16132
if (segmentHeader.p_offset < firstSegmentStart) firstSegmentStart = segmentHeader.p_offset;
16133
if (lastSegmentEnd < end) lastSegmentEnd = end;
16134
}
16135
16136
// segmentless sections
16137
size_t firstSectionStart = fileData.size(), lastSectionEnd = 0;
16138
for (size_t i = 0; i < segmentlessSections.size(); i++)
16139
{
16140
if (segmentlessSections[i]->getType() == SHT_NULL) continue;
16141
16142
size_t start = segmentlessSections[i]->getOffset();
16143
size_t end = start+segmentlessSections[i]->getSize();
16144
16145
if (start == 0 && end == 0)
16146
continue;
16147
if (start < firstSectionStart) firstSectionStart = start;
16148
if (lastSectionEnd < end) lastSectionEnd = end;
16149
}
16150
16151
struct PartsSort {
16152
size_t offset;
16153
ElfPart type;
16154
bool operator<(const PartsSort& other) const { return offset < other.offset; };
16155
};
16156
16157
PartsSort temp[4] = {
16158
{ segmentTable, ELFPART_SEGMENTTABLE },
16159
{ sectionTable, ELFPART_SECTIONTABLE },
16160
{ firstSegmentStart, ELFPART_SEGMENTS },
16161
{ firstSectionStart, ELFPART_SEGMENTLESSSECTIONS },
16162
};
16163
16164
std::sort(&temp[0],&temp[4]);
16165
16166
for (size_t i = 0; i < 4; i++)
16167
{
16168
partsOrder[i] = temp[i].type;
16169
}
16170
}
16171
16172
int ElfFile::findSegmentlessSection(const std::string& name)
16173
{
16174
for (size_t i = 0; i < segmentlessSections.size(); i++)
16175
{
16176
if (stringEqualInsensitive(name,segmentlessSections[i]->getName()))
16177
return i;
16178
}
16179
16180
return -1;
16181
}
16182
16183
void ElfFile::loadElfHeader()
16184
{
16185
memcpy(fileHeader.e_ident, &fileData[0], sizeof(fileHeader.e_ident));
16186
Endianness endianness = getEndianness();
16187
fileHeader.e_type = fileData.getWord(0x10, endianness);
16188
fileHeader.e_machine = fileData.getWord(0x12, endianness);
16189
fileHeader.e_version = fileData.getDoubleWord(0x14, endianness);
16190
fileHeader.e_entry = fileData.getDoubleWord(0x18, endianness);
16191
fileHeader.e_phoff = fileData.getDoubleWord(0x1C, endianness);
16192
fileHeader.e_shoff = fileData.getDoubleWord(0x20, endianness);
16193
fileHeader.e_flags = fileData.getDoubleWord(0x24, endianness);
16194
fileHeader.e_ehsize = fileData.getWord(0x28, endianness);
16195
fileHeader.e_phentsize = fileData.getWord(0x2A, endianness);
16196
fileHeader.e_phnum = fileData.getWord(0x2C, endianness);
16197
fileHeader.e_shentsize = fileData.getWord(0x2E, endianness);
16198
fileHeader.e_shnum = fileData.getWord(0x30, endianness);
16199
fileHeader.e_shstrndx = fileData.getWord(0x32, endianness);
16200
}
16201
16202
void ElfFile::writeHeader(ByteArray& data, int pos, Endianness endianness)
16203
{
16204
memcpy(&fileData[0], fileHeader.e_ident, sizeof(fileHeader.e_ident));
16205
data.replaceWord(pos + 0x10, fileHeader.e_type, endianness);
16206
data.replaceWord(pos + 0x12, fileHeader.e_machine, endianness);
16207
data.replaceDoubleWord(pos + 0x14, fileHeader.e_version, endianness);
16208
data.replaceDoubleWord(pos + 0x18, fileHeader.e_entry, endianness);
16209
data.replaceDoubleWord(pos + 0x1C, fileHeader.e_phoff, endianness);
16210
data.replaceDoubleWord(pos + 0x20, fileHeader.e_shoff, endianness);
16211
data.replaceDoubleWord(pos + 0x24, fileHeader.e_flags, endianness);
16212
data.replaceWord(pos + 0x28, fileHeader.e_ehsize, endianness);
16213
data.replaceWord(pos + 0x2A, fileHeader.e_phentsize, endianness);
16214
data.replaceWord(pos + 0x2C, fileHeader.e_phnum, endianness);
16215
data.replaceWord(pos + 0x2E, fileHeader.e_shentsize, endianness);
16216
data.replaceWord(pos + 0x30, fileHeader.e_shnum, endianness);
16217
data.replaceWord(pos + 0x32, fileHeader.e_shstrndx, endianness);
16218
}
16219
16220
void ElfFile::loadProgramHeader(Elf32_Phdr& header, ByteArray& data, int pos)
16221
{
16222
Endianness endianness = getEndianness();
16223
header.p_type = data.getDoubleWord(pos + 0x00, endianness);
16224
header.p_offset = data.getDoubleWord(pos + 0x04, endianness);
16225
header.p_vaddr = data.getDoubleWord(pos + 0x08, endianness);
16226
header.p_paddr = data.getDoubleWord(pos + 0x0C, endianness);
16227
header.p_filesz = data.getDoubleWord(pos + 0x10, endianness);
16228
header.p_memsz = data.getDoubleWord(pos + 0x14, endianness);
16229
header.p_flags = data.getDoubleWord(pos + 0x18, endianness);
16230
header.p_align = data.getDoubleWord(pos + 0x1C, endianness);
16231
}
16232
16233
void ElfFile::loadSectionHeader(Elf32_Shdr& header, ByteArray& data, int pos)
16234
{
16235
Endianness endianness = getEndianness();
16236
header.sh_name = data.getDoubleWord(pos + 0x00, endianness);
16237
header.sh_type = data.getDoubleWord(pos + 0x04, endianness);
16238
header.sh_flags = data.getDoubleWord(pos + 0x08, endianness);
16239
header.sh_addr = data.getDoubleWord(pos + 0x0C, endianness);
16240
header.sh_offset = data.getDoubleWord(pos + 0x10, endianness);
16241
header.sh_size = data.getDoubleWord(pos + 0x14, endianness);
16242
header.sh_link = data.getDoubleWord(pos + 0x18, endianness);
16243
header.sh_info = data.getDoubleWord(pos + 0x1C, endianness);
16244
header.sh_addralign = data.getDoubleWord(pos + 0x20, endianness);
16245
header.sh_entsize = data.getDoubleWord(pos + 0x24, endianness);
16246
}
16247
16248
bool ElfFile::load(const std::wstring& fileName, bool sort)
16249
{
16250
ByteArray data = ByteArray::fromFile(fileName);
16251
if (data.size() == 0)
16252
return false;
16253
return load(data,sort);
16254
}
16255
16256
bool ElfFile::load(ByteArray& data, bool sort)
16257
{
16258
fileData = data;
16259
16260
loadElfHeader();
16261
symTab = nullptr;
16262
strTab = nullptr;
16263
16264
// load segments
16265
for (size_t i = 0; i < fileHeader.e_phnum; i++)
16266
{
16267
int pos = fileHeader.e_phoff+i*fileHeader.e_phentsize;
16268
16269
Elf32_Phdr sectionHeader;
16270
loadProgramHeader(sectionHeader, fileData, pos);
16271
16272
ByteArray segmentData = fileData.mid(sectionHeader.p_offset,sectionHeader.p_filesz);
16273
ElfSegment* segment = new ElfSegment(sectionHeader,segmentData);
16274
segments.push_back(segment);
16275
}
16276
16277
// load sections and assign them to segments
16278
for (int i = 0; i < fileHeader.e_shnum; i++)
16279
{
16280
int pos = fileHeader.e_shoff+i*fileHeader.e_shentsize;
16281
16282
Elf32_Shdr sectionHeader;
16283
loadSectionHeader(sectionHeader, fileData, pos);
16284
16285
ElfSection* section = new ElfSection(sectionHeader);
16286
sections.push_back(section);
16287
16288
// check if the section belongs to a segment
16289
ElfSegment* owner = nullptr;
16290
for (int k = 0; k < (int)segments.size(); k++)
16291
{
16292
if (segments[k]->isSectionPartOf(section))
16293
{
16294
owner = segments[k];
16295
break;
16296
}
16297
}
16298
16299
if (owner != nullptr)
16300
{
16301
owner->addSection(section);
16302
} else {
16303
if (section->getType() != SHT_NOBITS && section->getType() != SHT_NULL)
16304
{
16305
ByteArray data = fileData.mid(section->getOffset(),section->getSize());
16306
section->setData(data);
16307
}
16308
16309
switch (section->getType())
16310
{
16311
case SHT_SYMTAB:
16312
symTab = section;
16313
break;
16314
case SHT_STRTAB:
16315
if (!strTab || i != fileHeader.e_shstrndx)
16316
{
16317
strTab = section;
16318
}
16319
break;
16320
}
16321
16322
segmentlessSections.push_back(section);
16323
}
16324
}
16325
16326
determinePartOrder();
16327
loadSectionNames();
16328
16329
if (sort)
16330
{
16331
std::sort(segmentlessSections.begin(),segmentlessSections.end(),compareSection);
16332
16333
for (int i = 0; i < (int)segments.size(); i++)
16334
{
16335
segments[i]->sortSections();
16336
}
16337
}
16338
16339
return true;
16340
}
16341
16342
void ElfFile::save(const std::wstring&fileName)
16343
{
16344
fileData.clear();
16345
16346
// reserve space for header and table data
16347
fileData.reserveBytes(sizeof(Elf32_Ehdr));
16348
16349
for (size_t i = 0; i < 4; i++)
16350
{
16351
switch (partsOrder[i])
16352
{
16353
case ELFPART_SEGMENTTABLE:
16354
fileData.alignSize(4);
16355
fileHeader.e_phoff = (Elf32_Off) fileData.size();
16356
fileData.reserveBytes(segments.size()*fileHeader.e_phentsize);
16357
break;
16358
case ELFPART_SECTIONTABLE:
16359
fileData.alignSize(4);
16360
fileHeader.e_shoff = (Elf32_Off) fileData.size();
16361
fileData.reserveBytes(sections.size()*fileHeader.e_shentsize);
16362
break;
16363
case ELFPART_SEGMENTS:
16364
for (size_t i = 0; i < segments.size(); i++)
16365
{
16366
segments[i]->writeData(fileData);
16367
}
16368
break;
16369
case ELFPART_SEGMENTLESSSECTIONS:
16370
for (size_t i = 0; i < segmentlessSections.size(); i++)
16371
{
16372
segmentlessSections[i]->writeData(fileData);
16373
}
16374
break;
16375
}
16376
}
16377
16378
// copy data to the tables
16379
Endianness endianness = getEndianness();
16380
writeHeader(fileData, 0, endianness);
16381
for (size_t i = 0; i < segments.size(); i++)
16382
{
16383
int pos = fileHeader.e_phoff+i*fileHeader.e_phentsize;
16384
segments[i]->writeHeader(fileData, pos, endianness);
16385
}
16386
16387
for (size_t i = 0; i < sections.size(); i++)
16388
{
16389
int pos = fileHeader.e_shoff+i*fileHeader.e_shentsize;
16390
sections[i]->writeHeader(fileData, pos, endianness);
16391
}
16392
16393
fileData.toFile(fileName);
16394
}
16395
16396
int ElfFile::getSymbolCount()
16397
{
16398
if (symTab == nullptr)
16399
return 0;
16400
16401
return symTab->getSize()/sizeof(Elf32_Sym);
16402
}
16403
16404
bool ElfFile::getSymbol(Elf32_Sym& symbol, size_t index)
16405
{
16406
if (symTab == nullptr)
16407
return false;
16408
16409
ByteArray &data = symTab->getData();
16410
int pos = index*sizeof(Elf32_Sym);
16411
Endianness endianness = getEndianness();
16412
symbol.st_name = data.getDoubleWord(pos + 0x00, endianness);
16413
symbol.st_value = data.getDoubleWord(pos + 0x04, endianness);
16414
symbol.st_size = data.getDoubleWord(pos + 0x08, endianness);
16415
symbol.st_info = data[pos + 0x0C];
16416
symbol.st_other = data[pos + 0x0D];
16417
symbol.st_shndx = data.getWord(pos + 0x0E, endianness);
16418
16419
return true;
16420
}
16421
16422
const char* ElfFile::getStrTableString(size_t pos)
16423
{
16424
if (strTab == nullptr)
16425
return nullptr;
16426
16427
return (const char*) &strTab->getData()[pos];
16428
}
16429
16430
// file: Core/ELF/ElfRelocator.cpp
16431
16432
struct ArFileHeader
16433
{
16434
char fileName[16];
16435
char modifactionTime[12];
16436
char ownerId[6];
16437
char groupId[6];
16438
char fileMode[8];
16439
char fileSize[10];
16440
char magic[2];
16441
};
16442
16443
struct ArFileEntry
16444
{
16445
std::wstring name;
16446
ByteArray data;
16447
};
16448
16449
std::vector<ArFileEntry> loadArArchive(const std::wstring& inputName)
16450
{
16451
ByteArray input = ByteArray::fromFile(inputName);
16452
std::vector<ArFileEntry> result;
16453
16454
if (input.size() < 8 || memcmp(input.data(),"!<arch>\n",8) != 0)
16455
{
16456
if (input.size() < 4 || memcmp(input.data(),"\x7F""ELF",4) != 0)
16457
return result;
16458
16459
ArFileEntry entry;
16460
entry.name = getFileNameFromPath(inputName);
16461
entry.data = input;
16462
result.push_back(entry);
16463
return result;
16464
}
16465
16466
size_t pos = 8;
16467
while (pos < input.size())
16468
{
16469
ArFileHeader* header = (ArFileHeader*) input.data(pos);
16470
pos += sizeof(ArFileHeader);
16471
16472
// get file size
16473
int size = 0;
16474
for (int i = 0; i < 10; i++)
16475
{
16476
if (header->fileSize[i] == ' ')
16477
break;
16478
16479
size = size*10;
16480
size += (header->fileSize[i]-'0');
16481
}
16482
16483
// only ELF files are actually interesting
16484
if (memcmp(input.data(pos),"\x7F""ELF",4) == 0)
16485
{
16486
// get file name
16487
char fileName[17];
16488
fileName[16] = 0;
16489
for (int i = 0; i < 16; i++)
16490
{
16491
if (header->fileName[i] == ' ')
16492
{
16493
// remove trailing slashes of file names
16494
if (i > 0 && fileName[i-1] == '/')
16495
i--;
16496
fileName[i] = 0;
16497
break;;
16498
}
16499
16500
fileName[i] = header->fileName[i];
16501
}
16502
16503
ArFileEntry entry;
16504
entry.name = convertUtf8ToWString(fileName);
16505
entry.data = input.mid(pos,size);
16506
result.push_back(entry);
16507
}
16508
16509
pos += size;
16510
if (pos % 2)
16511
pos++;
16512
}
16513
16514
return result;
16515
}
16516
16517
bool ElfRelocator::init(const std::wstring& inputName)
16518
{
16519
relocator = Arch->getElfRelocator();
16520
if (relocator == nullptr)
16521
{
16522
Logger::printError(Logger::Error,L"Object importing not supported for this architecture");
16523
return false;
16524
}
16525
16526
auto inputFiles = loadArArchive(inputName);
16527
if (inputFiles.size() == 0)
16528
{
16529
Logger::printError(Logger::Error,L"Could not load library");
16530
return false;
16531
}
16532
16533
for (ArFileEntry& entry: inputFiles)
16534
{
16535
ElfRelocatorFile file;
16536
16537
ElfFile* elf = new ElfFile();
16538
if (elf->load(entry.data,false) == false)
16539
{
16540
Logger::printError(Logger::Error,L"Could not load object file %s",entry.name);
16541
return false;
16542
}
16543
16544
if (elf->getType() != ET_REL)
16545
{
16546
Logger::printError(Logger::Error,L"Unexpected ELF type %d in object file %s",elf->getType(),entry.name);
16547
return false;
16548
}
16549
16550
if (elf->getMachine() != relocator->expectedMachine())
16551
{
16552
Logger::printError(Logger::Error,L"Unexpected ELF machine %d in object file %s",elf->getMachine(),entry.name);
16553
return false;
16554
}
16555
16556
if (elf->getEndianness() != Arch->getEndianness())
16557
{
16558
Logger::printError(Logger::Error,L"Incorrect endianness in object file %s",entry.name);
16559
return false;
16560
}
16561
16562
if (elf->getSegmentCount() != 0)
16563
{
16564
Logger::printError(Logger::Error,L"Unexpected segment count %d in object file %s",elf->getSegmentCount(),entry.name);
16565
return false;
16566
}
16567
16568
16569
// load all relevant sections of this file
16570
for (size_t s = 0; s < elf->getSegmentlessSectionCount(); s++)
16571
{
16572
ElfSection* sec = elf->getSegmentlessSection(s);
16573
if (!(sec->getFlags() & SHF_ALLOC))
16574
continue;
16575
16576
if (sec->getType() == SHT_PROGBITS || sec->getType() == SHT_NOBITS || sec->getType() == SHT_INIT_ARRAY)
16577
{
16578
ElfRelocatorSection sectionEntry;
16579
sectionEntry.section = sec;
16580
sectionEntry.index = s;
16581
sectionEntry.relSection = nullptr;
16582
sectionEntry.label = nullptr;
16583
16584
// search relocation section
16585
for (size_t k = 0; k < elf->getSegmentlessSectionCount(); k++)
16586
{
16587
ElfSection* relSection = elf->getSegmentlessSection(k);
16588
if (relSection->getType() != SHT_REL)
16589
continue;
16590
if (relSection->getInfo() != s)
16591
continue;
16592
16593
// got it
16594
sectionEntry.relSection = relSection;
16595
break;
16596
}
16597
16598
// keep track of constructor sections
16599
if (sec->getName() == ".ctors" || sec->getName() == ".init_array")
16600
{
16601
ElfRelocatorCtor ctor;
16602
ctor.symbolName = Global.symbolTable.getUniqueLabelName();
16603
ctor.size = sec->getSize();
16604
16605
sectionEntry.label = Global.symbolTable.getLabel(ctor.symbolName,-1,-1);
16606
sectionEntry.label->setDefined(true);
16607
16608
ctors.push_back(ctor);
16609
}
16610
16611
file.sections.push_back(sectionEntry);
16612
}
16613
}
16614
16615
// init exportable symbols
16616
for (int i = 0; i < elf->getSymbolCount(); i++)
16617
{
16618
Elf32_Sym symbol;
16619
elf->getSymbol(symbol, i);
16620
16621
if (ELF32_ST_BIND(symbol.st_info) == STB_GLOBAL && symbol.st_shndx != 0)
16622
{
16623
ElfRelocatorSymbol symEntry;
16624
symEntry.type = ELF32_ST_TYPE(symbol.st_info);
16625
symEntry.name = convertUtf8ToWString(elf->getStrTableString(symbol.st_name));
16626
symEntry.relativeAddress = symbol.st_value;
16627
symEntry.section = symbol.st_shndx;
16628
symEntry.size = symbol.st_size;
16629
symEntry.label = nullptr;
16630
16631
file.symbols.push_back(symEntry);
16632
}
16633
}
16634
16635
file.elf = elf;
16636
file.name = entry.name;
16637
files.push_back(file);
16638
}
16639
16640
return true;
16641
}
16642
16643
bool ElfRelocator::exportSymbols()
16644
{
16645
bool error = false;
16646
16647
for (ElfRelocatorFile& file: files)
16648
{
16649
for (ElfRelocatorSymbol& sym: file.symbols)
16650
{
16651
if (sym.label != nullptr)
16652
continue;
16653
16654
std::wstring lowered = sym.name;
16655
std::transform(lowered.begin(), lowered.end(), lowered.begin(), ::towlower);
16656
16657
sym.label = Global.symbolTable.getLabel(lowered,-1,-1);
16658
if (sym.label == nullptr)
16659
{
16660
Logger::printError(Logger::Error,L"Invalid label name \"%s\"",sym.name);
16661
error = true;
16662
continue;
16663
}
16664
16665
if (sym.label->isDefined())
16666
{
16667
Logger::printError(Logger::Error,L"Label \"%s\" already defined",sym.name);
16668
error = true;
16669
continue;
16670
}
16671
16672
RelocationData data;
16673
data.symbolAddress = sym.relativeAddress;
16674
relocator->setSymbolAddress(data,sym.relativeAddress,sym.type);
16675
16676
sym.relativeAddress = data.symbolAddress;
16677
sym.label->setInfo(data.targetSymbolInfo);
16678
sym.label->setIsData(sym.type == STT_OBJECT);
16679
sym.label->setUpdateInfo(false);
16680
16681
sym.label->setValue(0);
16682
sym.label->setDefined(true);
16683
sym.label->setOriginalName(sym.name);
16684
}
16685
}
16686
16687
return !error;
16688
}
16689
16690
std::unique_ptr<CAssemblerCommand> ElfRelocator::generateCtor(const std::wstring& ctorName)
16691
{
16692
std::unique_ptr<CAssemblerCommand> content = relocator->generateCtorStub(ctors);
16693
16694
auto func = ::make_unique<CDirectiveFunction>(ctorName,ctorName);
16695
func->setContent(std::move(content));
16696
return func;
16697
}
16698
16699
void ElfRelocator::loadRelocation(Elf32_Rel& rel, ByteArray& data, int offset, Endianness endianness)
16700
{
16701
rel.r_offset = data.getDoubleWord(offset + 0x00, endianness);
16702
rel.r_info = data.getDoubleWord(offset + 0x04, endianness);
16703
}
16704
16705
bool ElfRelocator::relocateFile(ElfRelocatorFile& file, int64_t& relocationAddress)
16706
{
16707
ElfFile* elf = file.elf;
16708
int64_t start = relocationAddress;
16709
16710
// calculate address for each section
16711
std::map<int64_t,int64_t> relocationOffsets;
16712
for (ElfRelocatorSection& entry: file.sections)
16713
{
16714
ElfSection* section = entry.section;
16715
size_t index = entry.index;
16716
int size = section->getSize();
16717
16718
while (relocationAddress % section->getAlignment())
16719
relocationAddress++;
16720
16721
if (entry.label != nullptr)
16722
entry.label->setValue(relocationAddress);
16723
16724
relocationOffsets[index] = relocationAddress;
16725
relocationAddress += size;
16726
}
16727
16728
size_t dataStart = outputData.size();
16729
outputData.reserveBytes((size_t)(relocationAddress-start));
16730
16731
// load sections
16732
bool error = false;
16733
for (ElfRelocatorSection& entry: file.sections)
16734
{
16735
ElfSection* section = entry.section;
16736
size_t index = entry.index;
16737
16738
if (section->getType() == SHT_NOBITS)
16739
{
16740
// reserveBytes initialized the data to 0 already
16741
continue;
16742
}
16743
16744
ByteArray sectionData = section->getData();
16745
16746
// relocate if necessary
16747
ElfSection* relSection = entry.relSection;
16748
if (relSection != nullptr)
16749
{
16750
std::vector<RelocationAction> relocationActions;
16751
for (unsigned int relOffset = 0; relOffset < relSection->getSize(); relOffset += sizeof(Elf32_Rel))
16752
{
16753
Elf32_Rel rel;
16754
loadRelocation(rel, relSection->getData(), relOffset, elf->getEndianness());
16755
int pos = rel.r_offset;
16756
16757
if (relocator->isDummyRelocationType(rel.getType()))
16758
continue;
16759
16760
int symNum = rel.getSymbolNum();
16761
if (symNum <= 0)
16762
{
16763
Logger::queueError(Logger::Warning,L"Invalid symbol num %06X",symNum);
16764
error = true;
16765
continue;
16766
}
16767
16768
Elf32_Sym sym;
16769
elf->getSymbol(sym, symNum);
16770
int symSection = sym.st_shndx;
16771
16772
RelocationData relData;
16773
relData.opcode = sectionData.getDoubleWord(pos, elf->getEndianness());
16774
relData.opcodeOffset = pos+relocationOffsets[index];
16775
relocator->setSymbolAddress(relData,sym.st_value,sym.st_info & 0xF);
16776
16777
// externs?
16778
if (sym.st_shndx == 0)
16779
{
16780
if (sym.st_name == 0)
16781
{
16782
Logger::queueError(Logger::Error, L"Symbol without a name");
16783
error = true;
16784
continue;
16785
}
16786
16787
std::wstring symName = toWLowercase(elf->getStrTableString(sym.st_name));
16788
16789
std::shared_ptr<Label> label = Global.symbolTable.getLabel(symName,-1,-1);
16790
if (label == nullptr)
16791
{
16792
Logger::queueError(Logger::Error,L"Invalid external symbol %s",symName);
16793
error = true;
16794
continue;
16795
}
16796
if (label->isDefined() == false)
16797
{
16798
Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",symName,file.name);
16799
error = true;
16800
continue;
16801
}
16802
16803
relData.relocationBase = (unsigned int) label->getValue();
16804
relData.targetSymbolType = label->isData() ? STT_OBJECT : STT_FUNC;
16805
relData.targetSymbolInfo = label->getInfo();
16806
} else {
16807
relData.relocationBase = relocationOffsets[symSection]+relData.symbolAddress;
16808
}
16809
16810
std::vector<std::wstring> errors;
16811
if (!relocator->relocateOpcode(rel.getType(),relData, relocationActions, errors))
16812
{
16813
for (const std::wstring& error : errors)
16814
{
16815
Logger::queueError(Logger::Error, error);
16816
}
16817
error = true;
16818
continue;
16819
}
16820
}
16821
16822
// finish any dangling relocations
16823
std::vector<std::wstring> errors;
16824
if (!relocator->finish(relocationActions, errors))
16825
{
16826
for (const std::wstring& error : errors)
16827
{
16828
Logger::queueError(Logger::Error, error);
16829
}
16830
error = true;
16831
}
16832
16833
// now actually write the relocated values
16834
for (const RelocationAction& action : relocationActions)
16835
{
16836
sectionData.replaceDoubleWord(action.offset-relocationOffsets[index], action.newValue, elf->getEndianness());
16837
}
16838
}
16839
16840
size_t arrayStart = (size_t) (dataStart+relocationOffsets[index]-start);
16841
memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size());
16842
}
16843
16844
// now update symbols
16845
for (ElfRelocatorSymbol& sym: file.symbols)
16846
{
16847
int64_t oldAddress = sym.relocatedAddress;
16848
16849
switch (sym.section)
16850
{
16851
case SHN_ABS: // address does not change
16852
sym.relocatedAddress = sym.relativeAddress;
16853
break;
16854
case SHN_COMMON: // needs to be allocated. relativeAddress gives alignment constraint
16855
{
16856
int64_t start = relocationAddress;
16857
16858
while (relocationAddress % sym.relativeAddress)
16859
relocationAddress++;
16860
16861
sym.relocatedAddress = relocationAddress;
16862
relocationAddress += sym.size;
16863
outputData.reserveBytes((size_t)(relocationAddress-start));
16864
}
16865
break;
16866
default: // normal relocated symbol
16867
sym.relocatedAddress = sym.relativeAddress+relocationOffsets[sym.section];
16868
break;
16869
}
16870
16871
if (sym.label != nullptr)
16872
sym.label->setValue(sym.relocatedAddress);
16873
16874
if (oldAddress != sym.relocatedAddress)
16875
dataChanged = true;
16876
}
16877
16878
return !error;
16879
}
16880
16881
bool ElfRelocator::relocate(int64_t& memoryAddress)
16882
{
16883
int oldCrc = getCrc32(outputData.data(),outputData.size());
16884
outputData.clear();
16885
dataChanged = false;
16886
16887
bool error = false;
16888
int64_t start = memoryAddress;
16889
16890
for (ElfRelocatorFile& file: files)
16891
{
16892
if (relocateFile(file,memoryAddress) == false)
16893
error = true;
16894
}
16895
16896
int newCrc = getCrc32(outputData.data(),outputData.size());
16897
if (oldCrc != newCrc)
16898
dataChanged = true;
16899
16900
memoryAddress -= start;
16901
return !error;
16902
}
16903
16904
void ElfRelocator::writeSymbols(SymbolData& symData) const
16905
{
16906
for (const ElfRelocatorFile& file: files)
16907
{
16908
for (const ElfRelocatorSymbol& sym: file.symbols)
16909
{
16910
symData.addLabel(sym.relocatedAddress,sym.name);
16911
16912
switch (sym.type)
16913
{
16914
case STT_OBJECT:
16915
symData.addData(sym.relocatedAddress,sym.size,SymbolData::Data8);
16916
break;
16917
case STT_FUNC:
16918
symData.startFunction(sym.relocatedAddress);
16919
symData.endFunction(sym.relocatedAddress+sym.size);
16920
break;
16921
}
16922
}
16923
}
16924
}
16925
16926
// file: Core/Assembler.cpp
16927
#include <thread>
16928
16929
void AddFileName(const std::wstring& FileName)
16930
{
16931
Global.FileInfo.FileNum = (int) Global.FileInfo.FileList.size();
16932
Global.FileInfo.FileList.push_back(FileName);
16933
Global.FileInfo.LineNumber = 0;
16934
}
16935
16936
bool encodeAssembly(std::unique_ptr<CAssemblerCommand> content, SymbolData& symData, TempData& tempData)
16937
{
16938
bool Revalidate;
16939
16940
#ifdef ARMIPS_ARM
16941
Arm.Pass2();
16942
#endif
16943
Mips.Pass2();
16944
16945
int validationPasses = 0;
16946
do // loop until everything is constant
16947
{
16948
Global.validationPasses = validationPasses;
16949
Logger::clearQueue();
16950
Revalidate = false;
16951
16952
if (validationPasses >= 100)
16953
{
16954
Logger::queueError(Logger::Error,L"Stuck in infinite validation loop");
16955
break;
16956
}
16957
16958
g_fileManager->reset();
16959
16960
#ifdef _DEBUG
16961
if (!Logger::isSilent())
16962
printf("Validate %d...\n",validationPasses);
16963
#endif
16964
16965
if (Global.memoryMode)
16966
g_fileManager->openFile(Global.memoryFile,true);
16967
16968
Revalidate = content->Validate();
16969
16970
#ifdef ARMIPS_ARM
16971
Arm.Revalidate();
16972
#endif
16973
Mips.Revalidate();
16974
16975
if (Global.memoryMode)
16976
g_fileManager->closeFile();
16977
16978
validationPasses++;
16979
} while (Revalidate == true);
16980
16981
Logger::printQueue();
16982
if (Logger::hasError() == true)
16983
{
16984
return false;
16985
}
16986
16987
#ifdef _DEBUG
16988
if (!Logger::isSilent())
16989
printf("Encode...\n");
16990
#endif
16991
16992
// and finally encode
16993
if (Global.memoryMode)
16994
g_fileManager->openFile(Global.memoryFile,false);
16995
16996
auto writeTempData = [&]()
16997
{
16998
tempData.start();
16999
if (tempData.isOpen())
17000
content->writeTempData(tempData);
17001
tempData.end();
17002
};
17003
17004
auto writeSymData = [&]()
17005
{
17006
content->writeSymData(symData);
17007
symData.write();
17008
};
17009
17010
// writeTempData, writeSymData and encode all access the same
17011
// memory but never change, so they can run in parallel
17012
if (Global.multiThreading)
17013
{
17014
std::thread tempThread(writeTempData);
17015
std::thread symThread(writeSymData);
17016
17017
content->Encode();
17018
17019
tempThread.join();
17020
symThread.join();
17021
} else {
17022
writeTempData();
17023
writeSymData();
17024
content->Encode();
17025
}
17026
17027
if (g_fileManager->hasOpenFile())
17028
{
17029
if (!Global.memoryMode)
17030
Logger::printError(Logger::Warning,L"File not closed");
17031
g_fileManager->closeFile();
17032
}
17033
17034
return true;
17035
}
17036
17037
bool runArmips(ArmipsArguments& settings)
17038
{
17039
// initialize and reset global data
17040
Global.Section = 0;
17041
Global.nocash = false;
17042
Global.FileInfo.FileCount = 0;
17043
Global.FileInfo.TotalLineCount = 0;
17044
Global.relativeInclude = false;
17045
Global.validationPasses = 0;
17046
Global.multiThreading = true;
17047
Arch = &InvalidArchitecture;
17048
17049
Tokenizer::clearEquValues();
17050
Logger::clear();
17051
Global.Table.clear();
17052
Global.symbolTable.clear();
17053
17054
Global.FileInfo.FileList.clear();
17055
Global.FileInfo.FileCount = 0;
17056
Global.FileInfo.TotalLineCount = 0;
17057
Global.FileInfo.LineNumber = 0;
17058
Global.FileInfo.FileNum = 0;
17059
17060
#ifdef ARMIPS_ARM
17061
Arm.clear();
17062
#endif
17063
17064
// process settings
17065
Parser parser;
17066
SymbolData symData;
17067
TempData tempData;
17068
17069
Logger::setSilent(settings.silent);
17070
Logger::setErrorOnWarning(settings.errorOnWarning);
17071
17072
if (!settings.symFileName.empty())
17073
symData.setNocashSymFileName(settings.symFileName, settings.symFileVersion);
17074
17075
if (!settings.tempFileName.empty())
17076
tempData.setFileName(settings.tempFileName);
17077
17078
Token token;
17079
for (size_t i = 0; i < settings.equList.size(); i++)
17080
{
17081
parser.addEquation(token, settings.equList[i].name, settings.equList[i].value);
17082
}
17083
17084
Global.symbolTable.addLabels(settings.labels);
17085
for (const LabelDefinition& label : settings.labels)
17086
{
17087
symData.addLabel(label.value, label.originalName);
17088
}
17089
17090
if (Logger::hasError())
17091
return false;
17092
17093
// run assembler
17094
TextFile input;
17095
switch (settings.mode)
17096
{
17097
case ArmipsMode::FILE:
17098
Global.memoryMode = false;
17099
if (input.open(settings.inputFileName,TextFile::Read) == false)
17100
{
17101
Logger::printError(Logger::Error,L"Could not open file");
17102
return false;
17103
}
17104
break;
17105
case ArmipsMode::MEMORY:
17106
Global.memoryMode = true;
17107
Global.memoryFile = settings.memoryFile;
17108
input.openMemory(settings.content);
17109
break;
17110
}
17111
17112
std::unique_ptr<CAssemblerCommand> content = parser.parseFile(input);
17113
Logger::printQueue();
17114
17115
bool result = !Logger::hasError();
17116
if (result == true && content != nullptr)
17117
result = encodeAssembly(std::move(content), symData, tempData);
17118
17119
if (g_fileManager->hasOpenFile())
17120
{
17121
if (!Global.memoryMode)
17122
Logger::printError(Logger::Warning,L"File not closed");
17123
g_fileManager->closeFile();
17124
}
17125
17126
// return errors
17127
if (settings.errorsResult != nullptr)
17128
{
17129
StringList errors = Logger::getErrors();
17130
for (size_t i = 0; i < errors.size(); i++)
17131
settings.errorsResult->push_back(errors[i]);
17132
}
17133
17134
return result;
17135
}
17136
17137
// file: Core/Common.cpp
17138
#include <sys/stat.h>
17139
17140
FileManager fileManager;
17141
FileManager* g_fileManager = &fileManager;
17142
17143
tGlobal Global;
17144
CArchitecture* Arch;
17145
17146
std::wstring getFolderNameFromPath(const std::wstring& src)
17147
{
17148
#ifdef _WIN32
17149
size_t s = src.find_last_of(L"\\/");
17150
#else
17151
size_t s = src.rfind(L"/");
17152
#endif
17153
if (s == std::wstring::npos)
17154
{
17155
return L".";
17156
}
17157
17158
return src.substr(0,s);
17159
}
17160
17161
std::wstring getFullPathName(const std::wstring& path)
17162
{
17163
if (Global.relativeInclude == true)
17164
{
17165
if (isAbsolutePath(path))
17166
{
17167
return path;
17168
} else {
17169
std::wstring source = Global.FileInfo.FileList[Global.FileInfo.FileNum];
17170
return getFolderNameFromPath(source) + L"/" + path;
17171
}
17172
} else {
17173
return path;
17174
}
17175
}
17176
17177
bool checkLabelDefined(const std::wstring& labelName, int section)
17178
{
17179
std::shared_ptr<Label> label = Global.symbolTable.getLabel(labelName,Global.FileInfo.FileNum,section);
17180
return label->isDefined();
17181
}
17182
17183
bool checkValidLabelName(const std::wstring& labelName)
17184
{
17185
return Global.symbolTable.isValidSymbolName(labelName);
17186
}
17187
17188
bool isPowerOfTwo(int64_t n)
17189
{
17190
if (n == 0) return false;
17191
return !(n & (n - 1));
17192
}
17193
17194
// file: Core/Expression.cpp
17195
17196
enum class ExpressionValueCombination
17197
{
17198
II = (int(ExpressionValueType::Integer) << 2) | (int(ExpressionValueType::Integer) << 0),
17199
IF = (int(ExpressionValueType::Integer) << 2) | (int(ExpressionValueType::Float) << 0),
17200
FI = (int(ExpressionValueType::Float) << 2) | (int(ExpressionValueType::Integer) << 0),
17201
FF = (int(ExpressionValueType::Float) << 2) | (int(ExpressionValueType::Float) << 0),
17202
IS = (int(ExpressionValueType::Integer) << 2) | (int(ExpressionValueType::String) << 0),
17203
FS = (int(ExpressionValueType::Float) << 2) | (int(ExpressionValueType::String) << 0),
17204
SI = (int(ExpressionValueType::String) << 2) | (int(ExpressionValueType::Integer) << 0),
17205
SF = (int(ExpressionValueType::String) << 2) | (int(ExpressionValueType::Float) << 0),
17206
SS = (int(ExpressionValueType::String) << 2) | (int(ExpressionValueType::String) << 0),
17207
};
17208
17209
ExpressionValueCombination getValueCombination(ExpressionValueType a, ExpressionValueType b)
17210
{
17211
return (ExpressionValueCombination) ((int(a) << 2) | (int(b) << 0));
17212
}
17213
17214
ExpressionValue ExpressionValue::operator+(const ExpressionValue& other) const
17215
{
17216
ExpressionValue result;
17217
switch (getValueCombination(type,other.type))
17218
{
17219
case ExpressionValueCombination::II:
17220
result.type = ExpressionValueType::Integer;
17221
result.intValue = intValue + other.intValue;
17222
break;
17223
case ExpressionValueCombination::FI:
17224
result.type = ExpressionValueType::Float;
17225
result.floatValue = floatValue + other.intValue;
17226
break;
17227
case ExpressionValueCombination::IF:
17228
result.type = ExpressionValueType::Float;
17229
result.floatValue = intValue + other.floatValue;
17230
break;
17231
case ExpressionValueCombination::FF:
17232
result.type = ExpressionValueType::Float;
17233
result.floatValue = floatValue + other.floatValue;
17234
break;
17235
case ExpressionValueCombination::IS:
17236
result.type = ExpressionValueType::String;
17237
result.strValue = to_wstring(intValue) + other.strValue;
17238
break;
17239
case ExpressionValueCombination::FS:
17240
result.type = ExpressionValueType::String;
17241
result.strValue = to_wstring(floatValue) + other.strValue;
17242
break;
17243
case ExpressionValueCombination::SI:
17244
result.type = ExpressionValueType::String;
17245
result.strValue = strValue + to_wstring(other.intValue);
17246
break;
17247
case ExpressionValueCombination::SF:
17248
result.type = ExpressionValueType::String;
17249
result.strValue = strValue + to_wstring(other.floatValue);
17250
break;
17251
case ExpressionValueCombination::SS:
17252
result.type = ExpressionValueType::String;
17253
result.strValue = strValue + other.strValue;
17254
break;
17255
}
17256
17257
return result;
17258
}
17259
17260
ExpressionValue ExpressionValue::operator-(const ExpressionValue& other) const
17261
{
17262
ExpressionValue result;
17263
switch (getValueCombination(type,other.type))
17264
{
17265
case ExpressionValueCombination::II:
17266
result.type = ExpressionValueType::Integer;
17267
result.intValue = intValue - other.intValue;
17268
break;
17269
case ExpressionValueCombination::FI:
17270
result.type = ExpressionValueType::Float;
17271
result.floatValue = floatValue - other.intValue;
17272
break;
17273
case ExpressionValueCombination::IF:
17274
result.type = ExpressionValueType::Float;
17275
result.floatValue = intValue - other.floatValue;
17276
break;
17277
case ExpressionValueCombination::FF:
17278
result.type = ExpressionValueType::Float;
17279
result.floatValue = floatValue - other.floatValue;
17280
break;
17281
default:
17282
break;
17283
}
17284
17285
return result;
17286
}
17287
17288
ExpressionValue ExpressionValue::operator*(const ExpressionValue& other) const
17289
{
17290
ExpressionValue result;
17291
switch (getValueCombination(type,other.type))
17292
{
17293
case ExpressionValueCombination::II:
17294
result.type = ExpressionValueType::Integer;
17295
result.intValue = intValue * other.intValue;
17296
break;
17297
case ExpressionValueCombination::FI:
17298
result.type = ExpressionValueType::Float;
17299
result.floatValue = floatValue * other.intValue;
17300
break;
17301
case ExpressionValueCombination::IF:
17302
result.type = ExpressionValueType::Float;
17303
result.floatValue = intValue * other.floatValue;
17304
break;
17305
case ExpressionValueCombination::FF:
17306
result.type = ExpressionValueType::Float;
17307
result.floatValue = floatValue * other.floatValue;
17308
break;
17309
default:
17310
break;
17311
}
17312
17313
return result;
17314
}
17315
17316
ExpressionValue ExpressionValue::operator/(const ExpressionValue& other) const
17317
{
17318
ExpressionValue result;
17319
switch (getValueCombination(type,other.type))
17320
{
17321
case ExpressionValueCombination::II:
17322
result.type = ExpressionValueType::Integer;
17323
if (intValue == INT64_MIN && other.intValue == -1){
17324
result.intValue = INT64_MIN;
17325
Logger::queueError(Logger::Warning,L"Division overflow in expression");
17326
return result;
17327
}
17328
if (other.intValue == 0)
17329
{
17330
result.intValue = ~0;
17331
Logger::queueError(Logger::Warning,L"Integer division by zero in expression");
17332
return result;
17333
}
17334
result.intValue = intValue / other.intValue;
17335
break;
17336
case ExpressionValueCombination::FI:
17337
result.type = ExpressionValueType::Float;
17338
result.floatValue = floatValue / other.intValue;
17339
break;
17340
case ExpressionValueCombination::IF:
17341
result.type = ExpressionValueType::Float;
17342
result.floatValue = intValue / other.floatValue;
17343
break;
17344
case ExpressionValueCombination::FF:
17345
result.type = ExpressionValueType::Float;
17346
result.floatValue = floatValue / other.floatValue;
17347
break;
17348
default:
17349
break;
17350
}
17351
17352
return result;
17353
}
17354
17355
ExpressionValue ExpressionValue::operator%(const ExpressionValue& other) const
17356
{
17357
ExpressionValue result;
17358
switch (getValueCombination(type,other.type))
17359
{
17360
case ExpressionValueCombination::II:
17361
result.type = ExpressionValueType::Integer;
17362
if (intValue == INT64_MIN && other.intValue == -1){
17363
result.intValue = 0;
17364
Logger::queueError(Logger::Warning,L"Division overflow in expression");
17365
return result;
17366
}
17367
if (other.intValue == 0)
17368
{
17369
result.intValue = intValue;
17370
Logger::queueError(Logger::Warning,L"Integer division by zero in expression");
17371
return result;
17372
}
17373
result.intValue = intValue % other.intValue;
17374
break;
17375
default:
17376
break;
17377
}
17378
17379
return result;
17380
}
17381
17382
ExpressionValue ExpressionValue::operator!() const
17383
{
17384
ExpressionValue result;
17385
result.type = ExpressionValueType::Integer;
17386
17387
if (isFloat())
17388
result.intValue = !floatValue;
17389
else
17390
result.intValue = !intValue;
17391
17392
return result;
17393
}
17394
17395
ExpressionValue ExpressionValue::operator~() const
17396
{
17397
ExpressionValue result;
17398
17399
if (isInt())
17400
{
17401
result.type = ExpressionValueType::Integer;
17402
result.intValue = ~intValue;
17403
}
17404
17405
return result;
17406
}
17407
17408
ExpressionValue ExpressionValue::operator<<(const ExpressionValue& other) const
17409
{
17410
ExpressionValue result;
17411
switch (getValueCombination(type,other.type))
17412
{
17413
case ExpressionValueCombination::II:
17414
result.type = ExpressionValueType::Integer;
17415
result.intValue = ((uint64_t) intValue) << other.intValue;
17416
break;
17417
default:
17418
break;
17419
}
17420
17421
return result;
17422
}
17423
17424
ExpressionValue ExpressionValue::operator>>(const ExpressionValue& other) const
17425
{
17426
ExpressionValue result;
17427
switch (getValueCombination(type,other.type))
17428
{
17429
case ExpressionValueCombination::II:
17430
result.type = ExpressionValueType::Integer;
17431
result.intValue = ((uint64_t) intValue) >> other.intValue;
17432
break;
17433
default:
17434
break;
17435
}
17436
17437
return result;
17438
}
17439
17440
bool ExpressionValue::operator<(const ExpressionValue& other) const
17441
{
17442
switch (getValueCombination(type,other.type))
17443
{
17444
case ExpressionValueCombination::II:
17445
return intValue < other.intValue;
17446
case ExpressionValueCombination::FI:
17447
return floatValue < other.intValue;
17448
case ExpressionValueCombination::IF:
17449
return intValue < other.floatValue;
17450
case ExpressionValueCombination::FF:
17451
return floatValue < other.floatValue;
17452
case ExpressionValueCombination::SS:
17453
return strValue < other.strValue;
17454
default:
17455
break;
17456
}
17457
17458
return false;
17459
}
17460
17461
bool ExpressionValue::operator<=(const ExpressionValue& other) const
17462
{
17463
switch (getValueCombination(type,other.type))
17464
{
17465
case ExpressionValueCombination::II:
17466
return intValue <= other.intValue;
17467
case ExpressionValueCombination::FI:
17468
return floatValue <= other.intValue;
17469
case ExpressionValueCombination::IF:
17470
return intValue <= other.floatValue;
17471
case ExpressionValueCombination::FF:
17472
return floatValue <= other.floatValue;
17473
case ExpressionValueCombination::SS:
17474
return strValue <= other.strValue;
17475
default:
17476
break;
17477
}
17478
17479
return false;
17480
}
17481
17482
bool ExpressionValue::operator>(const ExpressionValue& other) const
17483
{
17484
return other < *this;
17485
}
17486
17487
bool ExpressionValue::operator>=(const ExpressionValue& other) const
17488
{
17489
return other <= *this;
17490
}
17491
17492
bool ExpressionValue::operator==(const ExpressionValue& other) const
17493
{
17494
switch (getValueCombination(type,other.type))
17495
{
17496
case ExpressionValueCombination::II:
17497
return intValue == other.intValue;
17498
case ExpressionValueCombination::FI:
17499
return floatValue == other.intValue;
17500
case ExpressionValueCombination::IF:
17501
return intValue == other.floatValue;
17502
case ExpressionValueCombination::FF:
17503
return floatValue == other.floatValue;
17504
case ExpressionValueCombination::IS:
17505
return to_wstring(intValue) == other.strValue;
17506
case ExpressionValueCombination::FS:
17507
return to_wstring(floatValue) == other.strValue;
17508
case ExpressionValueCombination::SI:
17509
return strValue == to_wstring(other.intValue);
17510
case ExpressionValueCombination::SF:
17511
return strValue == to_wstring(other.floatValue);
17512
case ExpressionValueCombination::SS:
17513
return strValue == other.strValue;
17514
}
17515
17516
return false;
17517
}
17518
17519
bool ExpressionValue::operator!=(const ExpressionValue& other) const
17520
{
17521
return !(*this == other);
17522
}
17523
17524
ExpressionValue ExpressionValue::operator&(const ExpressionValue& other) const
17525
{
17526
ExpressionValue result;
17527
switch (getValueCombination(type,other.type))
17528
{
17529
case ExpressionValueCombination::II:
17530
result.type = ExpressionValueType::Integer;
17531
result.intValue = intValue & other.intValue;
17532
break;
17533
default:
17534
break;
17535
}
17536
17537
return result;
17538
}
17539
17540
ExpressionValue ExpressionValue::operator|(const ExpressionValue& other) const
17541
{
17542
ExpressionValue result;
17543
switch (getValueCombination(type,other.type))
17544
{
17545
case ExpressionValueCombination::II:
17546
result.type = ExpressionValueType::Integer;
17547
result.intValue = intValue | other.intValue;
17548
break;
17549
default:
17550
break;
17551
}
17552
17553
return result;
17554
}
17555
17556
ExpressionValue ExpressionValue::operator^(const ExpressionValue& other) const
17557
{
17558
ExpressionValue result;
17559
switch (getValueCombination(type,other.type))
17560
{
17561
case ExpressionValueCombination::II:
17562
result.type = ExpressionValueType::Integer;
17563
result.intValue = intValue ^ other.intValue;
17564
break;
17565
default:
17566
break;
17567
}
17568
17569
return result;
17570
}
17571
17572
ExpressionValue ExpressionValue::operator&&(const ExpressionValue& other) const
17573
{
17574
ExpressionValue result;
17575
result.type = ExpressionValueType::Integer;
17576
17577
switch (getValueCombination(type,other.type))
17578
{
17579
case ExpressionValueCombination::II:
17580
result.intValue = intValue && other.intValue;
17581
break;
17582
case ExpressionValueCombination::FI:
17583
result.floatValue = floatValue && other.intValue;
17584
break;
17585
case ExpressionValueCombination::IF:
17586
result.floatValue = intValue && other.floatValue;
17587
break;
17588
case ExpressionValueCombination::FF:
17589
result.floatValue = floatValue && other.floatValue;
17590
break;
17591
default:
17592
break;
17593
}
17594
17595
return result;
17596
}
17597
17598
ExpressionValue ExpressionValue::operator||(const ExpressionValue& other) const
17599
{
17600
ExpressionValue result;
17601
result.type = ExpressionValueType::Integer;
17602
17603
switch (getValueCombination(type,other.type))
17604
{
17605
case ExpressionValueCombination::II:
17606
result.intValue = intValue || other.intValue;
17607
break;
17608
case ExpressionValueCombination::FI:
17609
result.floatValue = floatValue || other.intValue;
17610
break;
17611
case ExpressionValueCombination::IF:
17612
result.floatValue = intValue || other.floatValue;
17613
break;
17614
case ExpressionValueCombination::FF:
17615
result.floatValue = floatValue || other.floatValue;
17616
break;
17617
default:
17618
break;
17619
}
17620
17621
return result;
17622
}
17623
17624
ExpressionInternal::ExpressionInternal()
17625
{
17626
children = nullptr;
17627
childrenCount = 0;
17628
}
17629
17630
ExpressionInternal::~ExpressionInternal()
17631
{
17632
deallocate();
17633
}
17634
17635
ExpressionInternal::ExpressionInternal(int64_t value)
17636
: ExpressionInternal()
17637
{
17638
type = OperatorType::Integer;
17639
intValue = value;
17640
}
17641
17642
ExpressionInternal::ExpressionInternal(double value)
17643
: ExpressionInternal()
17644
{
17645
type = OperatorType::Float;
17646
floatValue = value;
17647
}
17648
17649
ExpressionInternal::ExpressionInternal(const std::wstring& value, OperatorType type)
17650
: ExpressionInternal()
17651
{
17652
this->type = type;
17653
strValue = value;
17654
17655
switch (type)
17656
{
17657
case OperatorType::Identifier:
17658
fileNum = Global.FileInfo.FileNum;
17659
section = Global.Section;
17660
break;
17661
case OperatorType::String:
17662
break;
17663
default:
17664
break;
17665
}
17666
}
17667
17668
ExpressionInternal::ExpressionInternal(OperatorType op, ExpressionInternal* a,
17669
ExpressionInternal* b, ExpressionInternal* c)
17670
: ExpressionInternal()
17671
{
17672
type = op;
17673
allocate(3);
17674
17675
children[0] = a;
17676
children[1] = b;
17677
children[2] = c;
17678
}
17679
17680
ExpressionInternal::ExpressionInternal(const std::wstring& name, const std::vector<ExpressionInternal*>& parameters)
17681
: ExpressionInternal()
17682
{
17683
type = OperatorType::FunctionCall;
17684
allocate(parameters.size());
17685
17686
strValue = name;
17687
for (size_t i = 0; i < parameters.size(); i++)
17688
{
17689
children[i] = parameters[i];
17690
}
17691
}
17692
17693
void ExpressionInternal::allocate(size_t count)
17694
{
17695
deallocate();
17696
17697
children = new ExpressionInternal*[count];
17698
childrenCount = count;
17699
}
17700
17701
void ExpressionInternal::deallocate()
17702
{
17703
for (size_t i = 0; i < childrenCount; i++)
17704
{
17705
delete children[i];
17706
}
17707
17708
delete[] children;
17709
children = nullptr;
17710
childrenCount = 0;
17711
}
17712
17713
void ExpressionInternal::replaceMemoryPos(const std::wstring& identifierName)
17714
{
17715
for (size_t i = 0; i < childrenCount; i++)
17716
{
17717
if (children[i] != nullptr)
17718
{
17719
children[i]->replaceMemoryPos(identifierName);
17720
}
17721
}
17722
17723
if (type == OperatorType::MemoryPos)
17724
{
17725
type = OperatorType::Identifier;
17726
strValue = identifierName;
17727
fileNum = Global.FileInfo.FileNum;
17728
section = Global.Section;
17729
}
17730
}
17731
17732
bool ExpressionInternal::checkParameterCount(size_t minParams, size_t maxParams)
17733
{
17734
if (minParams > childrenCount)
17735
{
17736
Logger::queueError(Logger::Error,L"Not enough parameters for \"%s\" (min %d)",strValue,minParams);
17737
return false;
17738
}
17739
17740
if (maxParams < childrenCount)
17741
{
17742
Logger::queueError(Logger::Error,L"Too many parameters for \"%s\" (min %d)",strValue,maxParams);
17743
return false;
17744
}
17745
17746
return true;
17747
}
17748
17749
ExpressionValue ExpressionInternal::executeExpressionFunctionCall(const ExpressionFunctionEntry& entry)
17750
{
17751
// check parameters
17752
if (!checkParameterCount(entry.minParams, entry.maxParams))
17753
return {};
17754
17755
// evaluate parameters
17756
std::vector<ExpressionValue> params;
17757
params.reserve(childrenCount);
17758
17759
for (size_t i = 0; i < childrenCount; i++)
17760
{
17761
ExpressionValue result = children[i]->evaluate();
17762
if (!result.isValid())
17763
{
17764
Logger::queueError(Logger::Error,L"%s: Invalid parameter %d", strValue, i+1);
17765
return result;
17766
}
17767
17768
params.push_back(result);
17769
}
17770
17771
// execute
17772
return entry.function(strValue, params);
17773
}
17774
17775
ExpressionValue ExpressionInternal::executeExpressionLabelFunctionCall(const ExpressionLabelFunctionEntry& entry)
17776
{
17777
// check parameters
17778
if (!checkParameterCount(entry.minParams, entry.maxParams))
17779
return {};
17780
17781
// evaluate parameters
17782
std::vector<std::shared_ptr<Label>> params;
17783
params.reserve(childrenCount);
17784
17785
for (size_t i = 0; i < childrenCount; i++)
17786
{
17787
ExpressionInternal *exp = children[i];
17788
if (!exp || !exp->isIdentifier())
17789
{
17790
Logger::queueError(Logger::Error,L"%s: Invalid parameter %d, expecting identifier", strValue, i+1);
17791
return {};
17792
}
17793
17794
const std::wstring& name = exp->getStringValue();
17795
std::shared_ptr<Label> label = Global.symbolTable.getLabel(name,exp->getFileNum(),exp->getSection());
17796
params.push_back(label);
17797
}
17798
17799
// execute
17800
return entry.function(strValue, params);
17801
}
17802
17803
ExpressionValue ExpressionInternal::executeFunctionCall()
17804
{
17805
// try expression functions
17806
auto expFuncIt = expressionFunctions.find(strValue);
17807
if (expFuncIt != expressionFunctions.end())
17808
return executeExpressionFunctionCall(expFuncIt->second);
17809
17810
// try expression label functions
17811
auto expLabelFuncIt = expressionLabelFunctions.find(strValue);
17812
if (expLabelFuncIt != expressionLabelFunctions.end())
17813
return executeExpressionLabelFunctionCall(expLabelFuncIt->second);
17814
17815
// try architecture specific expression functions
17816
auto& archExpressionFunctions = Arch->getExpressionFunctions();
17817
expFuncIt = archExpressionFunctions.find(strValue);
17818
if (expFuncIt != archExpressionFunctions.end())
17819
return executeExpressionFunctionCall(expFuncIt->second);
17820
17821
// error
17822
Logger::queueError(Logger::Error, L"Unknown function \"%s\"", strValue);
17823
return {};
17824
}
17825
17826
bool isExpressionFunctionSafe(const std::wstring& name, bool inUnknownOrFalseBlock)
17827
{
17828
// expression functions may be unsafe, others are safe
17829
ExpFuncSafety safety = ExpFuncSafety::Unsafe;
17830
bool found = false;
17831
17832
auto it = expressionFunctions.find(name);
17833
if (it != expressionFunctions.end())
17834
{
17835
safety = it->second.safety;
17836
found = true;
17837
}
17838
17839
if (!found)
17840
{
17841
auto labelIt = expressionLabelFunctions.find(name);
17842
if (labelIt != expressionLabelFunctions.end())
17843
{
17844
safety = labelIt->second.safety;
17845
found = true;
17846
}
17847
}
17848
17849
if (!found)
17850
{
17851
auto& archExpressionFunctions = Arch->getExpressionFunctions();
17852
it = archExpressionFunctions.find(name);
17853
if (it != archExpressionFunctions.end())
17854
{
17855
safety = it->second.safety;
17856
found = true;
17857
}
17858
}
17859
17860
if (inUnknownOrFalseBlock && safety == ExpFuncSafety::ConditionalUnsafe)
17861
return false;
17862
17863
return safety != ExpFuncSafety::Unsafe;
17864
}
17865
17866
bool ExpressionInternal::simplify(bool inUnknownOrFalseBlock)
17867
{
17868
// check if this expression can actually be simplified
17869
// without causing side effects
17870
switch (type)
17871
{
17872
case OperatorType::Identifier:
17873
case OperatorType::MemoryPos:
17874
case OperatorType::ToString:
17875
return false;
17876
case OperatorType::FunctionCall:
17877
if (isExpressionFunctionSafe(strValue, inUnknownOrFalseBlock) == false)
17878
return false;
17879
break;
17880
default:
17881
break;
17882
}
17883
17884
// check if the same applies to all children
17885
bool canSimplify = true;
17886
for (size_t i = 0; i < childrenCount; i++)
17887
{
17888
if (children[i] != nullptr && children[i]->simplify(inUnknownOrFalseBlock) == false)
17889
canSimplify = false;
17890
}
17891
17892
// if so, this expression can be evaluated into a constant
17893
if (canSimplify)
17894
{
17895
ExpressionValue value = evaluate();
17896
17897
switch (value.type)
17898
{
17899
case ExpressionValueType::Integer:
17900
type = OperatorType::Integer;
17901
intValue = value.intValue;
17902
break;
17903
case ExpressionValueType::Float:
17904
type = OperatorType::Float;
17905
floatValue = value.floatValue;
17906
break;
17907
case ExpressionValueType::String:
17908
type = OperatorType::String;
17909
strValue = value.strValue;
17910
break;
17911
default:
17912
type = OperatorType::Invalid;
17913
break;
17914
}
17915
17916
deallocate();
17917
}
17918
17919
return canSimplify;
17920
}
17921
17922
ExpressionValue ExpressionInternal::evaluate()
17923
{
17924
ExpressionValue val;
17925
17926
std::shared_ptr<Label> label;
17927
switch (type)
17928
{
17929
case OperatorType::Integer:
17930
val.type = ExpressionValueType::Integer;
17931
val.intValue = intValue;
17932
return val;
17933
case OperatorType::Float:
17934
val.type = ExpressionValueType::Float;
17935
val.floatValue = floatValue;
17936
return val;
17937
case OperatorType::Identifier:
17938
label = Global.symbolTable.getLabel(strValue,fileNum,section);
17939
if (label == nullptr)
17940
{
17941
Logger::queueError(Logger::Error,L"Invalid label name \"%s\"",strValue);
17942
return val;
17943
}
17944
17945
if (!label->isDefined())
17946
{
17947
Logger::queueError(Logger::Error,L"Undefined label \"%s\"",label->getName());
17948
return val;
17949
}
17950
17951
val.type = ExpressionValueType::Integer;
17952
val.intValue = label->getValue();
17953
return val;
17954
case OperatorType::String:
17955
val.type = ExpressionValueType::String;
17956
val.strValue = strValue;
17957
return val;
17958
case OperatorType::MemoryPos:
17959
val.type = ExpressionValueType::Integer;
17960
val.intValue = g_fileManager->getVirtualAddress();
17961
return val;
17962
case OperatorType::ToString:
17963
val.type = ExpressionValueType::String;
17964
val.strValue = children[0]->toString();
17965
return val;
17966
case OperatorType::Add:
17967
return children[0]->evaluate() + children[1]->evaluate();
17968
case OperatorType::Sub:
17969
return children[0]->evaluate() - children[1]->evaluate();
17970
case OperatorType::Mult:
17971
return children[0]->evaluate() * children[1]->evaluate();
17972
case OperatorType::Div:
17973
return children[0]->evaluate() / children[1]->evaluate();
17974
case OperatorType::Mod:
17975
return children[0]->evaluate() % children[1]->evaluate();
17976
case OperatorType::Neg:
17977
val.type = ExpressionValueType::Integer;
17978
val.intValue = 0;
17979
return val - children[0]->evaluate();
17980
case OperatorType::LogNot:
17981
return !children[0]->evaluate();
17982
case OperatorType::BitNot:
17983
return ~children[0]->evaluate();
17984
case OperatorType::LeftShift:
17985
return children[0]->evaluate() << children[1]->evaluate();
17986
case OperatorType::RightShift:
17987
return children[0]->evaluate() >> children[1]->evaluate();
17988
case OperatorType::Less:
17989
val.type = ExpressionValueType::Integer;
17990
val.intValue = children[0]->evaluate() < children[1]->evaluate();
17991
return val;
17992
case OperatorType::Greater:
17993
val.type = ExpressionValueType::Integer;
17994
val.intValue = children[0]->evaluate() > children[1]->evaluate();
17995
return val;
17996
case OperatorType::LessEqual:
17997
val.type = ExpressionValueType::Integer;
17998
val.intValue = children[0]->evaluate() <= children[1]->evaluate();
17999
return val;
18000
case OperatorType::GreaterEqual:
18001
val.type = ExpressionValueType::Integer;
18002
val.intValue = children[0]->evaluate() >= children[1]->evaluate();
18003
return val;
18004
case OperatorType::Equal:
18005
val.type = ExpressionValueType::Integer;
18006
val.intValue = children[0]->evaluate() == children[1]->evaluate();
18007
return val;
18008
case OperatorType::NotEqual:
18009
val.type = ExpressionValueType::Integer;
18010
val.intValue = children[0]->evaluate() != children[1]->evaluate();
18011
return val;
18012
case OperatorType::BitAnd:
18013
return children[0]->evaluate() & children[1]->evaluate();
18014
case OperatorType::BitOr:
18015
return children[0]->evaluate() | children[1]->evaluate();
18016
case OperatorType::LogAnd:
18017
return children[0]->evaluate() && children[1]->evaluate();
18018
case OperatorType::LogOr:
18019
return children[0]->evaluate() || children[1]->evaluate();
18020
case OperatorType::Xor:
18021
return children[0]->evaluate() ^ children[1]->evaluate();
18022
case OperatorType::TertiaryIf:
18023
val.type = ExpressionValueType::Integer;
18024
val.intValue = 0;
18025
if (children[0]->evaluate() == val)
18026
return children[2]->evaluate();
18027
else
18028
return children[1]->evaluate();
18029
case OperatorType::FunctionCall:
18030
return executeFunctionCall();
18031
default:
18032
return val;
18033
}
18034
}
18035
18036
static std::wstring escapeString(const std::wstring& text)
18037
{
18038
std::wstring result = text;
18039
replaceAll(result,LR"(\)",LR"(\\)");
18040
replaceAll(result,LR"(")",LR"(\")");
18041
18042
return formatString(LR"("%s")",text);
18043
}
18044
18045
std::wstring ExpressionInternal::formatFunctionCall()
18046
{
18047
std::wstring text = strValue + L"(";
18048
18049
for (size_t i = 0; i < childrenCount; i++)
18050
{
18051
if (i != 0)
18052
text += L",";
18053
text += children[i]->toString();
18054
}
18055
18056
return text + L")";
18057
}
18058
18059
std::wstring ExpressionInternal::toString()
18060
{
18061
switch (type)
18062
{
18063
case OperatorType::Integer:
18064
return formatString(L"%d",intValue);
18065
case OperatorType::Float:
18066
return formatString(L"%g",floatValue);
18067
case OperatorType::Identifier:
18068
return strValue;
18069
case OperatorType::String:
18070
return escapeString(strValue);
18071
case OperatorType::MemoryPos:
18072
return L".";
18073
case OperatorType::Add:
18074
return formatString(L"(%s + %s)",children[0]->toString(),children[1]->toString());
18075
case OperatorType::Sub:
18076
return formatString(L"(%s - %s)",children[0]->toString(),children[1]->toString());
18077
case OperatorType::Mult:
18078
return formatString(L"(%s * %s)",children[0]->toString(),children[1]->toString());
18079
case OperatorType::Div:
18080
return formatString(L"(%s / %s)",children[0]->toString(),children[1]->toString());
18081
case OperatorType::Mod:
18082
return formatString(L"(%s %% %s)",children[0]->toString(),children[1]->toString());
18083
case OperatorType::Neg:
18084
return formatString(L"(-%s)",children[0]->toString());
18085
case OperatorType::LogNot:
18086
return formatString(L"(!%s)",children[0]->toString());
18087
case OperatorType::BitNot:
18088
return formatString(L"(~%s)",children[0]->toString());
18089
case OperatorType::LeftShift:
18090
return formatString(L"(%s << %s)",children[0]->toString(),children[1]->toString());
18091
case OperatorType::RightShift:
18092
return formatString(L"(%s >> %s)",children[0]->toString(),children[1]->toString());
18093
case OperatorType::Less:
18094
return formatString(L"(%s < %s)",children[0]->toString(),children[1]->toString());
18095
case OperatorType::Greater:
18096
return formatString(L"(%s > %s)",children[0]->toString(),children[1]->toString());
18097
case OperatorType::LessEqual:
18098
return formatString(L"(%s <= %s)",children[0]->toString(),children[1]->toString());
18099
case OperatorType::GreaterEqual:
18100
return formatString(L"(%s >= %s)",children[0]->toString(),children[1]->toString());
18101
case OperatorType::Equal:
18102
return formatString(L"(%s == %s)",children[0]->toString(),children[1]->toString());
18103
case OperatorType::NotEqual:
18104
return formatString(L"(%s != %s)",children[0]->toString(),children[1]->toString());
18105
case OperatorType::BitAnd:
18106
return formatString(L"(%s & %s)",children[0]->toString(),children[1]->toString());
18107
case OperatorType::BitOr:
18108
return formatString(L"(%s | %s)",children[0]->toString(),children[1]->toString());
18109
case OperatorType::LogAnd:
18110
return formatString(L"(%s && %s)",children[0]->toString(),children[1]->toString());
18111
case OperatorType::LogOr:
18112
return formatString(L"(%s || %s)",children[0]->toString(),children[1]->toString());
18113
case OperatorType::Xor:
18114
return formatString(L"(%s ^ %s)",children[0]->toString(),children[1]->toString());
18115
case OperatorType::TertiaryIf:
18116
return formatString(L"(%s ? %s : %s)",children[0]->toString(),children[1]->toString(),children[2]->toString());
18117
case OperatorType::ToString:
18118
return formatString(L"(%c%s)",L'\U000000B0',children[0]->toString());
18119
case OperatorType::FunctionCall:
18120
return formatFunctionCall();
18121
default:
18122
return L"";
18123
}
18124
}
18125
18126
Expression::Expression()
18127
{
18128
expression = nullptr;
18129
constExpression = true;
18130
}
18131
18132
void Expression::setExpression(ExpressionInternal* exp, bool inUnknownOrFalseBlock)
18133
{
18134
expression = std::shared_ptr<ExpressionInternal>(exp);
18135
if (exp != nullptr)
18136
constExpression = expression->simplify(inUnknownOrFalseBlock);
18137
else
18138
constExpression = true;
18139
}
18140
18141
ExpressionValue Expression::evaluate()
18142
{
18143
if (expression == nullptr)
18144
{
18145
ExpressionValue invalid;
18146
return invalid;
18147
}
18148
18149
return expression->evaluate();
18150
}
18151
18152
void Expression::replaceMemoryPos(const std::wstring& identifierName)
18153
{
18154
if (expression != nullptr)
18155
expression->replaceMemoryPos(identifierName);
18156
}
18157
18158
Expression createConstExpression(int64_t value)
18159
{
18160
Expression exp;
18161
ExpressionInternal* num = new ExpressionInternal(value);
18162
exp.setExpression(num,false);
18163
return exp;
18164
}
18165
18166
// file: Core/ExpressionFunctions.cpp
18167
#if ARMIPS_REGEXP
18168
#include <regex>
18169
#endif
18170
18171
bool getExpFuncParameter(const std::vector<ExpressionValue>& parameters, size_t index, int64_t& dest,
18172
const std::wstring& funcName, bool optional)
18173
{
18174
if (optional && index >= parameters.size())
18175
return true;
18176
18177
if (index >= parameters.size() || parameters[index].isInt() == false)
18178
{
18179
Logger::queueError(Logger::Error,L"Invalid parameter %d for %s: expecting integer",index+1,funcName);
18180
return false;
18181
}
18182
18183
dest = parameters[index].intValue;
18184
return true;
18185
}
18186
18187
bool getExpFuncParameter(const std::vector<ExpressionValue>& parameters, size_t index, const std::wstring*& dest,
18188
const std::wstring& funcName, bool optional)
18189
{
18190
if (optional && index >= parameters.size())
18191
return true;
18192
18193
if (index >= parameters.size() || parameters[index].isString() == false)
18194
{
18195
Logger::queueError(Logger::Error,L"Invalid parameter %d for %s: expecting string",index+1,funcName);
18196
return false;
18197
}
18198
18199
dest = &parameters[index].strValue;
18200
return true;
18201
}
18202
18203
#define GET_PARAM(params,index,dest) \
18204
if (getExpFuncParameter(params,index,dest,funcName,false) == false) \
18205
return ExpressionValue();
18206
#define GET_OPTIONAL_PARAM(params,index,dest,defaultValue) \
18207
dest = defaultValue; \
18208
if (getExpFuncParameter(params,index,dest,funcName,true) == false) \
18209
return ExpressionValue();
18210
18211
18212
ExpressionValue expFuncVersion(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18213
{
18214
int64_t value = ARMIPS_VERSION_MAJOR*1000 + ARMIPS_VERSION_MINOR*10 + ARMIPS_VERSION_REVISION;
18215
return ExpressionValue(value);
18216
}
18217
18218
ExpressionValue expFuncEndianness(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18219
{
18220
ExpressionValue result;
18221
result.type = ExpressionValueType::String;
18222
18223
switch (g_fileManager->getEndianness())
18224
{
18225
case Endianness::Little:
18226
return ExpressionValue(L"little");
18227
case Endianness::Big:
18228
return ExpressionValue(L"big");
18229
}
18230
18231
return ExpressionValue();
18232
}
18233
18234
ExpressionValue expFuncOutputName(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18235
{
18236
std::shared_ptr<AssemblerFile> file = g_fileManager->getOpenFile();
18237
if (file == nullptr)
18238
{
18239
Logger::queueError(Logger::Error,L"outputName: no file opened");
18240
return ExpressionValue();
18241
}
18242
18243
std::wstring value = file->getFileName();
18244
return ExpressionValue(value);
18245
}
18246
18247
ExpressionValue expFuncFileExists(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18248
{
18249
const std::wstring* fileName;
18250
GET_PARAM(parameters,0,fileName);
18251
18252
std::wstring fullName = getFullPathName(*fileName);
18253
return ExpressionValue(fileExists(fullName) ? INT64_C(1) : INT64_C(0));
18254
}
18255
18256
ExpressionValue expFuncFileSize(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18257
{
18258
const std::wstring* fileName;
18259
GET_PARAM(parameters,0,fileName);
18260
18261
std::wstring fullName = getFullPathName(*fileName);
18262
return ExpressionValue((int64_t) fileSize(fullName));
18263
}
18264
18265
ExpressionValue expFuncToString(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18266
{
18267
ExpressionValue result;
18268
18269
switch (parameters[0].type)
18270
{
18271
case ExpressionValueType::String:
18272
result.strValue = parameters[0].strValue;
18273
break;
18274
case ExpressionValueType::Integer:
18275
result.strValue = formatString(L"%d",parameters[0].intValue);
18276
break;
18277
case ExpressionValueType::Float:
18278
result.strValue = formatString(L"%#.17g",parameters[0].floatValue);
18279
break;
18280
default:
18281
return result;
18282
}
18283
18284
result.type = ExpressionValueType::String;
18285
return result;
18286
}
18287
18288
ExpressionValue expFuncToHex(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18289
{
18290
int64_t value, digits;
18291
GET_PARAM(parameters,0,value);
18292
GET_OPTIONAL_PARAM(parameters,1,digits,8);
18293
18294
return ExpressionValue(formatString(L"%0*X",digits,value));
18295
}
18296
18297
ExpressionValue expFuncInt(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18298
{
18299
ExpressionValue result;
18300
18301
switch (parameters[0].type)
18302
{
18303
case ExpressionValueType::Integer:
18304
result.intValue = parameters[0].intValue;
18305
break;
18306
case ExpressionValueType::Float:
18307
result.intValue = (int64_t) parameters[0].floatValue;
18308
break;
18309
default:
18310
return result;
18311
}
18312
18313
result.type = ExpressionValueType::Integer;
18314
return result;
18315
}
18316
18317
ExpressionValue expFuncRound(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18318
{
18319
ExpressionValue result;
18320
18321
switch (parameters[0].type)
18322
{
18323
case ExpressionValueType::Integer:
18324
result.intValue = parameters[0].intValue;
18325
break;
18326
case ExpressionValueType::Float:
18327
result.intValue = llround(parameters[0].floatValue);
18328
break;
18329
default:
18330
return result;
18331
}
18332
18333
result.type = ExpressionValueType::Integer;
18334
return result;
18335
}
18336
18337
ExpressionValue expFuncFloat(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18338
{
18339
ExpressionValue result;
18340
18341
switch (parameters[0].type)
18342
{
18343
case ExpressionValueType::Integer:
18344
result.floatValue = (double) parameters[0].intValue;
18345
break;
18346
case ExpressionValueType::Float:
18347
result.floatValue = parameters[0].floatValue;
18348
break;
18349
default:
18350
return result;
18351
}
18352
18353
result.type = ExpressionValueType::Float;
18354
return result;
18355
}
18356
18357
ExpressionValue expFuncFrac(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18358
{
18359
ExpressionValue result;
18360
double intPart;
18361
18362
switch (parameters[0].type)
18363
{
18364
case ExpressionValueType::Float:
18365
result.floatValue = modf(parameters[0].floatValue,&intPart);
18366
break;
18367
default:
18368
return result;
18369
}
18370
18371
result.type = ExpressionValueType::Float;
18372
return result;
18373
}
18374
18375
ExpressionValue expFuncMin(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18376
{
18377
ExpressionValue result;
18378
double floatMin, floatCur;
18379
int64_t intMin, intCur;
18380
18381
floatCur = floatMin = std::numeric_limits<double>::max();
18382
intCur = intMin = std::numeric_limits<int64_t>::max();
18383
bool isInt = true;
18384
18385
for (size_t i = 0; i < parameters.size(); i++)
18386
{
18387
switch (parameters[i].type)
18388
{
18389
case ExpressionValueType::Integer:
18390
intCur = parameters[i].intValue;
18391
floatCur = (double)parameters[i].intValue;
18392
break;
18393
case ExpressionValueType::Float:
18394
floatCur = parameters[i].floatValue;
18395
isInt = false;
18396
break;
18397
default:
18398
return result;
18399
}
18400
18401
if (intCur < intMin)
18402
intMin = intCur;
18403
if (floatCur < floatMin)
18404
floatMin = floatCur;
18405
}
18406
18407
if (isInt)
18408
{
18409
result.intValue = intMin;
18410
result.type = ExpressionValueType::Integer;
18411
}
18412
else
18413
{
18414
result.floatValue = floatMin;
18415
result.type = ExpressionValueType::Float;
18416
}
18417
18418
return result;
18419
}
18420
18421
ExpressionValue expFuncMax(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18422
{
18423
ExpressionValue result;
18424
double floatMax, floatCur;
18425
int64_t intMax, intCur;
18426
18427
floatCur = floatMax = std::numeric_limits<double>::min();
18428
intCur = intMax = std::numeric_limits<int64_t>::min();
18429
bool isInt = true;
18430
18431
for (size_t i = 0; i < parameters.size(); i++)
18432
{
18433
switch (parameters[i].type)
18434
{
18435
case ExpressionValueType::Integer:
18436
intCur = parameters[i].intValue;
18437
floatCur = (double)parameters[i].intValue;
18438
break;
18439
case ExpressionValueType::Float:
18440
floatCur = parameters[i].floatValue;
18441
isInt = false;
18442
break;
18443
default:
18444
return result;
18445
}
18446
18447
if (intCur > intMax)
18448
intMax = intCur;
18449
if (floatCur > floatMax)
18450
floatMax = floatCur;
18451
}
18452
18453
if (isInt)
18454
{
18455
result.intValue = intMax;
18456
result.type = ExpressionValueType::Integer;
18457
}
18458
else
18459
{
18460
result.floatValue = floatMax;
18461
result.type = ExpressionValueType::Float;
18462
}
18463
18464
return result;
18465
}
18466
18467
ExpressionValue expFuncAbs(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18468
{
18469
ExpressionValue result;
18470
18471
switch (parameters[0].type)
18472
{
18473
case ExpressionValueType::Float:
18474
result.type = ExpressionValueType::Float;
18475
result.floatValue = fabs(parameters[0].floatValue);
18476
break;
18477
case ExpressionValueType::Integer:
18478
result.type = ExpressionValueType::Integer;
18479
result.intValue = parameters[0].intValue >= 0 ?
18480
parameters[0].intValue : -parameters[0].intValue;
18481
break;
18482
default:
18483
break;
18484
}
18485
18486
return result;
18487
}
18488
18489
ExpressionValue expFuncStrlen(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18490
{
18491
const std::wstring* source;
18492
GET_PARAM(parameters,0,source);
18493
18494
return ExpressionValue((int64_t)source->size());
18495
}
18496
18497
ExpressionValue expFuncSubstr(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18498
{
18499
int64_t start, count;
18500
const std::wstring* source;
18501
18502
GET_PARAM(parameters,0,source);
18503
GET_PARAM(parameters,1,start);
18504
GET_PARAM(parameters,2,count);
18505
18506
return ExpressionValue(source->substr((size_t)start,(size_t)count));
18507
}
18508
18509
#if ARMIPS_REGEXP
18510
ExpressionValue expFuncRegExMatch(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18511
{
18512
const std::wstring* source;
18513
const std::wstring* regexString;
18514
18515
GET_PARAM(parameters,0,source);
18516
GET_PARAM(parameters,1,regexString);
18517
18518
#if ARMIPS_EXCEPTIONS
18519
try
18520
{
18521
#endif
18522
std::wregex regex(*regexString);
18523
bool found = std::regex_match(*source,regex);
18524
return ExpressionValue(found ? INT64_C(1) : INT64_C(0));
18525
#if ARMIPS_EXCEPTIONS
18526
} catch (std::regex_error&)
18527
{
18528
Logger::queueError(Logger::Error,L"Invalid regular expression");
18529
return ExpressionValue();
18530
}
18531
#endif
18532
}
18533
18534
ExpressionValue expFuncRegExSearch(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18535
{
18536
const std::wstring* source;
18537
const std::wstring* regexString;
18538
18539
GET_PARAM(parameters,0,source);
18540
GET_PARAM(parameters,1,regexString);
18541
18542
#if ARMIPS_EXCEPTIONS
18543
try
18544
{
18545
#endif
18546
std::wregex regex(*regexString);
18547
bool found = std::regex_search(*source,regex);
18548
return ExpressionValue(found ? INT64_C(1) : INT64_C(0));
18549
#if ARMIPS_EXCEPTIONS
18550
} catch (std::regex_error&)
18551
{
18552
Logger::queueError(Logger::Error,L"Invalid regular expression");
18553
return ExpressionValue();
18554
}
18555
#endif
18556
}
18557
18558
ExpressionValue expFuncRegExExtract(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18559
{
18560
const std::wstring* source;
18561
const std::wstring* regexString;
18562
int64_t matchIndex;
18563
18564
GET_PARAM(parameters,0,source);
18565
GET_PARAM(parameters,1,regexString);
18566
GET_OPTIONAL_PARAM(parameters,2,matchIndex,0);
18567
18568
#if ARMIPS_EXCEPTIONS
18569
try
18570
{
18571
#endif
18572
std::wregex regex(*regexString);
18573
std::wsmatch result;
18574
bool found = std::regex_search(*source,result,regex);
18575
if (found == false || (size_t)matchIndex >= result.size())
18576
{
18577
Logger::queueError(Logger::Error,L"Capture group index %d does not exist",matchIndex);
18578
return ExpressionValue();
18579
}
18580
18581
return ExpressionValue(result[(size_t)matchIndex].str());
18582
#if ARMIPS_EXCEPTIONS
18583
} catch (std::regex_error&)
18584
{
18585
Logger::queueError(Logger::Error,L"Invalid regular expression");
18586
return ExpressionValue();
18587
}
18588
#endif
18589
}
18590
#endif
18591
18592
ExpressionValue expFuncFind(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18593
{
18594
int64_t start;
18595
const std::wstring* source;
18596
const std::wstring* value;
18597
18598
GET_PARAM(parameters,0,source);
18599
GET_PARAM(parameters,1,value);
18600
GET_OPTIONAL_PARAM(parameters,2,start,0);
18601
18602
size_t pos = source->find(*value,(size_t)start);
18603
return ExpressionValue(pos == std::wstring::npos ? INT64_C(-1) : (int64_t) pos);
18604
}
18605
18606
ExpressionValue expFuncRFind(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18607
{
18608
int64_t start;
18609
const std::wstring* source;
18610
const std::wstring* value;
18611
18612
GET_PARAM(parameters,0,source);
18613
GET_PARAM(parameters,1,value);
18614
GET_OPTIONAL_PARAM(parameters,2,start,std::wstring::npos);
18615
18616
size_t pos = source->rfind(*value,(size_t)start);
18617
return ExpressionValue(pos == std::wstring::npos ? INT64_C(-1) : (int64_t) pos);
18618
}
18619
18620
18621
template<typename T>
18622
ExpressionValue expFuncRead(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18623
{
18624
const std::wstring* fileName;
18625
int64_t pos;
18626
18627
GET_PARAM(parameters,0,fileName);
18628
GET_OPTIONAL_PARAM(parameters,1,pos,0);
18629
18630
std::wstring fullName = getFullPathName(*fileName);
18631
18632
BinaryFile file;
18633
if (file.open(fullName,BinaryFile::Read) == false)
18634
{
18635
Logger::queueError(Logger::Error,L"Could not open %s",*fileName);
18636
return ExpressionValue();
18637
}
18638
18639
file.setPos(pos);
18640
18641
T buffer;
18642
if (file.read(&buffer, sizeof(T)) != sizeof(T))
18643
{
18644
Logger::queueError(Logger::Error, L"Failed to read %d byte(s) from offset 0x%08X of %s", sizeof(T), pos, *fileName);
18645
return ExpressionValue();
18646
}
18647
18648
return ExpressionValue((int64_t) buffer);
18649
}
18650
18651
ExpressionValue expFuncReadAscii(const std::wstring& funcName, const std::vector<ExpressionValue>& parameters)
18652
{
18653
const std::wstring* fileName;
18654
int64_t start;
18655
int64_t length;
18656
18657
GET_PARAM(parameters,0,fileName);
18658
GET_OPTIONAL_PARAM(parameters,1,start,0);
18659
GET_OPTIONAL_PARAM(parameters,2,length,0);
18660
18661
std::wstring fullName = getFullPathName(*fileName);
18662
18663
int64_t totalSize = fileSize(fullName);
18664
if (length == 0 || start+length > totalSize)
18665
length = totalSize-start;
18666
18667
BinaryFile file;
18668
if (file.open(fullName,BinaryFile::Read) == false)
18669
{
18670
Logger::queueError(Logger::Error,L"Could not open %s",fileName);
18671
return ExpressionValue();
18672
}
18673
18674
file.setPos((long)start);
18675
18676
unsigned char* buffer = new unsigned char[length];
18677
file.read(buffer,(size_t)length);
18678
18679
std::wstring result;
18680
for (size_t i = 0; i < (size_t) length; i++)
18681
{
18682
if (buffer[i] < 0x20 || buffer[i] > 0x7F)
18683
{
18684
Logger::printError(Logger::Warning,L"%s: Non-ASCII character",funcName);
18685
return ExpressionValue();
18686
}
18687
18688
result += (wchar_t) buffer[i];
18689
}
18690
18691
delete[] buffer;
18692
18693
return ExpressionValue(result);
18694
}
18695
18696
ExpressionValue expLabelFuncDefined(const std::wstring &funcName, const std::vector<std::shared_ptr<Label>> &parameters)
18697
{
18698
if (parameters.empty() || !parameters.front())
18699
{
18700
Logger::queueError(Logger::Error,L"%s: Invalid parameters", funcName);
18701
return ExpressionValue();
18702
}
18703
18704
return ExpressionValue(parameters.front()->isDefined() ? INT64_C(1) : INT64_C(0));
18705
}
18706
18707
ExpressionValue expLabelFuncOrg(const std::wstring& funcName, const std::vector<std::shared_ptr<Label>>& parameters)
18708
{
18709
// return physical address of label parameter
18710
if (parameters.size())
18711
{
18712
Label* label = parameters.front().get();
18713
if (!label)
18714
return ExpressionValue();
18715
18716
return ExpressionValue(parameters.front()->getValue());
18717
}
18718
18719
if(!g_fileManager->hasOpenFile())
18720
{
18721
Logger::queueError(Logger::Error,L"%s: no file opened", funcName);
18722
return ExpressionValue();
18723
}
18724
return ExpressionValue(g_fileManager->getVirtualAddress());
18725
}
18726
18727
ExpressionValue expLabelFuncOrga(const std::wstring& funcName, const std::vector<std::shared_ptr<Label>>& parameters)
18728
{
18729
// return physical address of label parameter
18730
if (parameters.size())
18731
{
18732
Label* label = parameters.front().get();
18733
if (!label)
18734
return ExpressionValue();
18735
18736
if (!label->hasPhysicalValue())
18737
{
18738
Logger::queueError(Logger::Error,L"%s: parameter %s has no physical address", funcName, label->getName() );
18739
return ExpressionValue();
18740
}
18741
18742
return ExpressionValue(parameters.front()->getPhysicalValue());
18743
}
18744
18745
// return current physical address otherwise
18746
if(!g_fileManager->hasOpenFile())
18747
{
18748
Logger::queueError(Logger::Error,L"%s: no file opened", funcName);
18749
return ExpressionValue();
18750
}
18751
return ExpressionValue(g_fileManager->getPhysicalAddress());
18752
}
18753
18754
ExpressionValue expLabelFuncHeaderSize(const std::wstring& funcName, const std::vector<std::shared_ptr<Label>>& parameters)
18755
{
18756
// return difference between physical and virtual address of label parameter
18757
if (parameters.size())
18758
{
18759
Label* label = parameters.front().get();
18760
if (!label)
18761
return ExpressionValue();
18762
18763
if (!label->hasPhysicalValue())
18764
{
18765
Logger::queueError(Logger::Error,L"%s: parameter %s has no physical address", funcName, label->getName() );
18766
return ExpressionValue();
18767
}
18768
18769
return ExpressionValue(label->getValue() - label->getPhysicalValue());
18770
}
18771
18772
if(!g_fileManager->hasOpenFile())
18773
{
18774
Logger::queueError(Logger::Error,L"headersize: no file opened");
18775
return ExpressionValue();
18776
}
18777
return ExpressionValue(g_fileManager->getHeaderSize());
18778
}
18779
18780
const ExpressionFunctionMap expressionFunctions = {
18781
{ L"version", { &expFuncVersion, 0, 0, ExpFuncSafety::Safe } },
18782
{ L"endianness", { &expFuncEndianness, 0, 0, ExpFuncSafety::Unsafe } },
18783
{ L"outputname", { &expFuncOutputName, 0, 0, ExpFuncSafety::Unsafe } },
18784
{ L"fileexists", { &expFuncFileExists, 1, 1, ExpFuncSafety::Safe } },
18785
{ L"filesize", { &expFuncFileSize, 1, 1, ExpFuncSafety::ConditionalUnsafe } },
18786
{ L"tostring", { &expFuncToString, 1, 1, ExpFuncSafety::Safe } },
18787
{ L"tohex", { &expFuncToHex, 1, 2, ExpFuncSafety::Safe } },
18788
18789
{ L"int", { &expFuncInt, 1, 1, ExpFuncSafety::Safe } },
18790
{ L"float", { &expFuncFloat, 1, 1, ExpFuncSafety::Safe } },
18791
{ L"frac", { &expFuncFrac, 1, 1, ExpFuncSafety::Safe } },
18792
{ L"abs", { &expFuncAbs, 1, 1, ExpFuncSafety::Safe } },
18793
{ L"round", { &expFuncRound, 1, 1, ExpFuncSafety::Safe } },
18794
{ L"min", { &expFuncMin, 1, std::numeric_limits<size_t>::max(), ExpFuncSafety::Safe } },
18795
{ L"max", { &expFuncMax, 1, std::numeric_limits<size_t>::max(), ExpFuncSafety::Safe } },
18796
18797
{ L"strlen", { &expFuncStrlen, 1, 1, ExpFuncSafety::Safe } },
18798
{ L"substr", { &expFuncSubstr, 3, 3, ExpFuncSafety::Safe } },
18799
#if ARMIPS_REGEXP
18800
{ L"regex_match", { &expFuncRegExMatch, 2, 2, ExpFuncSafety::Safe } },
18801
{ L"regex_search", { &expFuncRegExSearch, 2, 2, ExpFuncSafety::Safe } },
18802
{ L"regex_extract", { &expFuncRegExExtract, 2, 3, ExpFuncSafety::Safe } },
18803
#endif
18804
{ L"find", { &expFuncFind, 2, 3, ExpFuncSafety::Safe } },
18805
{ L"rfind", { &expFuncRFind, 2, 3, ExpFuncSafety::Safe } },
18806
18807
{ L"readbyte", { &expFuncRead<uint8_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18808
{ L"readu8", { &expFuncRead<uint8_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18809
{ L"readu16", { &expFuncRead<uint16_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18810
{ L"readu32", { &expFuncRead<uint32_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18811
{ L"readu64", { &expFuncRead<uint64_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18812
{ L"reads8", { &expFuncRead<int8_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18813
{ L"reads16", { &expFuncRead<int16_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18814
{ L"reads32", { &expFuncRead<int32_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18815
{ L"reads64", { &expFuncRead<int64_t>, 1, 2, ExpFuncSafety::ConditionalUnsafe } },
18816
{ L"readascii", { &expFuncReadAscii, 1, 3, ExpFuncSafety::ConditionalUnsafe } },
18817
};
18818
18819
extern const ExpressionLabelFunctionMap expressionLabelFunctions =
18820
{
18821
{ L"defined", { &expLabelFuncDefined, 1, 1, ExpFuncSafety::Unsafe } },
18822
{ L"org", { &expLabelFuncOrg, 0, 1, ExpFuncSafety::Unsafe } },
18823
{ L"orga", { &expLabelFuncOrga, 0, 1, ExpFuncSafety::Unsafe } },
18824
{ L"headersize", { &expLabelFuncHeaderSize, 0, 1, ExpFuncSafety::Unsafe } },
18825
};
18826
18827
// file: Core/FileManager.cpp
18828
18829
inline uint64_t swapEndianness64(uint64_t value)
18830
{
18831
return ((value & 0xFF) << 56) | ((value & 0xFF00) << 40) | ((value & 0xFF0000) << 24) | ((value & 0xFF000000) << 8) |
18832
((value & 0xFF00000000) >> 8) | ((value & 0xFF0000000000) >> 24) |
18833
((value & 0xFF000000000000) >> 40) | ((value & 0xFF00000000000000) >> 56);
18834
}
18835
18836
inline uint32_t swapEndianness32(uint32_t value)
18837
{
18838
return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24);
18839
}
18840
18841
inline uint16_t swapEndianness16(uint16_t value)
18842
{
18843
return ((value & 0xFF) << 8) | ((value & 0xFF00) >> 8);
18844
}
18845
18846
18847
GenericAssemblerFile::GenericAssemblerFile(const std::wstring& fileName, int64_t headerSize, bool overwrite)
18848
{
18849
this->fileName = fileName;
18850
this->headerSize = headerSize;
18851
this->originalHeaderSize = headerSize;
18852
this->seekPhysical(0);
18853
mode = overwrite == true ? Create : Open;
18854
}
18855
18856
GenericAssemblerFile::GenericAssemblerFile(const std::wstring& fileName, const std::wstring& originalFileName, int64_t headerSize)
18857
{
18858
this->fileName = fileName;
18859
this->originalName = originalFileName;
18860
this->headerSize = headerSize;
18861
this->originalHeaderSize = headerSize;
18862
this->seekPhysical(0);
18863
mode = Copy;
18864
}
18865
18866
bool GenericAssemblerFile::open(bool onlyCheck)
18867
{
18868
headerSize = originalHeaderSize;
18869
virtualAddress = headerSize;
18870
18871
if (onlyCheck == false)
18872
{
18873
// actually open the file
18874
bool success;
18875
switch (mode)
18876
{
18877
case Open:
18878
success = handle.open(fileName,BinaryFile::ReadWrite);
18879
if (success == false)
18880
{
18881
Logger::printError(Logger::FatalError,L"Could not open file %s",fileName);
18882
return false;
18883
}
18884
return true;
18885
18886
case Create:
18887
success = handle.open(fileName,BinaryFile::Write);
18888
if (success == false)
18889
{
18890
Logger::printError(Logger::FatalError,L"Could not create file %s",fileName);
18891
return false;
18892
}
18893
return true;
18894
18895
case Copy:
18896
success = copyFile(originalName,fileName);
18897
if (success == false)
18898
{
18899
Logger::printError(Logger::FatalError,L"Could not copy file %s",originalName);
18900
return false;
18901
}
18902
18903
success = handle.open(fileName,BinaryFile::ReadWrite);
18904
if (success == false)
18905
{
18906
Logger::printError(Logger::FatalError,L"Could not create file %s",fileName);
18907
return false;
18908
}
18909
return true;
18910
18911
default:
18912
return false;
18913
}
18914
}
18915
18916
// else only check if it can be done, don't actually do it permanently
18917
bool success, exists;
18918
BinaryFile temp;
18919
switch (mode)
18920
{
18921
case Open:
18922
success = temp.open(fileName,BinaryFile::ReadWrite);
18923
if (success == false)
18924
{
18925
Logger::queueError(Logger::FatalError,L"Could not open file %s",fileName);
18926
return false;
18927
}
18928
temp.close();
18929
return true;
18930
18931
case Create:
18932
// if it exists, check if you can open it with read/write access
18933
// otherwise open it with write access and remove it afterwards
18934
exists = fileExists(fileName);
18935
success = temp.open(fileName,exists ? BinaryFile::ReadWrite : BinaryFile::Write);
18936
if (success == false)
18937
{
18938
Logger::queueError(Logger::FatalError,L"Could not create file %s",fileName);
18939
return false;
18940
}
18941
temp.close();
18942
18943
if (exists == false)
18944
deleteFile(fileName);
18945
18946
return true;
18947
18948
case Copy:
18949
// check original file
18950
success = temp.open(originalName,BinaryFile::ReadWrite);
18951
if (success == false)
18952
{
18953
Logger::queueError(Logger::FatalError,L"Could not open file %s",originalName);
18954
return false;
18955
}
18956
temp.close();
18957
18958
// check new file, same as create
18959
exists = fileExists(fileName);
18960
success = temp.open(fileName,exists ? BinaryFile::ReadWrite : BinaryFile::Write);
18961
if (success == false)
18962
{
18963
Logger::queueError(Logger::FatalError,L"Could not create file %s",fileName);
18964
return false;
18965
}
18966
temp.close();
18967
18968
if (exists == false)
18969
deleteFile(fileName);
18970
18971
return true;
18972
18973
default:
18974
return false;
18975
};
18976
18977
return false;
18978
}
18979
18980
bool GenericAssemblerFile::write(void* data, size_t length)
18981
{
18982
if (isOpen() == false)
18983
return false;
18984
18985
size_t len = handle.write(data,length);
18986
virtualAddress += len;
18987
return len == length;
18988
}
18989
18990
bool GenericAssemblerFile::seekVirtual(int64_t virtualAddress)
18991
{
18992
if (virtualAddress - headerSize < 0)
18993
{
18994
Logger::queueError(Logger::Error,L"Seeking to virtual address with negative physical address");
18995
return false;
18996
}
18997
if (virtualAddress < 0)
18998
Logger::queueError(Logger::Warning,L"Seeking to negative virtual address");
18999
19000
this->virtualAddress = virtualAddress;
19001
int64_t physicalAddress = virtualAddress-headerSize;
19002
19003
if (isOpen())
19004
handle.setPos((long)physicalAddress);
19005
19006
return true;
19007
}
19008
19009
bool GenericAssemblerFile::seekPhysical(int64_t physicalAddress)
19010
{
19011
if (physicalAddress < 0)
19012
{
19013
Logger::queueError(Logger::Error,L"Seeking to negative physical address");
19014
return false;
19015
}
19016
if (physicalAddress + headerSize < 0)
19017
Logger::queueError(Logger::Warning,L"Seeking to physical address with negative virtual address");
19018
19019
virtualAddress = physicalAddress+headerSize;
19020
19021
if (isOpen())
19022
handle.setPos((long)physicalAddress);
19023
19024
return true;
19025
}
19026
19027
19028
19029
FileManager::FileManager()
19030
{
19031
// detect own endianness
19032
volatile union
19033
{
19034
uint32_t i;
19035
uint8_t c[4];
19036
} u;
19037
u.c[3] = 0xAA;
19038
u.c[2] = 0xBB;
19039
u.c[1] = 0xCC;
19040
u.c[0] = 0xDD;
19041
19042
if (u.i == 0xDDCCBBAA)
19043
ownEndianness = Endianness::Big;
19044
else if (u.i == 0xAABBCCDD)
19045
ownEndianness = Endianness::Little;
19046
else
19047
Logger::printError(Logger::Error,L"Running on unknown endianness");
19048
19049
reset();
19050
}
19051
19052
FileManager::~FileManager()
19053
{
19054
19055
}
19056
19057
void FileManager::reset()
19058
{
19059
activeFile = nullptr;
19060
setEndianness(Endianness::Little);
19061
}
19062
19063
bool FileManager::checkActiveFile()
19064
{
19065
if (activeFile == nullptr)
19066
{
19067
Logger::queueError(Logger::Error,L"No file opened");
19068
return false;
19069
}
19070
return true;
19071
}
19072
19073
bool FileManager::openFile(std::shared_ptr<AssemblerFile> file, bool onlyCheck)
19074
{
19075
if (activeFile != nullptr)
19076
{
19077
Logger::queueError(Logger::Warning,L"File not closed before opening a new one");
19078
activeFile->close();
19079
}
19080
19081
activeFile = file;
19082
return activeFile->open(onlyCheck);
19083
}
19084
19085
void FileManager::addFile(std::shared_ptr<AssemblerFile> file)
19086
{
19087
files.push_back(file);
19088
}
19089
19090
void FileManager::closeFile()
19091
{
19092
if (activeFile == nullptr)
19093
{
19094
Logger::queueError(Logger::Warning,L"No file opened");
19095
return;
19096
}
19097
19098
activeFile->close();
19099
activeFile = nullptr;
19100
}
19101
19102
bool FileManager::write(void* data, size_t length)
19103
{
19104
if (checkActiveFile() == false)
19105
return false;
19106
19107
if (activeFile->isOpen() == false)
19108
{
19109
Logger::queueError(Logger::Error,L"No file opened");
19110
return false;
19111
}
19112
19113
return activeFile->write(data,length);
19114
}
19115
19116
bool FileManager::writeU8(uint8_t data)
19117
{
19118
return write(&data,1);
19119
}
19120
19121
bool FileManager::writeU16(uint16_t data)
19122
{
19123
if (endianness != ownEndianness)
19124
data = swapEndianness16(data);
19125
19126
return write(&data,2);
19127
}
19128
19129
bool FileManager::writeU32(uint32_t data)
19130
{
19131
if (endianness != ownEndianness)
19132
data = swapEndianness32(data);
19133
19134
return write(&data,4);
19135
}
19136
19137
bool FileManager::writeU64(uint64_t data)
19138
{
19139
if (endianness != ownEndianness)
19140
data = swapEndianness64(data);
19141
19142
return write(&data,8);
19143
}
19144
19145
int64_t FileManager::getVirtualAddress()
19146
{
19147
if (activeFile == nullptr)
19148
return -1;
19149
return activeFile->getVirtualAddress();
19150
}
19151
19152
int64_t FileManager::getPhysicalAddress()
19153
{
19154
if (activeFile == nullptr)
19155
return -1;
19156
return activeFile->getPhysicalAddress();
19157
}
19158
19159
int64_t FileManager::getHeaderSize()
19160
{
19161
if (activeFile == nullptr)
19162
return -1;
19163
return activeFile->getHeaderSize();
19164
}
19165
19166
bool FileManager::seekVirtual(int64_t virtualAddress)
19167
{
19168
if (checkActiveFile() == false)
19169
return false;
19170
19171
bool result = activeFile->seekVirtual(virtualAddress);
19172
if (result && Global.memoryMode)
19173
{
19174
int sec = Global.symbolTable.findSection(virtualAddress);
19175
if (sec != -1)
19176
Global.Section = sec;
19177
}
19178
19179
return result;
19180
}
19181
19182
bool FileManager::seekPhysical(int64_t virtualAddress)
19183
{
19184
if (checkActiveFile() == false)
19185
return false;
19186
return activeFile->seekPhysical(virtualAddress);
19187
}
19188
19189
bool FileManager::advanceMemory(size_t bytes)
19190
{
19191
if (checkActiveFile() == false)
19192
return false;
19193
19194
int64_t pos = activeFile->getVirtualAddress();
19195
return activeFile->seekVirtual(pos+bytes);
19196
}
19197
19198
// file: Core/Misc.cpp
19199
#include <iostream>
19200
19201
#ifdef _WIN32
19202
#include <windows.h>
19203
#endif
19204
19205
std::vector<Logger::QueueEntry> Logger::queue;
19206
std::vector<std::wstring> Logger::errors;
19207
bool Logger::error = false;
19208
bool Logger::fatalError = false;
19209
bool Logger::errorOnWarning = false;
19210
bool Logger::silent = false;
19211
int Logger::suppressLevel = 0;
19212
19213
std::wstring Logger::formatError(ErrorType type, const wchar_t* text)
19214
{
19215
std::wstring position;
19216
19217
if (Global.memoryMode == false && Global.FileInfo.FileList.size() > 0)
19218
{
19219
std::wstring& fileName = Global.FileInfo.FileList[Global.FileInfo.FileNum];
19220
position = formatString(L"%s(%d) ",fileName,Global.FileInfo.LineNumber);
19221
}
19222
19223
switch (type)
19224
{
19225
case Warning:
19226
return formatString(L"%swarning: %s",position,text);
19227
case Error:
19228
return formatString(L"%serror: %s",position,text);
19229
case FatalError:
19230
return formatString(L"%sfatal error: %s",position,text);
19231
case Notice:
19232
return formatString(L"%snotice: %s",position,text);
19233
}
19234
19235
return L"";
19236
}
19237
19238
void Logger::setFlags(ErrorType type)
19239
{
19240
switch (type)
19241
{
19242
case Warning:
19243
if (errorOnWarning)
19244
error = true;
19245
break;
19246
case Error:
19247
error = true;
19248
break;
19249
case FatalError:
19250
error = true;
19251
fatalError = true;
19252
break;
19253
case Notice:
19254
break;
19255
}
19256
}
19257
19258
void Logger::clear()
19259
{
19260
queue.clear();
19261
errors.clear();
19262
error = false;
19263
fatalError = false;
19264
errorOnWarning = false;
19265
silent = false;
19266
}
19267
19268
void Logger::printLine(const std::wstring& text)
19269
{
19270
if (suppressLevel)
19271
return;
19272
19273
std::wcout << text << std::endl;
19274
19275
#if defined(_MSC_VER) && defined(_DEBUG)
19276
OutputDebugStringW(text.c_str());
19277
OutputDebugStringW(L"\n");
19278
#endif
19279
}
19280
19281
void Logger::printLine(const std::string& text)
19282
{
19283
if (suppressLevel)
19284
return;
19285
19286
std::cout << text << std::endl;
19287
19288
#if defined(_MSC_VER) && defined(_DEBUG)
19289
OutputDebugStringA(text.c_str());
19290
OutputDebugStringA("\n");
19291
#endif
19292
}
19293
19294
void Logger::print(const std::wstring& text)
19295
{
19296
if (suppressLevel)
19297
return;
19298
19299
std::wcout << text;
19300
19301
#if defined(_MSC_VER) && defined(_DEBUG)
19302
OutputDebugStringW(text.c_str());
19303
#endif
19304
}
19305
19306
void Logger::printError(ErrorType type, const std::wstring& text)
19307
{
19308
if (suppressLevel)
19309
return;
19310
19311
std::wstring errorText = formatError(type,text.c_str());
19312
errors.push_back(errorText);
19313
19314
if (!silent)
19315
printLine(errorText);
19316
19317
setFlags(type);
19318
}
19319
19320
void Logger::printError(ErrorType type, const wchar_t* text)
19321
{
19322
if (suppressLevel)
19323
return;
19324
19325
std::wstring errorText = formatError(type,text);
19326
errors.push_back(errorText);
19327
19328
if (!silent)
19329
printLine(errorText);
19330
19331
setFlags(type);
19332
}
19333
19334
void Logger::queueError(ErrorType type, const std::wstring& text)
19335
{
19336
if (suppressLevel)
19337
return;
19338
19339
QueueEntry entry;
19340
entry.type = type;
19341
entry.text = formatError(type,text.c_str());
19342
queue.push_back(entry);
19343
}
19344
19345
void Logger::queueError(ErrorType type, const wchar_t* text)
19346
{
19347
if (suppressLevel)
19348
return;
19349
19350
QueueEntry entry;
19351
entry.type = type;
19352
entry.text = formatError(type,text);
19353
queue.push_back(entry);
19354
}
19355
19356
void Logger::printQueue()
19357
{
19358
for (size_t i = 0; i < queue.size(); i++)
19359
{
19360
errors.push_back(queue[i].text);
19361
19362
if (!silent)
19363
printLine(queue[i].text);
19364
19365
setFlags(queue[i].type);
19366
}
19367
}
19368
19369
void TempData::start()
19370
{
19371
if (file.getFileName().empty() == false)
19372
{
19373
if (file.open(TextFile::Write) == false)
19374
{
19375
Logger::printError(Logger::Error,L"Could not open temp file %s.",file.getFileName());
19376
return;
19377
}
19378
19379
size_t fileCount = Global.FileInfo.FileList.size();
19380
size_t lineCount = Global.FileInfo.TotalLineCount;
19381
size_t labelCount = Global.symbolTable.getLabelCount();
19382
size_t equCount = Global.symbolTable.getEquationCount();
19383
19384
file.writeFormat(L"; %d %S included\n",fileCount,fileCount == 1 ? "file" : "files");
19385
file.writeFormat(L"; %d %S\n",lineCount,lineCount == 1 ? "line" : "lines");
19386
file.writeFormat(L"; %d %S\n",labelCount,labelCount == 1 ? "label" : "labels");
19387
file.writeFormat(L"; %d %S\n\n",equCount,equCount == 1 ? "equation" : "equations");
19388
for (size_t i = 0; i < fileCount; i++)
19389
{
19390
file.writeFormat(L"; %S\n",Global.FileInfo.FileList[i]);
19391
}
19392
file.writeLine("");
19393
}
19394
}
19395
19396
void TempData::end()
19397
{
19398
if (file.isOpen())
19399
file.close();
19400
}
19401
19402
void TempData::writeLine(int64_t memoryAddress, const std::wstring& text)
19403
{
19404
if (file.isOpen())
19405
{
19406
wchar_t hexbuf[10] = {0};
19407
swprintf(hexbuf, 10, L"%08X ", (int32_t) memoryAddress);
19408
std::wstring str = hexbuf + text;
19409
while (str.size() < 70)
19410
str += ' ';
19411
19412
str += formatString(L"; %S line %d",
19413
Global.FileInfo.FileList[Global.FileInfo.FileNum],Global.FileInfo.LineNumber);
19414
19415
file.writeLine(str);
19416
}
19417
}
19418
19419
// file: Core/SymbolData.cpp
19420
#include <algorithm>
19421
19422
SymbolData::SymbolData()
19423
{
19424
clear();
19425
}
19426
19427
void SymbolData::clear()
19428
{
19429
enabled = true;
19430
nocashSymFileName.clear();
19431
modules.clear();
19432
files.clear();
19433
currentModule = 0;
19434
currentFunction = -1;
19435
19436
SymDataModule defaultModule;
19437
defaultModule.file = nullptr;
19438
modules.push_back(defaultModule);
19439
}
19440
19441
struct NocashSymEntry
19442
{
19443
int64_t address;
19444
std::wstring text;
19445
19446
bool operator<(const NocashSymEntry& other) const
19447
{
19448
if (address != other.address)
19449
return address < other.address;
19450
return text < other.text;
19451
}
19452
};
19453
19454
void SymbolData::writeNocashSym()
19455
{
19456
if (nocashSymFileName.empty())
19457
return;
19458
19459
std::vector<NocashSymEntry> entries;
19460
for (size_t k = 0; k < modules.size(); k++)
19461
{
19462
SymDataModule& module = modules[k];
19463
for (size_t i = 0; i < module.symbols.size(); i++)
19464
{
19465
SymDataSymbol& sym = module.symbols[i];
19466
19467
size_t size = 0;
19468
for (size_t f = 0; f < module.functions.size(); f++)
19469
{
19470
if (module.functions[f].address == sym.address)
19471
{
19472
size = module.functions[f].size;
19473
break;
19474
}
19475
}
19476
19477
NocashSymEntry entry;
19478
entry.address = sym.address;
19479
19480
if (size != 0 && nocashSymVersion >= 2)
19481
entry.text = formatString(L"%s,%08X",sym.name,size);
19482
else
19483
entry.text = sym.name;
19484
19485
if (nocashSymVersion == 1)
19486
std::transform(entry.text.begin(), entry.text.end(), entry.text.begin(), ::towlower);
19487
19488
entries.push_back(entry);
19489
}
19490
19491
for (const SymDataData& data: module.data)
19492
{
19493
NocashSymEntry entry;
19494
entry.address = data.address;
19495
19496
switch (data.type)
19497
{
19498
case Data8:
19499
entry.text = formatString(L".byt:%04X",data.size);
19500
break;
19501
case Data16:
19502
entry.text = formatString(L".wrd:%04X",data.size);
19503
break;
19504
case Data32:
19505
entry.text = formatString(L".dbl:%04X",data.size);
19506
break;
19507
case Data64:
19508
entry.text = formatString(L".dbl:%04X",data.size);
19509
break;
19510
case DataAscii:
19511
entry.text = formatString(L".asc:%04X",data.size);
19512
break;
19513
}
19514
19515
entries.push_back(entry);
19516
}
19517
}
19518
19519
std::sort(entries.begin(),entries.end());
19520
19521
TextFile file;
19522
if (file.open(nocashSymFileName,TextFile::Write,TextFile::ASCII) == false)
19523
{
19524
Logger::printError(Logger::Error,L"Could not open sym file %s.",file.getFileName());
19525
return;
19526
}
19527
file.writeLine(L"00000000 0");
19528
19529
for (size_t i = 0; i < entries.size(); i++)
19530
{
19531
file.writeFormat(L"%08X %s\n",entries[i].address,entries[i].text);
19532
}
19533
19534
file.write("\x1A");
19535
file.close();
19536
}
19537
19538
void SymbolData::write()
19539
{
19540
writeNocashSym();
19541
}
19542
19543
void SymbolData::addLabel(int64_t memoryAddress, const std::wstring& name)
19544
{
19545
if (!enabled)
19546
return;
19547
19548
SymDataSymbol sym;
19549
sym.address = memoryAddress;
19550
sym.name = name;
19551
19552
for (SymDataSymbol& symbol: modules[currentModule].symbols)
19553
{
19554
if (symbol.address == sym.address && symbol.name == sym.name)
19555
return;
19556
}
19557
19558
modules[currentModule].symbols.push_back(sym);
19559
}
19560
19561
void SymbolData::addData(int64_t address, size_t size, DataType type)
19562
{
19563
if (!enabled)
19564
return;
19565
19566
SymDataData data;
19567
data.address = address;
19568
data.size = size;
19569
data.type = type;
19570
modules[currentModule].data.insert(data);
19571
}
19572
19573
size_t SymbolData::addFileName(const std::wstring& fileName)
19574
{
19575
for (size_t i = 0; i < files.size(); i++)
19576
{
19577
if (files[i] == fileName)
19578
return i;
19579
}
19580
19581
files.push_back(fileName);
19582
return files.size()-1;
19583
}
19584
19585
void SymbolData::startModule(AssemblerFile* file)
19586
{
19587
for (size_t i = 0; i < modules.size(); i++)
19588
{
19589
if (modules[i].file == file)
19590
{
19591
currentModule = i;
19592
return;
19593
}
19594
}
19595
19596
SymDataModule module;
19597
module.file = file;
19598
modules.push_back(module);
19599
currentModule = modules.size()-1;
19600
}
19601
19602
void SymbolData::endModule(AssemblerFile* file)
19603
{
19604
if (modules[currentModule].file != file)
19605
return;
19606
19607
if (currentModule == 0)
19608
{
19609
Logger::printError(Logger::Error,L"No module opened");
19610
return;
19611
}
19612
19613
if (currentFunction != -1)
19614
{
19615
Logger::printError(Logger::Error,L"Module closed before function end");
19616
currentFunction = -1;
19617
}
19618
19619
currentModule = 0;
19620
}
19621
19622
void SymbolData::startFunction(int64_t address)
19623
{
19624
if (currentFunction != -1)
19625
{
19626
endFunction(address);
19627
}
19628
19629
currentFunction = modules[currentModule].functions.size();
19630
19631
SymDataFunction func;
19632
func.address = address;
19633
func.size = 0;
19634
modules[currentModule].functions.push_back(func);
19635
}
19636
19637
void SymbolData::endFunction(int64_t address)
19638
{
19639
if (currentFunction == -1)
19640
{
19641
Logger::printError(Logger::Error,L"Not inside a function");
19642
return;
19643
}
19644
19645
SymDataFunction& func = modules[currentModule].functions[currentFunction];
19646
func.size = (size_t) (address-func.address);
19647
currentFunction = -1;
19648
}
19649
19650
// file: Core/SymbolTable.cpp
19651
19652
const wchar_t validSymbolCharacters[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
19653
19654
bool operator<(SymbolKey const& lhs, SymbolKey const& rhs)
19655
{
19656
if (lhs.file != rhs.file)
19657
return lhs.file < rhs.file;
19658
if (lhs.section != rhs.section)
19659
return lhs.section < rhs.section;
19660
return lhs.name.compare(rhs.name) < 0;
19661
}
19662
19663
SymbolTable::SymbolTable()
19664
{
19665
uniqueCount = 0;
19666
}
19667
19668
SymbolTable::~SymbolTable()
19669
{
19670
clear();
19671
}
19672
19673
void SymbolTable::clear()
19674
{
19675
symbols.clear();
19676
labels.clear();
19677
equationsCount = 0;
19678
uniqueCount = 0;
19679
}
19680
19681
void SymbolTable::setFileSectionValues(const std::wstring& symbol, int& file, int& section)
19682
{
19683
if (symbol[0] == '@')
19684
{
19685
if (symbol[1] != '@')
19686
{
19687
// static label, @. the section doesn't matter
19688
section = -1;
19689
} else {
19690
// local label, @@. the file doesn't matter
19691
file = -1;
19692
}
19693
} else {
19694
// global label. neither file nor section matters
19695
file = section = -1;
19696
}
19697
}
19698
19699
std::shared_ptr<Label> SymbolTable::getLabel(const std::wstring& symbol, int file, int section)
19700
{
19701
if (isValidSymbolName(symbol) == false)
19702
return nullptr;
19703
19704
int actualSection = section;
19705
setFileSectionValues(symbol,file,section);
19706
SymbolKey key = { symbol, file, section };
19707
19708
// find label, create new one if it doesn't exist
19709
auto it = symbols.find(key);
19710
if (it == symbols.end())
19711
{
19712
SymbolInfo value = { LabelSymbol, labels.size() };
19713
symbols[key] = value;
19714
19715
std::shared_ptr<Label> result = std::make_shared<Label>(symbol);
19716
if (section == actualSection)
19717
result->setSection(section); // local, set section of parent
19718
else
19719
result->setSection(actualSection+1); // global, set section of children
19720
labels.push_back(result);
19721
return result;
19722
}
19723
19724
// make sure not to match symbols that aren't labels
19725
if (it->second.type != LabelSymbol)
19726
return nullptr;
19727
19728
return labels[it->second.index];
19729
}
19730
19731
bool SymbolTable::symbolExists(const std::wstring& symbol, int file, int section)
19732
{
19733
if (isValidSymbolName(symbol) == false)
19734
return false;
19735
19736
setFileSectionValues(symbol,file,section);
19737
19738
SymbolKey key = { symbol, file, section };
19739
auto it = symbols.find(key);
19740
return it != symbols.end();
19741
}
19742
19743
bool SymbolTable::isValidSymbolName(const std::wstring& symbol)
19744
{
19745
size_t size = symbol.size();
19746
size_t start = 0;
19747
19748
// don't match empty names
19749
if (size == 0 || symbol.compare(L"@") == 0 || symbol.compare(L"@@") == 0)
19750
return false;
19751
19752
if (symbol[0] == '@')
19753
{
19754
start++;
19755
if (size > 1 && symbol[1] == '@')
19756
start++;
19757
}
19758
19759
if (symbol[start] >= '0' && symbol[start] <= '9')
19760
return false;
19761
19762
for (size_t i = start; i < size; i++)
19763
{
19764
if (wcschr(validSymbolCharacters,symbol[i]) == nullptr)
19765
return false;
19766
}
19767
19768
return true;
19769
}
19770
19771
bool SymbolTable::isValidSymbolCharacter(wchar_t character, bool first)
19772
{
19773
if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z')) return true;
19774
if (!first && (character >= '0' && character <= '9')) return true;
19775
if (character == '_' || character == '.') return true;
19776
if (character == '@') return true;
19777
return false;
19778
}
19779
19780
bool SymbolTable::addEquation(const std::wstring& name, int file, int section, size_t referenceIndex)
19781
{
19782
if (isValidSymbolName(name) == false)
19783
return false;
19784
19785
if (symbolExists(name,file,section))
19786
return false;
19787
19788
setFileSectionValues(name,file,section);
19789
19790
SymbolKey key = { name, file, section };
19791
SymbolInfo value = { EquationSymbol, referenceIndex };
19792
symbols[key] = value;
19793
19794
equationsCount++;
19795
return true;
19796
}
19797
19798
bool SymbolTable::findEquation(const std::wstring& name, int file, int section, size_t& dest)
19799
{
19800
setFileSectionValues(name,file,section);
19801
19802
SymbolKey key = { name, file, section };
19803
auto it = symbols.find(key);
19804
if (it == symbols.end() || it->second.type != EquationSymbol)
19805
return false;
19806
19807
dest = it->second.index;
19808
return true;
19809
}
19810
19811
// TODO: better
19812
std::wstring SymbolTable::getUniqueLabelName(bool local)
19813
{
19814
std::wstring name = formatString(L"__armips_label_%08x__",uniqueCount++);
19815
if (local)
19816
name = L"@@" + name;
19817
19818
generatedLabels.insert(name);
19819
return name;
19820
}
19821
19822
void SymbolTable::addLabels(const std::vector<LabelDefinition>& labels)
19823
{
19824
for (const LabelDefinition& def: labels)
19825
{
19826
if (!isValidSymbolName(def.name))
19827
continue;
19828
19829
std::shared_ptr<Label> label = getLabel(def.name,Global.FileInfo.FileNum,Global.Section);
19830
if (label == nullptr)
19831
continue;
19832
19833
label->setOriginalName(def.originalName);
19834
19835
if (isLocalSymbol(def.name) == false)
19836
Global.Section++;
19837
19838
label->setDefined(true);
19839
label->setValue(def.value);
19840
}
19841
}
19842
19843
int SymbolTable::findSection(int64_t address)
19844
{
19845
int64_t smallestBefore = -1;
19846
int64_t smallestDiff = 0x7FFFFFFF;
19847
19848
for (auto& lab: labels)
19849
{
19850
int diff = address-lab->getValue();
19851
if (diff >= 0 && diff < smallestDiff)
19852
{
19853
smallestDiff = diff;
19854
smallestBefore = lab->getSection();
19855
}
19856
}
19857
19858
return smallestBefore;
19859
}
19860
19861
// file: Main/main.cpp
19862
19863
int wmain(int argc, wchar_t* argv[])
19864
{
19865
std::setlocale(LC_CTYPE,"");
19866
19867
#ifdef ARMIPS_TESTS
19868
std::wstring name;
19869
19870
if (argc < 2)
19871
return !runTests(L"Tests", argv[0]);
19872
else
19873
return !runTests(argv[1], argv[0]);
19874
#endif
19875
19876
StringList arguments = getStringListFromArray(argv,argc);
19877
19878
return runFromCommandLine(arguments);
19879
}
19880
19881
#ifndef _WIN32
19882
19883
int main(int argc, char* argv[])
19884
{
19885
// convert input to wstring
19886
std::vector<std::wstring> wideStrings;
19887
for (int i = 0; i < argc; i++)
19888
{
19889
std::wstring str = convertUtf8ToWString(argv[i]);
19890
wideStrings.push_back(str);
19891
}
19892
19893
// create argv replacement
19894
wchar_t** wargv = new wchar_t*[argc];
19895
for (int i = 0; i < argc; i++)
19896
{
19897
wargv[i] = (wchar_t*) wideStrings[i].c_str();
19898
}
19899
19900
int result = wmain(argc,wargv);
19901
19902
delete[] wargv;
19903
return result;
19904
}
19905
19906
#endif
19907
19908
19909