CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/MIPS/IR/IRCompFPU.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
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 or later versions.
6
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.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Core/Config.h"
19
#include "Core/MemMap.h"
20
#include "Core/MIPS/MIPS.h"
21
#include "Core/MIPS/MIPSCodeUtils.h"
22
#include "Core/MIPS/MIPSTables.h"
23
24
#include "Core/MIPS/IR/IRFrontend.h"
25
#include "Core/MIPS/IR/IRRegCache.h"
26
#include "Common/CPUDetect.h"
27
28
#define _RS MIPS_GET_RS(op)
29
#define _RT MIPS_GET_RT(op)
30
#define _RD MIPS_GET_RD(op)
31
#define _FS MIPS_GET_FS(op)
32
#define _FT MIPS_GET_FT(op)
33
#define _FD MIPS_GET_FD(op)
34
#define _SA MIPS_GET_SA(op)
35
#define _POS ((op>> 6) & 0x1F)
36
#define _SIZE ((op>>11) & 0x1F)
37
#define _IMM16 (signed short)(op & 0xFFFF)
38
#define _IMM26 (op & 0x03FFFFFF)
39
40
41
// FPCR interesting bits:
42
// 24: FZ (flush-to-zero)
43
// 23:22: RMode (0 = nearest, 1 = +inf, 2 = -inf, 3 = zero)
44
// not much else is interesting for us, but should be preserved.
45
// To access: MRS Xt, FPCR ; MSR FPCR, Xt
46
47
48
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
49
// Currently known non working ones should have DISABLE.
50
51
// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }
52
#define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; }
53
#define DISABLE { Comp_Generic(op); return; }
54
#define INVALIDOP { Comp_Generic(op); return; }
55
56
namespace MIPSComp {
57
58
void IRFrontend::Comp_FPU3op(MIPSOpcode op) {
59
CONDITIONAL_DISABLE(FPU);
60
61
int ft = _FT;
62
int fs = _FS;
63
int fd = _FD;
64
65
switch (op & 0x3f) {
66
case 0: ir.Write(IROp::FAdd, fd, fs, ft); break; //F(fd) = F(fs) + F(ft); //add
67
case 1: ir.Write(IROp::FSub, fd, fs, ft); break; //F(fd) = F(fs) - F(ft); //sub
68
case 2: ir.Write(IROp::FMul, fd, fs, ft); break; //F(fd) = F(fs) * F(ft); //mul
69
case 3: ir.Write(IROp::FDiv, fd, fs, ft); break; //F(fd) = F(fs) / F(ft); //div
70
default:
71
INVALIDOP;
72
return;
73
}
74
}
75
76
void IRFrontend::Comp_FPULS(MIPSOpcode op) {
77
CONDITIONAL_DISABLE(LSU_FPU);
78
s32 offset = _IMM16;
79
int ft = _FT;
80
MIPSGPReg rs = _RS;
81
82
CheckMemoryBreakpoint(rs, offset);
83
84
switch (op >> 26) {
85
case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1
86
ir.Write(IROp::LoadFloat, ft, rs, ir.AddConstant(offset));
87
break;
88
89
case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1
90
ir.Write(IROp::StoreFloat, ft, rs, ir.AddConstant(offset));
91
break;
92
93
default:
94
INVALIDOP;
95
break;
96
}
97
}
98
99
void IRFrontend::Comp_FPUComp(MIPSOpcode op) {
100
CONDITIONAL_DISABLE(FPU_COMP);
101
102
int opc = op & 0xF;
103
if (opc >= 8) opc -= 8; // alias
104
if (opc == 0) { // f, sf (signalling false)
105
ir.Write(IROp::FpCondFromReg, 0, MIPS_REG_ZERO);
106
return;
107
}
108
109
int fs = _FS;
110
int ft = _FT;
111
IRFpCompareMode mode;
112
switch (opc) {
113
case 1: // un, ngle (unordered)
114
mode = IRFpCompareMode::EitherUnordered;
115
break;
116
case 2: // eq, seq (equal, ordered)
117
mode = IRFpCompareMode::EqualOrdered;
118
break;
119
case 3: // ueq, ngl (equal, unordered)
120
mode = IRFpCompareMode::EqualUnordered;
121
break;
122
case 4: // olt, lt (less than, ordered)
123
mode = IRFpCompareMode::LessOrdered;
124
break;
125
case 5: // ult, nge (less than, unordered)
126
mode = IRFpCompareMode::LessUnordered;
127
break;
128
case 6: // ole, le (less equal, ordered)
129
mode = IRFpCompareMode::LessEqualOrdered;
130
break;
131
case 7: // ule, ngt (less equal, unordered)
132
mode = IRFpCompareMode::LessEqualUnordered;
133
break;
134
default:
135
INVALIDOP;
136
return;
137
}
138
ir.Write(IROp::FCmp, (int)mode, fs, ft);
139
}
140
141
void IRFrontend::Comp_FPU2op(MIPSOpcode op) {
142
CONDITIONAL_DISABLE(FPU);
143
144
int fs = _FS;
145
int fd = _FD;
146
147
switch (op & 0x3f) {
148
case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt
149
ir.Write(IROp::FSqrt, fd, fs);
150
break;
151
case 5: //F(fd) = fabsf(F(fs)); break; //abs
152
ir.Write(IROp::FAbs, fd, fs);
153
break;
154
case 6: //F(fd) = F(fs); break; //mov
155
if (fd != fs)
156
ir.Write(IROp::FMov, fd, fs);
157
break;
158
case 7: //F(fd) = -F(fs); break; //neg
159
ir.Write(IROp::FNeg, fd, fs);
160
break;
161
162
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
163
ir.Write(IROp::FRound, fd, fs);
164
break;
165
case 13: //FsI(fd) = Rto0(F(fs))); break; //trunc.w.s
166
ir.Write(IROp::FTrunc, fd, fs);
167
break;
168
case 14://FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
169
ir.Write(IROp::FCeil, fd, fs);
170
break;
171
case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s
172
ir.Write(IROp::FFloor, fd, fs);
173
break;
174
175
case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w
176
ir.Write(IROp::FCvtSW, fd, fs);
177
break;
178
179
case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s
180
ir.Write(IROp::FCvtWS, fd, fs);
181
break;
182
183
default:
184
INVALIDOP;
185
}
186
}
187
188
void IRFrontend::Comp_mxc1(MIPSOpcode op) {
189
CONDITIONAL_DISABLE(FPU_XFER);
190
191
int fs = _FS;
192
MIPSGPReg rt = _RT;
193
194
switch ((op >> 21) & 0x1f) {
195
case 0: // R(rt) = FI(fs); break; //mfc1
196
if (rt == MIPS_REG_ZERO) {
197
return;
198
}
199
ir.Write(IROp::FMovToGPR, rt, fs);
200
return;
201
202
case 2: //cfc1
203
if (rt == MIPS_REG_ZERO) {
204
return;
205
}
206
if (fs == 31) {
207
// This needs to insert fpcond.
208
ir.Write(IROp::FpCtrlToReg, rt);
209
} else if (fs == 0) {
210
ir.Write(IROp::SetConst, rt, ir.AddConstant(MIPSState::FCR0_VALUE));
211
} else {
212
// Unsupported regs are always 0.
213
ir.Write(IROp::SetConst, rt, ir.AddConstant(0));
214
}
215
return;
216
217
case 4: //FI(fs) = R(rt); break; //mtc1
218
ir.Write(IROp::FMovFromGPR, fs, rt);
219
return;
220
221
case 6: //ctc1
222
if (fs == 31) {
223
// Set rounding mode
224
RestoreRoundingMode();
225
ir.Write(IROp::FpCtrlFromReg, 0, rt);
226
// TODO: Do the UpdateRoundingMode check at runtime?
227
UpdateRoundingMode();
228
ApplyRoundingMode();
229
} else {
230
// Maybe not strictly invalid? But likely invalid.
231
INVALIDOP;
232
}
233
return;
234
default:
235
INVALIDOP;
236
break;
237
}
238
}
239
240
} // namespace MIPSComp
241
242