1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /***************************************************************************
4 
5     arm7fe.c
6 
7     Front-end for ARM7 DRC
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "arm7.h"
13 
14 
15 //**************************************************************************
16 //  ARM7 FRONTEND
17 //**************************************************************************
18 
19 // register flags 0
20 #define REGFLAG_R(n)                    (((n) == 0) ? 0 : (1 << (n)))
21 
22 //-------------------------------------------------
23 //  arm7_frontend - constructor
24 //-------------------------------------------------
25 
arm7_frontend(arm7_cpu_device * arm7,uint32_t window_start,uint32_t window_end,uint32_t max_sequence)26 arm7_frontend::arm7_frontend(arm7_cpu_device *arm7, uint32_t window_start, uint32_t window_end, uint32_t max_sequence)
27 	: drc_frontend(*arm7, window_start, window_end, max_sequence),
28 		m_arm7(arm7)
29 {
30 }
31 
32 
33 //-------------------------------------------------
34 //  describe_thumb - build a description of a
35 //  thumb instruction
36 //-------------------------------------------------
37 
describe_thumb(opcode_desc & desc,const opcode_desc * prev)38 bool arm7_frontend::describe_thumb(opcode_desc &desc, const opcode_desc *prev)
39 {
40 	return false;
41 }
42 
43 //-------------------------------------------------
44 //  describe_ops_* - build a description of
45 //  an ARM7 instruction
46 //-------------------------------------------------
47 
describe_ops_0123(opcode_desc & desc,const opcode_desc * prev,uint32_t op)48 bool arm7_frontend::describe_ops_0123(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
49 {
50 	/* Branch and Exchange (BX) */
51 	if ((op & 0x0ffffff0) == 0x012fff10) // BX
52 	{
53 	}
54 	else if ((op & 0x0ff000f0) == 0x01600010) // CLZ - v5
55 	{
56 	}
57 	else if ((op & 0x0ff000f0) == 0x01000050) // QADD - v5
58 	{
59 	}
60 	else if ((op & 0x0ff000f0) == 0x01400050) // QDADD - v5
61 	{
62 	}
63 	else if ((op & 0x0ff000f0) == 0x01200050) // QSUB - v5
64 	{
65 	}
66 	else if ((op & 0x0ff000f0) == 0x01600050) // QDSUB - v5
67 	{
68 	}
69 	else if ((op & 0x0ff00090) == 0x01000080) // SMLAxy - v5
70 	{
71 	}
72 	else if ((op & 0x0ff00090) == 0x01400080) // SMLALxy - v5
73 	{
74 	}
75 	else if ((op & 0x0ff00090) == 0x01600080) // SMULxy - v5
76 	{
77 	}
78 	else if ((op & 0x0ff000b0) == 0x012000a0) // SMULWy - v5
79 	{
80 	}
81 	else if ((op & 0x0ff000b0) == 0x01200080) // SMLAWy - v5
82 	{
83 	}
84 	else if ((op & 0x0e000000) == 0 && (op & 0x80) && (op & 0x10)) // Multiply OR Swap OR Half Word Data Transfer
85 	{
86 		if (op & 0x60) // Half Word Data Transfer
87 		{
88 			//HandleHalfWordDT(op);
89 		}
90 		else if (op & 0x01000000) // Swap
91 		{
92 			//HandleSwap(op);
93 		}
94 		else // Multiply Or Multiply Long
95 		{
96 			if (op & 0x800000) // Multiply long
97 			{
98 				if (op & 0x00400000) // Signed multiply
99 				{
100 					//HandleSMulLong(op);
101 				}
102 				else // Unsigned multiply
103 				{
104 					//HandleUMulLong(op);
105 				}
106 			}
107 			else // Multiply
108 			{
109 				//HandleMul(op);//
110 			}
111 		}
112 	}
113 	else if ((op & 0x0c000000) == 0) // Data Processing OR PSR Transfer
114 	{
115 		if (((op & 0x00100000) == 0) && ((op & 0x01800000) == 0x01000000)) // PSR Transfer
116 
117 		{
118 			//HandlePSRTransfer(insn);
119 			desc.cycles = 1;
120 		}
121 		else // Data processing
122 		{
123 			//HandleALU(insn);
124 		}
125 	}
126 	return true;
127 }
128 
describe_ops_4567(opcode_desc & desc,const opcode_desc * prev,uint32_t op)129 bool arm7_frontend::describe_ops_4567(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
130 {
131 	if (op & INSN_I)
132 	{
133 		/* Register Shift */
134 		//off = decodeShift(op, nullptr);
135 	}
136 	else
137 	{
138 		/* Immediate Value */
139 		//off = op & INSN_SDT_IMM;
140 	}
141 
142 	uint32_t rn = (op & INSN_RN) >> INSN_RN_SHIFT;
143 
144 	if (op & INSN_SDT_P)
145 	{
146 		/* Pre-indexed addressing */
147 		if ((get_mode32()) || (rn != eR15))
148 		{
149 			//rnv = (GetRegister(rn) + off);
150 		}
151 		else
152 		{
153 			//rnv = (GET_PC + off);
154 		}
155 
156 		if (op & INSN_SDT_W)
157 		{
158 			//rnv_old = GetRegister(rn);
159 			//SetRegister(rn, rnv);
160 		}
161 		else if (rn == eR15)
162 		{
163 			//rnv = rnv + 8;
164 		}
165 	}
166 	else
167 	{
168 		/* Post-indexed addressing */
169 		if (rn == eR15)
170 		{
171 			if (get_mode32())
172 			{
173 				//rnv = R15 + 8;
174 			}
175 			else
176 			{
177 				//rnv = GET_PC + 8;
178 			}
179 		}
180 		else
181 		{
182 			//rnv = GetRegister(rn);
183 		}
184 	}
185 
186 	/* Do the transfer */
187 	uint32_t rd = (op & INSN_RD) >> INSN_RD_SHIFT;
188 	if (op & INSN_SDT_L)
189 	{
190 		/* Load */
191 		if (op & INSN_SDT_B)
192 		{
193 			//uint32_t data = READ8(rnv);
194 			//SetRegister(rd, data);
195 		}
196 		else
197 		{
198 			//uint32_t data = READ32(rnv);
199 			if (rd == eR15)
200 			{
201 				//R15 = data - 4;
202 				// LDR, PC takes 2S + 2N + 1I (5 total cycles)
203 				desc.cycles = 5;
204 			}
205 			else
206 			{
207 				//SetRegister(rd, data);
208 			}
209 		}
210 	}
211 	else
212 	{
213 		/* Store */
214 		if (op & INSN_SDT_B)
215 		{
216 			//WRITE8(rnv, (uint8_t) GetRegister(rd) & 0xffu);
217 		}
218 		else
219 		{
220 			//WRITE32(rnv, rd == eR15 ? R15 + 8 + 4 : GetRegister(rd)); // manual says STR rd = PC, +12
221 		}
222 		// Store takes only 2 N Cycles, so add + 1
223 		desc.cycles = 2;
224 	}
225 
226 	/* Do post-indexing writeback */
227 	if (!(op & INSN_SDT_P)/* && (insn & INSN_SDT_W)*/)
228 	{
229 		if (rd == rn) {
230 			//SetRegister(rn, GetRegister(rd));
231 		}
232 		else {
233 			//SetRegister(rn, (rnv +/- off));
234 		}
235 	}
236 	return true;
237 }
238 
describe_ops_89(opcode_desc & desc,const opcode_desc * prev,uint32_t op)239 bool arm7_frontend::describe_ops_89(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
240 {
241 	if ((op & 0x005f0f00) == 0x004d0500)
242 	{
243 		// unsupported (armv6 onwards only)
244 		//arm9ops_undef(insn);
245 		//R15 += 4;
246 	}
247 	else if ((op & 0x00500f00) == 0x00100a00) /* Return From Exception (RFE) */
248 	{
249 		// unsupported (armv6 onwards only)
250 		//arm9ops_undef(insn);
251 		//R15 += 4;
252 	}
253 	else
254 	{
255 		//arm9ops_undef(insn);
256 		//R15 += 4;
257 	}
258 	return false;
259 }
260 
describe_ops_ab(opcode_desc & desc,const opcode_desc * prev,uint32_t op)261 bool arm7_frontend::describe_ops_ab(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
262 {
263 	// BLX
264 	//HandleBranch(insn, true);
265 	//set_cpsr(GET_CPSR|T_MASK);
266 	return true;
267 }
268 
describe_ops_cd(opcode_desc & desc,const opcode_desc * prev,uint32_t op)269 bool arm7_frontend::describe_ops_cd(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
270 {
271 	/* Additional coprocessor double register transfer */
272 	if ((op & 0x00e00000) == 0x00400000)
273 	{
274 		// unsupported
275 		//arm9ops_undef(insn);
276 		//R15 += 4;
277 	}
278 	else
279 	{
280 		//arm9ops_undef(insn);
281 		//R15 += 4;
282 	}
283 	return false;
284 }
285 
describe_ops_e(opcode_desc & desc,const opcode_desc * prev,uint32_t op)286 bool arm7_frontend::describe_ops_e(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
287 {
288 	/* Additional coprocessor register transfer */
289 	// unsupported
290 	//arm9ops_undef(insn);
291 	//R15 += 4;
292 	return false;
293 }
294 
describe_ops_f(opcode_desc & desc,const opcode_desc * prev,uint32_t op)295 bool arm7_frontend::describe_ops_f(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
296 {
297 	return false;
298 }
299 
300 //-------------------------------------------------
301 //  describe_arm9_ops_* - build a description of
302 //  an ARM9 instruction
303 //-------------------------------------------------
304 
describe_arm9_ops_1(opcode_desc & desc,const opcode_desc * prev,uint32_t op)305 bool describe_arm9_ops_1(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
306 {
307 	/* Change processor state (CPS) */
308 	if ((op & 0x00f10020) == 0x00000000)
309 	{
310 		// unsupported (armv6 onwards only)
311 		//arm9ops_undef(insn);
312 		//R15 += 4;
313 	}
314 	else if ((op & 0x00ff00f0) == 0x00010000) /* set endianness (SETEND) */
315 	{
316 		// unsupported (armv6 onwards only)
317 		//arm9ops_undef(insn);
318 		//R15 += 4;
319 	}
320 	else
321 	{
322 		//arm9ops_undef(insn);
323 		//R15 += 4;
324 	}
325 	return false;
326 }
327 
describe_arm9_ops_57(opcode_desc & desc,const opcode_desc * prev,uint32_t op)328 bool describe_arm9_ops_57(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
329 {
330 	/* Cache Preload (PLD) */
331 	if ((op & 0x0070f000) == 0x0050f000)
332 	{
333 		// unsupported (armv6 onwards only)
334 		//arm9ops_undef(insn);
335 		//R15 += 4;
336 	}
337 	else
338 	{
339 		//arm9ops_undef(insn);
340 		//R15 += 4;
341 	}
342 	return false;
343 }
344 
describe_arm9_ops_89(opcode_desc & desc,const opcode_desc * prev,uint32_t op)345 bool describe_arm9_ops_89(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
346 {
347 	return false;
348 }
349 
describe_arm9_ops_ab(opcode_desc & desc,const opcode_desc * prev,uint32_t op)350 bool describe_arm9_ops_ab(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
351 {
352 	return false;
353 }
354 
describe_arm9_ops_c(opcode_desc & desc,const opcode_desc * prev,uint32_t op)355 bool describe_arm9_ops_c(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
356 {
357 	return false;
358 }
359 
describe_arm9_ops_e(opcode_desc & desc,const opcode_desc * prev,uint32_t op)360 bool describe_arm9_ops_e(opcode_desc &desc, const opcode_desc *prev, uint32_t op)
361 {
362 	return false;
363 }
364 
365 
get_cpsr()366 uint32_t arm7_frontend::get_cpsr()
367 {
368 	return m_arm7->m_r[eCPSR];
369 }
370 
get_mode32()371 bool arm7_frontend::get_mode32()
372 {
373 	return m_arm7->m_r[eCPSR] & SR_MODE32;
374 }
375 
376 //-------------------------------------------------
377 //  describe - build a description of a single
378 //  instruction
379 //-------------------------------------------------
380 
describe(opcode_desc & desc,const opcode_desc * prev)381 bool arm7_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
382 {
383 	// compute the physical PC
384 	const uint32_t cpsr = get_cpsr();
385 	assert((desc.physpc & (T_IS_SET(cpsr) ? 1 : 3)) == 0);
386 	if (!m_arm7->arm7_tlb_translate(desc.physpc, ARM7_TLB_ABORT_P | ARM7_TLB_READ))
387 	{
388 		// uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and
389 		// mark as needing to validate; otherwise, just end the sequence here
390 		desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE;
391 		return true;
392 	}
393 
394 	if (T_IS_SET(cpsr))
395 	{
396 		return describe_thumb(desc, prev);
397 	}
398 
399 	// fetch the opcode
400 	uint32_t op = desc.opptr.l[0] = m_arm7->m_direct->read_dword(desc.physpc);
401 
402 	// all non-THUMB instructions are 4 bytes and default to 3 cycles each
403 	desc.length = 4;
404 	desc.cycles = 3;
405 
406 	// parse the instruction
407 
408 	int op_offset = 0;
409 	if ((op >> INSN_COND_SHIFT) == COND_NV && m_arm7->m_archRev >= 5)
410 	{
411 		op_offset = 0x10;
412 	}
413 
414 	switch (((op & 0xF000000) >> 24) + op_offset)
415 	{
416 		case 0x0: case 0x1: case 0x2: case 0x3:
417 			return describe_ops_0123(desc, prev, op);
418 
419 		case 0x4: case 0x5: case 0x6: case 0x7:
420 			return describe_ops_4567(desc, prev, op);
421 
422 		case 0x8: case 0x9:
423 			return describe_ops_89(desc, prev, op);
424 
425 		case 0xa: case 0xb:
426 			return describe_ops_ab(desc, prev, op);
427 
428 		case 0xc: case 0xd:
429 			return describe_ops_cd(desc, prev, op);
430 
431 		case 0xe:
432 			return describe_ops_e(desc, prev, op);
433 
434 		case 0xf:
435 			return describe_ops_f(desc, prev, op);
436 
437 		case 0x11: // ARM9
438 			return describe_arm9_ops_1(desc, prev, op);
439 
440 		case 0x15: case 0x17: // ARM9
441 			return describe_arm9_ops_57(desc, prev, op);
442 
443 		case 0x18: case 0x19: // ARM9
444 			return describe_arm9_ops_89(desc, prev, op);
445 
446 		case 0x1a: case 0x1b: // ARM9
447 			return describe_arm9_ops_ab(desc, prev, op);
448 
449 		case 0x1c: // ARM9
450 			return describe_arm9_ops_c(desc, prev, op);
451 
452 		case 0x1e: // ARM9
453 			return describe_arm9_ops_e(desc, prev, op);
454 
455 		default:
456 			return false;
457 	}
458 }
459