1 #include "stdafx.h"
2 #include "CMipsInstruction.h"
3 #include "Core/Common.h"
4 #include "Mips.h"
5 #include "MipsOpcodes.h"
6 #include "Core/FileManager.h"
7 #include "MipsParser.h"
8
CMipsInstruction(MipsOpcodeData & opcode,MipsImmediateData & immediate,MipsRegisterData & registers)9 CMipsInstruction::CMipsInstruction(MipsOpcodeData& opcode, MipsImmediateData& immediate, MipsRegisterData& registers)
10 {
11 this->opcodeData = opcode;
12 this->immediateData = immediate;
13 this->registerData = registers;
14
15 addNop = false;
16 IgnoreLoadDelay = Mips.GetIgnoreDelay();
17 }
18
~CMipsInstruction()19 CMipsInstruction::~CMipsInstruction()
20 {
21
22 }
23
getImmediateBits(MipsImmediateType type)24 int getImmediateBits(MipsImmediateType type)
25 {
26 switch (type)
27 {
28 case MipsImmediateType::Immediate5:
29 return 5;
30 case MipsImmediateType::Immediate7:
31 return 7;
32 case MipsImmediateType::Immediate10:
33 return 10;
34 case MipsImmediateType::Immediate16:
35 case MipsImmediateType::ImmediateHalfFloat:
36 return 16;
37 case MipsImmediateType::Immediate20:
38 case MipsImmediateType::Immediate20_0:
39 return 20;
40 case MipsImmediateType::Immediate25:
41 return 25;
42 case MipsImmediateType::Immediate26:
43 return 26;
44 default:
45 return 0;
46 }
47 }
48
49 // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/Allegrex/VfpuState.java?spec=svn3676&r=3383#1196
floatToHalfFloat(int i)50 int CMipsInstruction::floatToHalfFloat(int i)
51 {
52 int s = ((i >> 16) & 0x00008000); // sign
53 int e = ((i >> 23) & 0x000000ff) - (127 - 15); // exponent
54 int f = ((i >> 0) & 0x007fffff); // fraction
55
56 // need to handle NaNs and Inf?
57 if (e <= 0) {
58 if (e < -10) {
59 if (s != 0) {
60 // handle -0.0
61 return 0x8000;
62 }
63 return 0;
64 }
65 f = (f | 0x00800000) >> (1 - e);
66 return s | (f >> 13);
67 } else if (e == 0xff - (127 - 15)) {
68 if (f == 0) {
69 // Inf
70 return s | 0x7c00;
71 }
72 // NAN
73 return s | 0x7fff;
74 }
75
76 if (e > 30) {
77 // Overflow
78 return s | 0x7c00;
79 }
80
81 return s | (e << 10) | (f >> 13);
82 }
83
Validate()84 bool CMipsInstruction::Validate()
85 {
86 bool Result = false;
87
88 bool previousNop = addNop;
89 addNop = false;
90
91 RamPos = g_fileManager->getVirtualAddress();
92 if (RamPos % 4)
93 {
94 Logger::queueError(Logger::Error,L"opcode not aligned to word boundary");
95 return false;
96 }
97
98 // check immediates
99 if (immediateData.primary.type != MipsImmediateType::None)
100 {
101 if (immediateData.primary.expression.isLoaded())
102 {
103 if (immediateData.primary.expression.evaluateInteger(immediateData.primary.value) == false)
104 {
105 Logger::queueError(Logger::Error, L"Invalid immediate expression");
106 return false;
107 }
108
109 immediateData.primary.originalValue = immediateData.primary.value;
110 }
111
112 if (immediateData.primary.type == MipsImmediateType::ImmediateHalfFloat)
113 immediateData.primary.value = floatToHalfFloat(immediateData.primary.originalValue);
114
115 if (opcodeData.opcode.flags & MO_IMMALIGNED) // immediate must be aligned
116 {
117 if (immediateData.primary.value % 4)
118 {
119 Logger::queueError(Logger::Error,L"Immediate must be word aligned");
120 return false;
121 }
122 }
123
124 if (opcodeData.opcode.flags & MO_NEGIMM) // negated immediate
125 {
126 immediateData.primary.value = -immediateData.primary.value;
127 } else if (opcodeData.opcode.flags & MO_IPCA) // absolute value >> 2
128 {
129 immediateData.primary.value = (immediateData.primary.value >> 2) & 0x3FFFFFF;
130 } else if (opcodeData.opcode.flags & MO_IPCR) // relative 16 bit value
131 {
132 int num = (int) (immediateData.primary.value-RamPos-4);
133
134 if (num > 0x20000 || num < (-0x20000))
135 {
136 Logger::queueError(Logger::Error,L"Branch target %08X out of range",immediateData.primary.value);
137 return false;
138 }
139 immediateData.primary.value = num >> 2;
140 } else if (opcodeData.opcode.flags & (MO_RSP_HWOFFSET | MO_RSP_WOFFSET | MO_RSP_DWOFFSET | MO_RSP_QWOFFSET))
141 {
142 int shift = 0;
143
144 if (opcodeData.opcode.flags & MO_RSP_HWOFFSET) shift = 1;
145 else if (opcodeData.opcode.flags & MO_RSP_WOFFSET) shift = 2;
146 else if (opcodeData.opcode.flags & MO_RSP_DWOFFSET) shift = 3;
147 else if (opcodeData.opcode.flags & MO_RSP_QWOFFSET) shift = 4;
148
149 if (immediateData.primary.value & ((1 << shift) - 1))
150 {
151 Logger::queueError(Logger::Error,L"Offset must be %d-byte aligned",1<<shift);
152 return false;
153 }
154 immediateData.primary.value = immediateData.primary.value >> shift;
155 }
156
157 int immediateBits = getImmediateBits(immediateData.primary.type);
158 unsigned int mask = (0xFFFFFFFF << (32-immediateBits)) >> (32-immediateBits);
159 int digits = (immediateBits+3) / 4;
160
161 if ((unsigned int)std::abs(immediateData.primary.value) > mask)
162 {
163 Logger::queueError(Logger::Error,L"Immediate value 0x%0*X out of range",digits,immediateData.primary.value);
164 return false;
165 }
166
167 immediateData.primary.value &= mask;
168 }
169
170 if (immediateData.secondary.type != MipsImmediateType::None)
171 {
172 if (immediateData.secondary.expression.isLoaded())
173 {
174 if (immediateData.secondary.expression.evaluateInteger(immediateData.secondary.value) == false)
175 {
176 Logger::queueError(Logger::Error, L"Invalid immediate expression");
177 return false;
178 }
179
180 immediateData.secondary.originalValue = immediateData.secondary.value;
181 }
182
183 switch (immediateData.secondary.type)
184 {
185 case MipsImmediateType::CacheOp:
186 if ((unsigned int)immediateData.secondary.value > 0x1f)
187 {
188 Logger::queueError(Logger::Error,L"Immediate value %02X out of range",immediateData.secondary.value);
189 return false;
190 }
191 break;
192 case MipsImmediateType::Ext:
193 case MipsImmediateType::Ins:
194 if (immediateData.secondary.value > 32 || immediateData.secondary.value == 0)
195 {
196 Logger::queueError(Logger::Error,L"Immediate value %02X out of range",immediateData.secondary.value);
197 return false;
198 }
199
200 immediateData.secondary.value--;
201 if (immediateData.secondary.type == MipsImmediateType::Ins)
202 immediateData.secondary.value += immediateData.primary.value;
203 break;
204 case MipsImmediateType::Cop2BranchType:
205 default:
206 break;
207 }
208 }
209
210 // check load delay
211 if (Mips.hasLoadDelay() && Mips.GetLoadDelay() && IgnoreLoadDelay == false)
212 {
213 bool fix = false;
214
215 if (registerData.grd.num != -1 && registerData.grd.num == Mips.GetLoadDelayRegister())
216 {
217 Logger::queueError(Logger::Warning,L"register %S may not be available due to load delay",registerData.grd.name);
218 fix = true;
219 } else if (registerData.grs.num != -1 && registerData.grs.num == Mips.GetLoadDelayRegister())
220 {
221 Logger::queueError(Logger::Warning,L"register %S may not be available due to load delay",registerData.grs.name);
222 fix = true;
223 } else if (registerData.grt.num != -1 && registerData.grt.num == Mips.GetLoadDelayRegister()
224 && !(opcodeData.opcode.flags & MO_IGNORERTD))
225 {
226 Logger::queueError(Logger::Warning,L"register %S may not be available due to load delay",registerData.grt.name);
227 fix = true;
228 }
229
230 if (Mips.GetFixLoadDelay() == true && fix == true)
231 {
232 addNop = true;
233 Logger::queueError(Logger::Notice,L"added nop to ensure correct behavior");
234 }
235 }
236
237 if ((opcodeData.opcode.flags & MO_NODELAYSLOT) && Mips.GetDelaySlot() == true && IgnoreLoadDelay == false)
238 {
239 Logger::queueError(Logger::Error,L"This instruction can't be in a delay slot");
240 }
241
242 Mips.SetDelaySlot(opcodeData.opcode.flags & MO_DELAY ? true : false);
243
244 // now check if this opcode causes a load delay
245 if (Mips.hasLoadDelay())
246 Mips.SetLoadDelay(opcodeData.opcode.flags & MO_DELAYRT ? true : false,registerData.grt.num);
247
248 if (previousNop != addNop)
249 Result = true;
250
251 g_fileManager->advanceMemory(addNop ? 8 : 4);
252 return Result;
253 }
254
encodeNormal() const255 void CMipsInstruction::encodeNormal() const
256 {
257 int encoding = opcodeData.opcode.destencoding;
258
259 if (registerData.grs.num != -1) encoding |= MIPS_RS(registerData.grs.num); // source reg
260 if (registerData.grt.num != -1) encoding |= MIPS_RT(registerData.grt.num); // target reg
261 if (registerData.grd.num != -1) encoding |= MIPS_RD(registerData.grd.num); // dest reg
262
263 if (registerData.frt.num != -1) encoding |= MIPS_FT(registerData.frt.num); // float target reg
264 if (registerData.frs.num != -1) encoding |= MIPS_FS(registerData.frs.num); // float source reg
265 if (registerData.frd.num != -1) encoding |= MIPS_FD(registerData.frd.num); // float dest reg
266
267 if (registerData.ps2vrt.num != -1) encoding |= (registerData.ps2vrt.num << 16); // ps2 vector target reg
268 if (registerData.ps2vrs.num != -1) encoding |= (registerData.ps2vrs.num << 21); // ps2 vector source reg
269 if (registerData.ps2vrd.num != -1) encoding |= (registerData.ps2vrd.num << 6); // ps2 vector dest reg
270
271 if (registerData.rspvrt.num != -1) encoding |= MIPS_FT(registerData.rspvrt.num); // rsp vector target reg
272 if (registerData.rspvrs.num != -1) encoding |= MIPS_FS(registerData.rspvrs.num); // rsp vector source reg
273 if (registerData.rspvrd.num != -1) encoding |= MIPS_FD(registerData.rspvrd.num); // rsp vector dest reg
274
275 if (registerData.rspve.num != -1) encoding |= MIPS_RSP_VE(registerData.rspve.num); // rsp element
276 if (registerData.rspvde.num != -1) encoding |= MIPS_RSP_VDE(registerData.rspvde.num); // rsp destination element
277 if (registerData.rspvealt.num != -1) encoding |= MIPS_RSP_VEALT(registerData.rspvealt.num); // rsp element (alt. placement)
278
279 if (!(opcodeData.opcode.flags & MO_VFPU_MIXED) && registerData.vrt.num != -1) // vfpu rt
280 encoding |= registerData.vrt.num << 16;
281
282 switch (immediateData.primary.type)
283 {
284 case MipsImmediateType::Immediate5:
285 case MipsImmediateType::Immediate10:
286 case MipsImmediateType::Immediate20:
287 encoding |= immediateData.primary.value << 6;
288 break;
289 case MipsImmediateType::Immediate16:
290 case MipsImmediateType::Immediate25:
291 case MipsImmediateType::Immediate26:
292 case MipsImmediateType::Immediate20_0:
293 case MipsImmediateType::Immediate7:
294 case MipsImmediateType::ImmediateHalfFloat:
295 encoding |= immediateData.primary.value;
296 break;
297 default:
298 // TODO: Assert?
299 break;
300 }
301
302 switch (immediateData.secondary.type)
303 {
304 case MipsImmediateType::CacheOp:
305 encoding |= immediateData.secondary.value << 16;
306 break;
307 case MipsImmediateType::Ext:
308 case MipsImmediateType::Ins:
309 encoding |= immediateData.secondary.value << 11;
310 break;
311 case MipsImmediateType::Cop2BranchType:
312 encoding |= immediateData.secondary.value << 18;
313 break;
314 default:
315 // TODO: Assert?
316 break;
317 }
318
319 if (opcodeData.opcode.flags & MO_VFPU_MIXED)
320 {
321 // always vrt
322 encoding |= registerData.vrt.num >> 5;
323 encoding |= (registerData.vrt.num & 0x1F) << 16;
324 }
325
326 g_fileManager->writeU32((uint32_t)encoding);
327 }
328
encodeVfpu() const329 void CMipsInstruction::encodeVfpu() const
330 {
331 int encoding = opcodeData.opcode.destencoding;
332
333 if (opcodeData.vectorCondition != -1) encoding |= (opcodeData.vectorCondition << 0);
334 if (registerData.vrd.num != -1) encoding |= (registerData.vrd.num << 0);
335 if (registerData.vrs.num != -1) encoding |= (registerData.vrs.num << 8);
336 if (registerData.vrt.num != -1) encoding |= (registerData.vrt.num << 16);
337 if (opcodeData.vfpuSize != -1 && (opcodeData.opcode.flags & (MO_VFPU_PAIR|MO_VFPU_SINGLE|MO_VFPU_TRIPLE|MO_VFPU_QUAD)) == 0)
338 {
339 if (opcodeData.vfpuSize & 1) encoding |= (1 << 7);
340 if (opcodeData.vfpuSize & 2) encoding |= (1 << 15);
341 }
342
343 if (registerData.grt.num != -1) encoding |= (registerData.grt.num << 16);
344
345 switch (immediateData.primary.type)
346 {
347 case MipsImmediateType::Immediate5:
348 encoding |= immediateData.primary.value << 16;
349 break;
350 case MipsImmediateType::Immediate7:
351 encoding |= immediateData.primary.value << 0;
352 break;
353 default:
354 // TODO: Assert?
355 break;
356 }
357
358 g_fileManager->writeU32((uint32_t)encoding);
359 }
360
Encode() const361 void CMipsInstruction::Encode() const
362 {
363 if (addNop)
364 g_fileManager->writeU32(0);
365
366 if (opcodeData.opcode.flags & MO_VFPU)
367 encodeVfpu();
368 else
369 encodeNormal();
370 }
371
writeTempData(TempData & tempData) const372 void CMipsInstruction::writeTempData(TempData& tempData) const
373 {
374 MipsOpcodeFormatter formatter;
375 tempData.writeLine(RamPos,formatter.formatOpcode(opcodeData,registerData,immediateData));
376 }
377