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