1
// Copyright (C) 2003 Dolphin Project.
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0.
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
15
// Official SVN repository and contact information can be found at
16
// http://code.google.com/p/dolphin-emu/
18
// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!
20
#ifndef _DOLPHIN_FAKE_CODEGEN_
21
#define _DOLPHIN_FAKE_CODEGEN_
27
#include "MsgHandler.h"
29
// TODO: Check if Pandora still needs signal.h/kill here. Symbian doesn't.
34
#define IS_SIGNED 1 << 1
35
#define ROUND_TO_ZERO 1 << 2
42
R0 = 0, R1, R2, R3, R4, R5,
43
R6, R7, R8, R9, R10, R11,
46
// R13 - R15 are SP, LR, and PC.
47
// Almost always referred to by name instead of register number
48
R12 = 12, R13 = 13, R14 = 14, R15 = 15,
49
R_IP = 12, R_SP = 13, R_LR = 14, R_PC = 15,
52
// VFP single precision registers
53
S0, S1, S2, S3, S4, S5, S6,
54
S7, S8, S9, S10, S11, S12, S13,
55
S14, S15, S16, S17, S18, S19, S20,
56
S21, S22, S23, S24, S25, S26, S27,
59
// VFP Double Precision registers
60
D0, D1, D2, D3, D4, D5, D6, D7,
61
D8, D9, D10, D11, D12, D13, D14, D15,
62
D16, D17, D18, D19, D20, D21, D22, D23,
63
D24, D25, D26, D27, D28, D29, D30, D31,
65
// ASIMD Quad-Word registers
66
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
67
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
69
// for NEON VLD/VST instructions
71
INVALID_REG = 0xFFFFFFFF
80
CC_MI, // Minus (Negative)
84
CC_HI, // Unsigned higher
85
CC_LS, // Unsigned lower or same
86
CC_GE, // Signed greater than or equal
87
CC_LT, // Signed less than
88
CC_GT, // Signed greater than
89
CC_LE, // Signed less than or equal
90
CC_AL, // Always (unconditional) 14
91
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
92
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
94
const u32 NO_COND = 0xE0000000;
129
// This is no longer a proper operand2 class. Need to split up.
132
friend class FakeXEmitter;
140
u8 Rotation; // Only for u8 values
151
Operand2(u32 imm, OpType type = TYPE_IMM)
158
Operand2(FakeReg Reg)
164
Operand2(u8 imm, u8 rotation)
170
Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR
173
_assert_msg_(JIT, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
174
IndexOrShift = shift;
179
Operand2(FakeReg base, ShiftType type, u8 shift)// For IMM shifted register
181
if(shift == 32) shift = 0;
185
_assert_msg_(JIT, shift < 32, "Invalid Operand2: LSL %u", shift);
188
_assert_msg_(JIT, shift <= 32, "Invalid Operand2: LSR %u", shift);
195
_assert_msg_(JIT, shift < 32, "Invalid Operand2: ASR %u", shift);
202
_assert_msg_(JIT, shift < 32, "Invalid Operand2: ROR %u", shift);
207
_assert_msg_(JIT, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
211
IndexOrShift = shift;
221
return Imm12Mod(); // This'll need to be changed later
229
_assert_msg_(JIT, false, "GetData with Invalid Type");
233
u32 IMMSR() // IMM shifted register
235
_assert_msg_(JIT, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
236
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
238
u32 RSR() // Register shifted register
240
_assert_msg_(JIT, Type == TYPE_RSR, "RSR must be RSR Of Course");
241
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
245
_assert_msg_(JIT, Type == TYPE_REG, "Rm must be with Reg");
251
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm5 not IMM value");
252
return ((Value & 0x0000001F) << 7);
256
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value");
259
u32 Imm8Rot() // IMM8 with Rotation
261
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value");
262
_assert_msg_(JIT, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
263
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
267
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm12 not IMM");
268
return (Value & 0x00000FFF);
273
// This is an IMM12 with the top four bits being rotation and the
274
// bottom eight being an IMM. This is for instructions that need to
275
// expand a 8bit IMM to a 32bit value and gives you some rotation as
277
// Each rotation rotates to the right by 2 bits
278
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm12Mod not IMM");
279
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
283
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
284
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
290
u32 Imm16High() // Returns high 16bits
292
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
293
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
297
_assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
298
return (Value & 0x0FFFFFFF);
302
// Use these when you don't know if an imm can be represented as an operand2.
303
// This lets you generate both an optimal and a fallback solution by checking
304
// the return value, which will be false if these fail to find a Operand2 that
305
// represents your 32-bit imm value.
306
bool TryMakeOperand2(u32 imm, Operand2 &op2);
307
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
308
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
310
// Use this only when you know imm can be made into an Operand2.
311
Operand2 AssumeMakeOperand2(u32 imm);
313
inline Operand2 R(FakeReg Reg) { return Operand2(Reg, TYPE_REG); }
314
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
315
inline Operand2 Mem(void *ptr) { return Operand2((u32)(uintptr_t)ptr, TYPE_IMM); }
316
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
317
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
323
u32 condition; // Remembers our codition at the time
324
int type; //0 = B 1 = BL
327
typedef const u8* JumpTarget;
329
// XXX: Stop polluting the global namespace
330
const u32 I_8 = (1 << 0);
331
const u32 I_16 = (1 << 1);
332
const u32 I_32 = (1 << 2);
333
const u32 I_64 = (1 << 3);
334
const u32 I_SIGNED = (1 << 4);
335
const u32 I_UNSIGNED = (1 << 5);
336
const u32 F_32 = (1 << 6);
337
const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL
339
u32 EncodeVd(FakeReg Vd);
340
u32 EncodeVn(FakeReg Vn);
341
u32 EncodeVm(FakeReg Vm);
343
u32 encodedSize(u32 value);
345
// Subtracts the base from the register to give us the real one
346
FakeReg SubBase(FakeReg Reg);
348
// See A.7.1 in the Fakev7-A
349
// VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed
350
FakeReg DScalar(FakeReg dreg, int subScalar);
351
FakeReg QScalar(FakeReg qreg, int subScalar);
365
friend struct OpArg; // for Write8 etc
367
u8 *code, *startcode;
368
u8 *lastCacheFlushEnd;
372
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
375
FakeXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
376
condition = CC_AL << 28;
378
FakeXEmitter(u8 *code_ptr) {
380
lastCacheFlushEnd = code_ptr;
381
startcode = code_ptr;
382
condition = CC_AL << 28;
384
virtual ~FakeXEmitter() {}
386
void SetCodePtr(u8 *ptr) {}
387
void ReserveCodeSpace(u32 bytes) {}
388
const u8 *AlignCode16() { return nullptr; }
389
const u8 *AlignCodePage() { return nullptr; }
390
const u8 *GetCodePtr() const { return nullptr; }
391
void FlushIcache() {}
392
void FlushIcacheSection(u8 *start, u8 *end) {}
393
u8 *GetWritableCodePtr() { return nullptr; }
395
CCFlags GetCC() { return CCFlags(condition >> 28); }
396
void SetCC(CCFlags cond = CC_AL) {}
398
// Special purpose instructions
401
void NOP(int count = 1) {} //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
407
void QuickCallFunction(FakeReg scratchreg, const void *func);
408
template <typename T> void QuickCallFunction(FakeReg scratchreg, T func) {
409
QuickCallFunction(scratchreg, (const void *)func);
411
}; // class FakeXEmitter
414
// Everything that needs to generate machine code should inherit from this.
415
// You get memory management for free, plus, you can use all the MOV etc functions without
416
// having to prefix them with gen-> or something similar.
417
class FakeXCodeBlock : public FakeXEmitter
424
FakeXCodeBlock() : region(NULL), region_size(0) {}
425
virtual ~FakeXCodeBlock() { if (region) FreeCodeSpace(); }
427
// Call this before you generate any code.
428
void AllocCodeSpace(int size) { }
430
// Always clear code space with breakpoints, so that if someone accidentally executes
431
// uninitialized, it just breaks into the debugger.
432
void ClearCodeSpace() { }
434
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
435
void FreeCodeSpace() { }
437
bool IsInSpace(const u8 *ptr) const
439
return ptr >= region && ptr < region + region_size;
442
// Cannot currently be undone. Will write protect the entire code region.
443
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
444
void WriteProtect() { }
445
void UnWriteProtect() { }
452
size_t GetSpaceLeft() const
454
return region_size - (GetCodePtr() - region);
461
size_t GetOffset(const u8 *ptr) const {
468
#endif // _DOLPHIN_FAKE_CODEGEN_