/[gxemul]/trunk/src/cpus/cpu_arm_instr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpus/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 49891 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_arm_instr.c,v 1.26 2005/10/07 22:10:51 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (If no instruction was executed, then it should be decreased. If, say, 4
34 * instructions were combined into one function and executed, then it should
35 * be increased by 3.)
36 */
37
38
39 /*
40 * Helper definitions:
41 *
42 * Each instruction is defined like this:
43 *
44 * X(foo)
45 * {
46 * code for foo;
47 * }
48 * Y(foo)
49 *
50 * The Y macro defines 14 copies of the instruction, one for each possible
51 * condition code. (The NV condition code is not included, and the AL code
52 * uses the main foo function.) Y also defines an array with pointers to
53 * all of these functions.
54 */
55
56 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
57 struct arm_instr_call *ic) \
58 { if (cpu->cd.arm.cpsr & ARM_FLAG_Z) \
59 arm_instr_ ## n (cpu, ic); } \
60 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
61 struct arm_instr_call *ic) \
62 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
63 arm_instr_ ## n (cpu, ic); } \
64 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
65 struct arm_instr_call *ic) \
66 { if (cpu->cd.arm.cpsr & ARM_FLAG_C) \
67 arm_instr_ ## n (cpu, ic); } \
68 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
69 struct arm_instr_call *ic) \
70 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_C)) \
71 arm_instr_ ## n (cpu, ic); } \
72 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
73 struct arm_instr_call *ic) \
74 { if (cpu->cd.arm.cpsr & ARM_FLAG_N) \
75 arm_instr_ ## n (cpu, ic); } \
76 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
77 struct arm_instr_call *ic) \
78 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_N)) \
79 arm_instr_ ## n (cpu, ic); } \
80 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
81 struct arm_instr_call *ic) \
82 { if (cpu->cd.arm.cpsr & ARM_FLAG_V) \
83 arm_instr_ ## n (cpu, ic); } \
84 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
85 struct arm_instr_call *ic) \
86 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_V)) \
87 arm_instr_ ## n (cpu, ic); } \
88 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
89 struct arm_instr_call *ic) \
90 { if (cpu->cd.arm.cpsr & ARM_FLAG_C && \
91 !(cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
92 arm_instr_ ## n (cpu, ic); } \
93 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
94 struct arm_instr_call *ic) \
95 { if (cpu->cd.arm.cpsr & ARM_FLAG_Z || \
96 !(cpu->cd.arm.cpsr & ARM_FLAG_C)) \
97 arm_instr_ ## n (cpu, ic); } \
98 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
99 struct arm_instr_call *ic) \
100 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == \
101 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) \
102 arm_instr_ ## n (cpu, ic); } \
103 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
104 struct arm_instr_call *ic) \
105 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != \
106 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) \
107 arm_instr_ ## n (cpu, ic); } \
108 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
109 struct arm_instr_call *ic) \
110 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == \
111 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) && \
112 !(cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
113 arm_instr_ ## n (cpu, ic); } \
114 void arm_instr_ ## n ## __le(struct cpu *cpu, \
115 struct arm_instr_call *ic) \
116 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != \
117 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) || \
118 (cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
119 arm_instr_ ## n (cpu, ic); } \
120 void (*arm_cond_instr_ ## n [16])(struct cpu *, \
121 struct arm_instr_call *) = { \
122 arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
123 arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
124 arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
125 arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
126 arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
127 arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
128 arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
129 arm_instr_ ## n , arm_instr_nop };
130
131 #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
132
133
134 /*****************************************************************************/
135
136 /*
137 * update_c is set if the C flag should be updated with the last shifted/
138 * rotated bit.
139 */
140 uint32_t R(struct cpu *cpu, struct arm_instr_call *ic,
141 uint32_t iword, int update_c)
142 {
143 int rm = iword & 15, lastbit, t, c;
144 uint32_t tmp = cpu->cd.arm.r[rm];
145
146 if ((iword & 0xff0)==0 && rm != ARM_PC)
147 return tmp;
148
149 t = (iword >> 4) & 7;
150 c = (iword >> 7) & 31;
151 lastbit = 0;
152
153 if (rm == ARM_PC) {
154 /* Calculate tmp from this instruction's PC + 8 */
155 uint32_t low_pc = ((size_t)ic - (size_t)
156 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
157 tmp &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
158 ARM_INSTR_ALIGNMENT_SHIFT);
159 tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
160 tmp += 8;
161 }
162
163 if ((iword & 0xff0)==0 && rm == ARM_PC)
164 return tmp;
165
166 if ((t & 1) && (c >> 1) == ARM_PC) {
167 fatal("TODO: R: rc = PC\n");
168 exit(1);
169 }
170
171 switch (t) {
172 case 0: /* lsl #c (c = 0..31) */
173 if (update_c) {
174 if (c == 0)
175 update_c = 0;
176 else
177 lastbit = (tmp << (c-1)) & 0x80000000;
178 }
179 tmp <<= c;
180 break;
181 case 1: /* lsl Rc */
182 c = cpu->cd.arm.r[c >> 1] & 255;
183 if (c >= 32)
184 c = 33;
185 if (update_c) {
186 if (c == 0)
187 update_c = 0;
188 else
189 lastbit = ((uint64_t)tmp << (c-1)) & 0x80000000;
190 }
191 tmp = (uint64_t)tmp << c;
192 break;
193 case 2: /* lsr #c (c = 1..32) */
194 if (c == 0)
195 c = 32;
196 if (update_c) {
197 lastbit = ((uint64_t)tmp >> (c-1)) & 1;
198 }
199 tmp = (uint64_t)tmp >> c;
200 break;
201 case 3: /* lsr Rc */
202 c = cpu->cd.arm.r[c >> 1] & 255;
203 if (c >= 32)
204 c = 33;
205 if (update_c) {
206 if (c == 0)
207 update_c = 0;
208 else
209 lastbit = ((uint64_t)tmp >> (c-1)) & 1;
210 }
211 tmp = (uint64_t)tmp >> c;
212 break;
213 case 4: /* asr #c (c = 1..32) */
214 if (c == 0)
215 c = 32;
216 if (update_c) {
217 lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1;
218 }
219 tmp = (int64_t)(int32_t)tmp >> c;
220 break;
221 case 5: /* asr Rc */
222 c = cpu->cd.arm.r[c >> 1] & 255;
223 if (c >= 32)
224 c = 33;
225 if (update_c) {
226 if (c == 0)
227 update_c = 0;
228 else
229 lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1;
230 }
231 tmp = (int64_t)(int32_t)tmp >> c;
232 break;
233 case 6: /* ror 1..31 */
234 if (c == 0) {
235 fatal("TODO: rrx\n");
236 exit(1);
237 }
238 if (update_c)
239 lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1;
240 tmp = (uint64_t)(((uint64_t)tmp << 32) | tmp) >> c;
241 break;
242 case 7: /* ror Rc */
243 c = cpu->cd.arm.r[c >> 1] & 255;
244 if (update_c) {
245 if (c == 0)
246 update_c = 0;
247 else {
248 c &= 31;
249 if (c == 0)
250 lastbit = tmp & 0x80000000;
251 else
252 lastbit = ((int64_t)(int32_t)tmp
253 >> (c-1)) & 1;
254 tmp = (uint64_t)(((uint64_t)tmp << 32)
255 | tmp) >> c;
256 }
257 }
258 break;
259 }
260 if (update_c) {
261 cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
262 if (lastbit)
263 cpu->cd.arm.cpsr |= ARM_FLAG_C;
264 }
265 return tmp;
266 }
267
268
269 /*****************************************************************************/
270
271
272 /*
273 * nop: Do nothing.
274 * invalid: Invalid instructions end up here.
275 */
276 X(nop) { }
277 X(invalid) {
278 uint32_t low_pc;
279 low_pc = ((size_t)ic - (size_t)
280 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
281 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
282 << ARM_INSTR_ALIGNMENT_SHIFT);
283 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
284 cpu->pc = cpu->cd.arm.r[ARM_PC];
285
286 fatal("Invalid ARM instruction: pc=0x%08x\n", (int)cpu->pc);
287
288 cpu->running = 0;
289 cpu->running_translated = 0;
290 cpu->n_translated_instrs --;
291 cpu->cd.arm.next_ic = &nothing_call;
292 }
293
294
295 /*
296 * b: Branch (to a different translated page)
297 *
298 * arg[0] = relative offset
299 */
300 X(b)
301 {
302 uint32_t low_pc;
303
304 /* Calculate new PC from this instruction + arg[0] */
305 low_pc = ((size_t)ic - (size_t)
306 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
307 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
308 << ARM_INSTR_ALIGNMENT_SHIFT);
309 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
310 cpu->cd.arm.r[ARM_PC] += (int32_t)ic->arg[0];
311 cpu->pc = cpu->cd.arm.r[ARM_PC];
312
313 /* Find the new physical page and update the translation pointers: */
314 arm_pc_to_pointers(cpu);
315 }
316 Y(b)
317
318
319 /*
320 * b_samepage: Branch (to within the same translated page)
321 *
322 * arg[0] = pointer to new arm_instr_call
323 */
324 X(b_samepage)
325 {
326 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
327 }
328 Y(b_samepage)
329
330
331 /*
332 * bx: Branch, potentially exchanging Thumb/ARM encoding
333 *
334 * arg[0] = ptr to rm
335 */
336 X(bx)
337 {
338 cpu->pc = cpu->cd.arm.r[ARM_PC] = reg(ic->arg[0]);
339 if (cpu->pc & 1) {
340 fatal("thumb: TODO\n");
341 exit(1);
342 }
343 cpu->pc &= ~3;
344
345 /* Find the new physical page and update the translation pointers: */
346 arm_pc_to_pointers(cpu);
347 }
348 Y(bx)
349
350
351 /*
352 * bx_trace: As bx, but with trace enabled, arg[0] = the link register.
353 *
354 * arg[0] = ignored
355 */
356 X(bx_trace)
357 {
358 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
359 if (cpu->pc & 1) {
360 fatal("thumb: TODO\n");
361 exit(1);
362 }
363 cpu->pc &= ~3;
364
365 cpu_functioncall_trace_return(cpu);
366
367 /* Find the new physical page and update the translation pointers: */
368 arm_pc_to_pointers(cpu);
369 }
370 Y(bx_trace)
371
372
373 /*
374 * bl: Branch and Link (to a different translated page)
375 *
376 * arg[0] = relative address
377 */
378 X(bl)
379 {
380 uint32_t lr, low_pc;
381
382 /* Figure out what the return (link) address will be: */
383 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
384 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
385 lr = cpu->cd.arm.r[ARM_PC];
386 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
387 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
388
389 /* Link: */
390 cpu->cd.arm.r[ARM_LR] = lr;
391
392 /* Calculate new PC from this instruction + arg[0] */
393 cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
394
395 /* Find the new physical page and update the translation pointers: */
396 arm_pc_to_pointers(cpu);
397 }
398 Y(bl)
399
400
401 /*
402 * blx: Branch and Link, potentially exchanging Thumb/ARM encoding
403 *
404 * arg[0] = ptr to rm
405 */
406 X(blx)
407 {
408 uint32_t lr, low_pc;
409
410 /* Figure out what the return (link) address will be: */
411 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
412 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
413 lr = cpu->cd.arm.r[ARM_PC];
414 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
415 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
416
417 /* Link: */
418 cpu->cd.arm.r[ARM_LR] = lr;
419
420 cpu->pc = cpu->cd.arm.r[ARM_PC] = reg(ic->arg[0]);
421 if (cpu->pc & 1) {
422 fatal("thumb: TODO\n");
423 exit(1);
424 }
425 cpu->pc &= ~3;
426
427 /* Find the new physical page and update the translation pointers: */
428 arm_pc_to_pointers(cpu);
429 }
430 Y(blx)
431
432
433 /*
434 * bl_trace: Branch and Link (to a different translated page), with trace
435 *
436 * Same as for bl.
437 */
438 X(bl_trace)
439 {
440 uint32_t lr, low_pc;
441
442 /* Figure out what the return (link) address will be: */
443 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
444 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
445 lr = cpu->cd.arm.r[ARM_PC];
446 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
447 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
448
449 /* Link: */
450 cpu->cd.arm.r[ARM_LR] = lr;
451
452 /* Calculate new PC from this instruction + arg[0] */
453 cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
454
455 cpu_functioncall_trace(cpu, cpu->pc);
456
457 /* Find the new physical page and update the translation pointers: */
458 arm_pc_to_pointers(cpu);
459 }
460 Y(bl_trace)
461
462
463 /*
464 * bl_samepage: A branch + link within the same page
465 *
466 * arg[0] = pointer to new arm_instr_call
467 */
468 X(bl_samepage)
469 {
470 uint32_t lr, low_pc;
471
472 /* Figure out what the return (link) address will be: */
473 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
474 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
475 lr = cpu->cd.arm.r[ARM_PC];
476 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
477 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
478
479 /* Link: */
480 cpu->cd.arm.r[ARM_LR] = lr;
481
482 /* Branch: */
483 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
484 }
485 Y(bl_samepage)
486
487
488 /*
489 * bl_samepage_trace: Branch and Link (to the same page), with trace
490 *
491 * Same as for bl_samepage.
492 */
493 X(bl_samepage_trace)
494 {
495 uint32_t tmp_pc, lr, low_pc;
496
497 /* Figure out what the return (link) address will be: */
498 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
499 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
500 lr = cpu->cd.arm.r[ARM_PC];
501 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
502 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
503
504 /* Link: */
505 cpu->cd.arm.r[ARM_LR] = lr;
506
507 /* Branch: */
508 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
509
510 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
511 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
512 tmp_pc = cpu->cd.arm.r[ARM_PC];
513 tmp_pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
514 << ARM_INSTR_ALIGNMENT_SHIFT);
515 tmp_pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
516 cpu_functioncall_trace(cpu, tmp_pc);
517 }
518 Y(bl_samepage_trace)
519
520
521 /*
522 * mul: Multiplication
523 *
524 * arg[0] = ptr to rd
525 * arg[1] = ptr to rm
526 * arg[2] = ptr to rs
527 */
528 X(mul)
529 {
530 reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
531 }
532 Y(mul)
533 X(muls)
534 {
535 uint32_t result = reg(ic->arg[1]) * reg(ic->arg[2]);
536 cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
537 if (result == 0)
538 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
539 if (result & 0x80000000)
540 cpu->cd.arm.cpsr |= ARM_FLAG_N;
541 reg(ic->arg[0]) = result;
542 }
543 Y(muls)
544
545
546 /*
547 * mla: Multiplication with addition
548 *
549 * arg[0] = copy of instruction word
550 */
551 X(mla)
552 {
553 /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
554 uint32_t iw = ic->arg[0];
555 int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,
556 rs = (iw >> 8) & 15, rm = iw & 15;
557 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
558 + cpu->cd.arm.r[rn];
559 }
560 Y(mla)
561 X(mlas)
562 {
563 /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
564 uint32_t iw = ic->arg[0];
565 int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,
566 rs = (iw >> 8) & 15, rm = iw & 15;
567 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
568 + cpu->cd.arm.r[rn];
569 cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
570 if (cpu->cd.arm.r[rd] == 0)
571 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
572 if (cpu->cd.arm.r[rd] & 0x80000000)
573 cpu->cd.arm.cpsr |= ARM_FLAG_N;
574 }
575 Y(mlas)
576
577
578 /*
579 * mull: Long multiplication
580 *
581 * arg[0] = copy of instruction word
582 */
583 X(mull)
584 {
585 /* xxxx0000 1UAShhhh llllssss 1001mmmm */
586 uint32_t iw = ic->arg[0];
587 int u_bit = (iw >> 22) & 1, a_bit = (iw >> 21) & 1;
588 uint64_t tmp = cpu->cd.arm.r[iw & 15];
589 if (u_bit)
590 tmp = (int64_t)(int32_t)tmp
591 * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
592 else
593 tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
594 if (a_bit) {
595 uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
596 | cpu->cd.arm.r[(iw >> 12) & 15];
597 x += tmp;
598 cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
599 cpu->cd.arm.r[(iw >> 12) & 15] = x;
600 } else {
601 cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
602 cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
603 }
604 }
605 Y(mull)
606
607
608 /*
609 * mov_reg_reg: Move a register to another.
610 *
611 * arg[0] = ptr to source register
612 * arg[1] = ptr to destination register
613 */
614 X(mov_reg_reg)
615 {
616 reg(ic->arg[1]) = reg(ic->arg[0]);
617 }
618 Y(mov_reg_reg)
619
620
621 /*
622 * ret_trace: "mov pc,lr" with trace enabled
623 *
624 * arg[0] = ignored
625 */
626 X(ret_trace)
627 {
628 uint32_t old_pc = cpu->cd.arm.r[ARM_PC];
629 uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
630 << ARM_INSTR_ALIGNMENT_SHIFT) |
631 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
632
633 /* Update the PC register: */
634 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
635
636 cpu_functioncall_trace_return(cpu);
637
638 /*
639 * Is this a return to code within the same page? Then there is no
640 * need to update all pointers, just next_ic.
641 */
642 if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
643 cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
644 ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
645 } else {
646 /* Find the new physical page and update pointers: */
647 arm_pc_to_pointers(cpu);
648 }
649 }
650 Y(ret_trace)
651
652
653 /*
654 * msr: Move to status register from a normal register or immediate value.
655 *
656 * arg[0] = immediate value
657 * arg[1] = mask
658 * arg[2] = pointer to rm
659 *
660 * msr_imm and msr_imm_spsr use arg[1] and arg[0].
661 * msr and msr_spsr use arg[1] and arg[2].
662 */
663 X(msr_imm)
664 {
665 uint32_t mask = ic->arg[1];
666 int switch_register_banks = (mask & ARM_FLAG_MODE) &&
667 ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
668 (ic->arg[0] & ARM_FLAG_MODE));
669 uint32_t new_value = ic->arg[0];
670
671 if (switch_register_banks)
672 arm_save_register_bank(cpu);
673
674 cpu->cd.arm.cpsr &= ~mask;
675 cpu->cd.arm.cpsr |= (new_value & mask);
676
677 if (switch_register_banks)
678 arm_load_register_bank(cpu);
679 }
680 Y(msr_imm)
681 X(msr)
682 {
683 ic->arg[0] = reg(ic->arg[2]);
684 instr(msr_imm)(cpu, ic);
685 }
686 Y(msr)
687 X(msr_imm_spsr)
688 {
689 uint32_t mask = ic->arg[1];
690 uint32_t new_value = ic->arg[0];
691 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
692 case ARM_MODE_FIQ32:
693 cpu->cd.arm.spsr_fiq &= ~mask;
694 cpu->cd.arm.spsr_fiq |= (new_value & mask);
695 break;
696 case ARM_MODE_ABT32:
697 cpu->cd.arm.spsr_abt &= ~mask;
698 cpu->cd.arm.spsr_abt |= (new_value & mask);
699 break;
700 case ARM_MODE_UND32:
701 cpu->cd.arm.spsr_und &= ~mask;
702 cpu->cd.arm.spsr_und |= (new_value & mask);
703 break;
704 case ARM_MODE_IRQ32:
705 cpu->cd.arm.spsr_irq &= ~mask;
706 cpu->cd.arm.spsr_irq |= (new_value & mask);
707 break;
708 case ARM_MODE_SVC32:
709 cpu->cd.arm.spsr_svc &= ~mask;
710 cpu->cd.arm.spsr_svc |= (new_value & mask);
711 break;
712 default:fatal("msr_spsr: unimplemented mode %i\n",
713 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
714 {
715 /* Synchronize the program counter: */
716 uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
717 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
718 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
719 << ARM_INSTR_ALIGNMENT_SHIFT);
720 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
721 old_pc = cpu->pc = cpu->cd.arm.r[ARM_PC];
722 printf("msr_spsr: old pc = 0x%08x\n", old_pc);
723 }
724 exit(1);
725 }
726 }
727 Y(msr_imm_spsr)
728 X(msr_spsr)
729 {
730 ic->arg[0] = reg(ic->arg[2]);
731 instr(msr_imm_spsr)(cpu, ic);
732 }
733 Y(msr_spsr)
734
735
736 /*
737 * mrs: Move from status/flag register to a normal register.
738 *
739 * arg[0] = pointer to rd
740 */
741 X(mrs)
742 {
743 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
744 }
745 Y(mrs)
746
747
748 /*
749 * mrs: Move from status/flag register to a normal register.
750 *
751 * arg[0] = pointer to rd
752 */
753 X(mrs_spsr)
754 {
755 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
756 case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
757 case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
758 case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
759 case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
760 case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
761 case ARM_MODE_USR32:
762 case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
763 default:fatal("mrs_spsr: unimplemented mode %i\n",
764 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
765 exit(1);
766 }
767 }
768 Y(mrs_spsr)
769
770
771 /*
772 * mcr_mrc: Coprocessor move
773 * cdp: Coprocessor operation
774 *
775 * arg[0] = copy of the instruction word
776 */
777 X(mcr_mrc) {
778 uint32_t low_pc;
779 low_pc = ((size_t)ic - (size_t)
780 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
781 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
782 << ARM_INSTR_ALIGNMENT_SHIFT);
783 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
784 cpu->pc = cpu->cd.arm.r[ARM_PC];
785 arm_mcr_mrc(cpu, ic->arg[0]);
786 }
787 Y(mcr_mrc)
788 X(cdp) {
789 uint32_t low_pc;
790 low_pc = ((size_t)ic - (size_t)
791 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
792 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
793 << ARM_INSTR_ALIGNMENT_SHIFT);
794 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
795 cpu->pc = cpu->cd.arm.r[ARM_PC];
796 arm_cdp(cpu, ic->arg[0]);
797 }
798 Y(cdp)
799
800
801 /*
802 * openfirmware:
803 */
804 X(openfirmware)
805 {
806 of_emul(cpu);
807 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
808 if (cpu->machine->show_trace_tree)
809 cpu_functioncall_trace_return(cpu);
810 arm_pc_to_pointers(cpu);
811 }
812
813
814 /*
815 * swi_useremul: Syscall.
816 *
817 * arg[0] = swi number
818 */
819 X(swi_useremul)
820 {
821 /* Synchronize the program counter: */
822 uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
823 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
824 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
825 << ARM_INSTR_ALIGNMENT_SHIFT);
826 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
827 old_pc = cpu->pc = cpu->cd.arm.r[ARM_PC];
828
829 useremul_syscall(cpu, ic->arg[0]);
830
831 if (!cpu->running) {
832 cpu->running_translated = 0;
833 cpu->n_translated_instrs --;
834 cpu->cd.arm.next_ic = &nothing_call;
835 } else if (cpu->pc != old_pc) {
836 /* PC was changed by the SWI call. Find the new physical
837 page and update the translation pointers: */
838 arm_pc_to_pointers(cpu);
839 }
840 }
841 Y(swi_useremul)
842
843
844 /*
845 * swi: Software interrupt.
846 */
847 X(swi)
848 {
849 /* Synchronize the program counter: */
850 uint32_t low_pc = ((size_t)ic - (size_t)
851 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
852 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
853 << ARM_INSTR_ALIGNMENT_SHIFT);
854 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
855 cpu->pc = cpu->cd.arm.r[ARM_PC];
856
857 arm_exception(cpu, ARM_EXCEPTION_SWI);
858 }
859 Y(swi)
860
861
862 /*
863 * swp, swpb: Swap (word or byte).
864 *
865 * arg[0] = ptr to rd
866 * arg[1] = ptr to rm
867 * arg[2] = ptr to rn
868 */
869 X(swp)
870 {
871 uint32_t addr = reg(ic->arg[2]), data, data2;
872 unsigned char d[4];
873 /* Synchronize the program counter: */
874 uint32_t low_pc = ((size_t)ic - (size_t)
875 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
876 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
877 << ARM_INSTR_ALIGNMENT_SHIFT);
878 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
879 cpu->pc = cpu->cd.arm.r[ARM_PC];
880
881 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
882 CACHE_DATA)) {
883 fatal("swp: load failed\n");
884 return;
885 }
886 data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
887 data2 = reg(ic->arg[1]);
888 d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
889 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
890 CACHE_DATA)) {
891 fatal("swp: store failed\n");
892 return;
893 }
894 reg(ic->arg[0]) = data;
895 }
896 Y(swp)
897 X(swpb)
898 {
899 uint32_t addr = reg(ic->arg[2]), data;
900 unsigned char d[1];
901 /* Synchronize the program counter: */
902 uint32_t low_pc = ((size_t)ic - (size_t)
903 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
904 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
905 << ARM_INSTR_ALIGNMENT_SHIFT);
906 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
907 cpu->pc = cpu->cd.arm.r[ARM_PC];
908
909 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
910 CACHE_DATA)) {
911 fatal("swp: load failed\n");
912 return;
913 }
914 data = d[0];
915 d[0] = reg(ic->arg[1]);
916 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
917 CACHE_DATA)) {
918 fatal("swp: store failed\n");
919 return;
920 }
921 reg(ic->arg[0]) = data;
922 }
923 Y(swpb)
924
925
926 extern void (*arm_load_store_instr[1024])(struct cpu *,
927 struct arm_instr_call *);
928 X(store_w0_byte_u1_p0_imm);
929 X(store_w0_word_u1_p0_imm);
930
931 extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
932 struct arm_instr_call *);
933
934 extern void (*arm_load_store_instr_3[2048])(struct cpu *,
935 struct arm_instr_call *);
936
937 extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
938 struct arm_instr_call *);
939
940 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
941 struct arm_instr_call *);
942 X(cmps);
943 X(sub);
944 X(subs);
945
946
947
948 /*
949 * bdt_load: Block Data Transfer, Load
950 *
951 * arg[0] = pointer to uint32_t in host memory, pointing to the base register
952 * arg[1] = 32-bit instruction word. Most bits are read from this.
953 */
954 X(bdt_load)
955 {
956 unsigned char data[4];
957 uint32_t *np = (uint32_t *)ic->arg[0];
958 uint32_t addr = *np, low_pc;
959 unsigned char *page;
960 uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
961 int p_bit = iw & 0x01000000;
962 int u_bit = iw & 0x00800000;
963 int s_bit = iw & 0x00400000;
964 int w_bit = iw & 0x00200000;
965 int i, return_flag = 0, saved_mode = 0;
966 uint32_t new_values[16];
967
968 /* Synchronize the program counter: */
969 low_pc = ((size_t)ic - (size_t)
970 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
971 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
972 ARM_INSTR_ALIGNMENT_SHIFT);
973 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
974 cpu->pc = cpu->cd.arm.r[ARM_PC];
975
976 if (s_bit) {
977 /* Load USR registers: */
978 if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
979 fatal("[ bdt_load: s-bit: in usermode? ]\n");
980 s_bit = 0;
981 } else if (iw & 0x8000) {
982 s_bit = 0;
983 return_flag = 1;
984 } else {
985 /* Which saved mode to restore to: */
986 uint32_t spsr;
987 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
988 case ARM_MODE_FIQ32:
989 spsr = cpu->cd.arm.spsr_fiq; break;
990 case ARM_MODE_ABT32:
991 spsr = cpu->cd.arm.spsr_abt; break;
992 case ARM_MODE_UND32:
993 spsr = cpu->cd.arm.spsr_und; break;
994 case ARM_MODE_IRQ32:
995 spsr = cpu->cd.arm.spsr_irq; break;
996 case ARM_MODE_SVC32:
997 spsr = cpu->cd.arm.spsr_svc; break;
998 default:fatal("bdt_load (1): unimplemented mode %i\n",
999 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1000 exit(1);
1001 }
1002 saved_mode = spsr & ARM_FLAG_MODE;
1003 }
1004 }
1005
1006 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1007 uint32_t value;
1008
1009 if (!((iw >> i) & 1)) {
1010 /* Skip register i: */
1011 continue;
1012 }
1013
1014 if (p_bit) {
1015 if (u_bit)
1016 addr += sizeof(uint32_t);
1017 else
1018 addr -= sizeof(uint32_t);
1019 }
1020
1021 page = cpu->cd.arm.host_load[addr >> 12];
1022 if (page != NULL) {
1023 uint32_t *p32 = (uint32_t *) page;
1024 value = p32[(addr & 0xfff) >> 2];
1025 /* Change byte order of value if
1026 host and emulated endianness differ: */
1027 #ifdef HOST_LITTLE_ENDIAN
1028 if (cpu->byte_order == EMUL_BIG_ENDIAN)
1029 #else
1030 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1031 #endif
1032 value = ((value & 0xff) << 24) |
1033 ((value & 0xff00) << 8) |
1034 ((value & 0xff0000) >> 8) |
1035 ((value & 0xff000000) >> 24);
1036 } else {
1037 if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1038 sizeof(data), MEM_READ, CACHE_DATA)) {
1039 /* load failed */
1040 return;
1041 }
1042 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1043 value = data[0] +
1044 (data[1] << 8) + (data[2] << 16)
1045 + (data[3] << 24);
1046 } else {
1047 value = data[3] +
1048 (data[2] << 8) + (data[1] << 16)
1049 + (data[0] << 24);
1050 }
1051 }
1052
1053 new_values[i] = value;
1054
1055 if (!p_bit) {
1056 if (u_bit)
1057 addr += sizeof(uint32_t);
1058 else
1059 addr -= sizeof(uint32_t);
1060 }
1061 }
1062
1063 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1064 if (!((iw >> i) & 1)) {
1065 /* Skip register i: */
1066 continue;
1067 }
1068
1069 if (!s_bit) {
1070 cpu->cd.arm.r[i] = new_values[i];
1071 } else {
1072 switch (saved_mode) {
1073 case ARM_MODE_USR32:
1074 case ARM_MODE_SYS32:
1075 if (i >= 8 && i <= 14)
1076 cpu->cd.arm.default_r8_r14[i-8] =
1077 new_values[i];
1078 else
1079 cpu->cd.arm.r[i] = new_values[i];
1080 break;
1081 case ARM_MODE_FIQ32:
1082 if (i >= 8 && i <= 14)
1083 cpu->cd.arm.fiq_r8_r14[i-8] =
1084 new_values[i];
1085 else
1086 cpu->cd.arm.r[i] = new_values[i];
1087 break;
1088 case ARM_MODE_IRQ32:
1089 if (i >= 13 && i <= 14)
1090 cpu->cd.arm.irq_r13_r14[i-13] =
1091 new_values[i];
1092 else
1093 cpu->cd.arm.r[i] = new_values[i];
1094 break;
1095 case ARM_MODE_SVC32:
1096 if (i >= 13 && i <= 14)
1097 cpu->cd.arm.svc_r13_r14[i-13] =
1098 new_values[i];
1099 else
1100 cpu->cd.arm.r[i] = new_values[i];
1101 break;
1102 case ARM_MODE_ABT32:
1103 if (i >= 13 && i <= 14)
1104 cpu->cd.arm.abt_r13_r14[i-13] =
1105 new_values[i];
1106 else
1107 cpu->cd.arm.r[i] = new_values[i];
1108 break;
1109 case ARM_MODE_UND32:
1110 if (i >= 13 && i <= 14)
1111 cpu->cd.arm.und_r13_r14[i-13] =
1112 new_values[i];
1113 else
1114 cpu->cd.arm.r[i] = new_values[i];
1115 break;
1116 }
1117 }
1118 }
1119
1120 if (w_bit)
1121 *np = addr;
1122
1123 if (return_flag) {
1124 uint32_t new_cpsr;
1125 int switch_register_banks;
1126
1127 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1128 case ARM_MODE_FIQ32:
1129 new_cpsr = cpu->cd.arm.spsr_fiq; break;
1130 case ARM_MODE_ABT32:
1131 new_cpsr = cpu->cd.arm.spsr_abt; break;
1132 case ARM_MODE_UND32:
1133 new_cpsr = cpu->cd.arm.spsr_und; break;
1134 case ARM_MODE_IRQ32:
1135 new_cpsr = cpu->cd.arm.spsr_irq; break;
1136 case ARM_MODE_SVC32:
1137 new_cpsr = cpu->cd.arm.spsr_svc; break;
1138 default:fatal("bdt_load: unimplemented mode %i\n",
1139 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1140 exit(1);
1141 }
1142
1143 switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
1144 (new_cpsr & ARM_FLAG_MODE);
1145
1146 if (switch_register_banks)
1147 arm_save_register_bank(cpu);
1148
1149 cpu->cd.arm.cpsr = new_cpsr;
1150
1151 if (switch_register_banks)
1152 arm_load_register_bank(cpu);
1153 }
1154
1155 /* NOTE: Special case: Loading the PC */
1156 if (iw & 0x8000) {
1157 cpu->cd.arm.r[ARM_PC] &= ~3;
1158 cpu->pc = cpu->cd.arm.r[ARM_PC];
1159 if (cpu->machine->show_trace_tree)
1160 cpu_functioncall_trace_return(cpu);
1161 /* TODO: There is no need to update the
1162 pointers if this is a return to the
1163 same page! */
1164 /* Find the new physical page and update the
1165 translation pointers: */
1166 arm_pc_to_pointers(cpu);
1167 }
1168 }
1169 Y(bdt_load)
1170
1171
1172 /*
1173 * bdt_store: Block Data Transfer, Store
1174 *
1175 * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1176 * arg[1] = 32-bit instruction word. Most bits are read from this.
1177 */
1178 X(bdt_store)
1179 {
1180 unsigned char data[4];
1181 uint32_t *np = (uint32_t *)ic->arg[0];
1182 uint32_t low_pc, value, addr = *np;
1183 uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1184 unsigned char *page;
1185 int p_bit = iw & 0x01000000;
1186 int u_bit = iw & 0x00800000;
1187 int s_bit = iw & 0x00400000;
1188 int w_bit = iw & 0x00200000;
1189 int i, saved_mode = 0;
1190
1191 if (s_bit) {
1192 /* Store USR (or saved) registers: */
1193 uint32_t spsr;
1194 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1195 case ARM_MODE_FIQ32:
1196 spsr = cpu->cd.arm.spsr_fiq; break;
1197 case ARM_MODE_ABT32:
1198 spsr = cpu->cd.arm.spsr_abt; break;
1199 case ARM_MODE_UND32:
1200 spsr = cpu->cd.arm.spsr_und; break;
1201 case ARM_MODE_IRQ32:
1202 spsr = cpu->cd.arm.spsr_irq; break;
1203 case ARM_MODE_SVC32:
1204 spsr = cpu->cd.arm.spsr_svc; break;
1205 default:fatal("bdt_store: unimplemented mode %i\n",
1206 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1207 exit(1);
1208 }
1209 saved_mode = spsr & ARM_FLAG_MODE;
1210 }
1211
1212 /* Synchronize the program counter: */
1213 low_pc = ((size_t)ic - (size_t)
1214 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1215 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
1216 ARM_INSTR_ALIGNMENT_SHIFT);
1217 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1218 cpu->pc = cpu->cd.arm.r[ARM_PC];
1219
1220 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1221 if (!((iw >> i) & 1)) {
1222 /* Skip register i: */
1223 continue;
1224 }
1225
1226 value = cpu->cd.arm.r[i];
1227
1228 if (s_bit) {
1229 switch (saved_mode) {
1230 case ARM_MODE_FIQ32:
1231 if (i >= 8 && i <= 14)
1232 value = cpu->cd.arm.fiq_r8_r14[i-8];
1233 break;
1234 case ARM_MODE_ABT32:
1235 if (i >= 13 && i <= 14)
1236 value = cpu->cd.arm.abt_r13_r14[i-13];
1237 break;
1238 case ARM_MODE_UND32:
1239 if (i >= 13 && i <= 14)
1240 value = cpu->cd.arm.und_r13_r14[i-13];
1241 break;
1242 case ARM_MODE_IRQ32:
1243 if (i >= 13 && i <= 14)
1244 value = cpu->cd.arm.irq_r13_r14[i-13];
1245 break;
1246 case ARM_MODE_SVC32:
1247 if (i >= 13 && i <= 14)
1248 value = cpu->cd.arm.svc_r13_r14[i-13];
1249 break;
1250 case ARM_MODE_USR32:
1251 case ARM_MODE_SYS32:
1252 if (i >= 8 && i <= 14)
1253 value = cpu->cd.arm.default_r8_r14[i-8];
1254 break;
1255 }
1256 }
1257
1258 if (i == ARM_PC)
1259 value += 12; /* NOTE/TODO: 8 on some ARMs */
1260
1261 if (p_bit) {
1262 if (u_bit)
1263 addr += sizeof(uint32_t);
1264 else
1265 addr -= sizeof(uint32_t);
1266 }
1267
1268 page = cpu->cd.arm.host_store[addr >> 12];
1269 if (page != NULL) {
1270 uint32_t *p32 = (uint32_t *) page;
1271 /* Change byte order of value if
1272 host and emulated endianness differ: */
1273 #ifdef HOST_LITTLE_ENDIAN
1274 if (cpu->byte_order == EMUL_BIG_ENDIAN)
1275 #else
1276 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1277 #endif
1278 value = ((value & 0xff) << 24) |
1279 ((value & 0xff00) << 8) |
1280 ((value & 0xff0000) >> 8) |
1281 ((value & 0xff000000) >> 24);
1282 p32[(addr & 0xfff) >> 2] = value;
1283 } else {
1284 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1285 data[0] = value;
1286 data[1] = value >> 8;
1287 data[2] = value >> 16;
1288 data[3] = value >> 24;
1289 } else {
1290 data[0] = value >> 24;
1291 data[1] = value >> 16;
1292 data[2] = value >> 8;
1293 data[3] = value;
1294 }
1295 if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1296 sizeof(data), MEM_WRITE, CACHE_DATA)) {
1297 /* store failed */
1298 return;
1299 }
1300 }
1301
1302 if (!p_bit) {
1303 if (u_bit)
1304 addr += sizeof(uint32_t);
1305 else
1306 addr -= sizeof(uint32_t);
1307 }
1308 }
1309
1310 if (w_bit)
1311 *np = addr;
1312 }
1313 Y(bdt_store)
1314
1315
1316 /*****************************************************************************/
1317
1318
1319 /*
1320 * fill_loop_test:
1321 *
1322 * A byte-fill loop. Fills at most one page at a time. If the page was not
1323 * in the host_store table, then the original sequence (beginning with
1324 * cmps rZ,#0) is executed instead.
1325 *
1326 * L: cmps rZ,#0 ic[0]
1327 * strb rX,[rY],#1 ic[1]
1328 * sub rZ,rZ,#1 ic[2]
1329 * bgt L ic[3]
1330 *
1331 * A maximum of 4 pages are filled before returning.
1332 */
1333 X(fill_loop_test)
1334 {
1335 int max_pages_left = 4;
1336 uint32_t addr, a, n, ofs, maxlen;
1337 uint32_t *rzp = (uint32_t *)(size_t)ic[0].arg[0];
1338 unsigned char *page;
1339
1340 restart_loop:
1341 addr = reg(ic[1].arg[0]);
1342 page = cpu->cd.arm.host_store[addr >> 12];
1343 if (page == NULL) {
1344 instr(cmps)(cpu, ic);
1345 return;
1346 }
1347
1348 n = reg(rzp) + 1;
1349 ofs = addr & 0xfff;
1350 maxlen = 4096 - ofs;
1351 if (n > maxlen)
1352 n = maxlen;
1353
1354 /* printf("x = %x, n = %i\n", reg(ic[1].arg[2]), n); */
1355 memset(page + ofs, reg(ic[1].arg[2]), n);
1356
1357 reg(ic[1].arg[0]) = addr + n;
1358
1359 reg(rzp) -= n;
1360 cpu->n_translated_instrs += (4 * n);
1361
1362 a = reg(rzp);
1363
1364 cpu->cd.arm.cpsr &=
1365 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
1366 if (a != 0)
1367 cpu->cd.arm.cpsr |= ARM_FLAG_C;
1368 else
1369 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
1370 if ((int32_t)a < 0)
1371 cpu->cd.arm.cpsr |= ARM_FLAG_N;
1372
1373 if (max_pages_left-- > 0 && (int32_t)a > 0)
1374 goto restart_loop;
1375
1376 cpu->n_translated_instrs --;
1377
1378 if ((int32_t)a > 0)
1379 cpu->cd.arm.next_ic = ic;
1380 else
1381 cpu->cd.arm.next_ic = &ic[4];
1382 }
1383
1384
1385 /*
1386 * fill_loop_test2:
1387 *
1388 * A word-fill loop. Fills at most one page at a time. If the page was not
1389 * in the host_store table, then the original sequence (beginning with
1390 * cmps rZ,#0) is executed instead.
1391 *
1392 * L: str rX,[rY],#4 ic[0]
1393 * subs rZ,rZ,#4 ic[1]
1394 * bgt L ic[2]
1395 *
1396 * A maximum of 5 pages are filled before returning.
1397 */
1398 X(fill_loop_test2)
1399 {
1400 int max_pages_left = 5;
1401 unsigned char x1,x2,x3,x4;
1402 uint32_t addr, a, n, x, ofs, maxlen;
1403 uint32_t *rzp = (uint32_t *)(size_t)ic[1].arg[0];
1404 unsigned char *page;
1405
1406 x = reg(ic[0].arg[2]);
1407 x1 = x; x2 = x >> 8; x3 = x >> 16; x4 = x >> 24;
1408 if (x1 != x2 || x1 != x3 || x1 != x4) {
1409 instr(store_w0_word_u1_p0_imm)(cpu, ic);
1410 return;
1411 }
1412
1413 restart_loop:
1414 addr = reg(ic[0].arg[0]);
1415 page = cpu->cd.arm.host_store[addr >> 12];
1416 if (page == NULL || (addr & 3) != 0) {
1417 instr(store_w0_word_u1_p0_imm)(cpu, ic);
1418 return;
1419 }
1420
1421 /* printf("addr = 0x%08x, page = %p\n", addr, page);
1422 printf("*rzp = 0x%08x\n", reg(rzp)); */
1423
1424 n = reg(rzp) / 4;
1425 if (n == 0)
1426 n++;
1427 /* n = nr of _words_ */
1428 ofs = addr & 0xfff;
1429 maxlen = 4096 - ofs;
1430 if (n*4 > maxlen)
1431 n = maxlen / 4;
1432
1433 /* printf("x = %x, n = %i\n", x1, n); */
1434 memset(page + ofs, x1, n * 4);
1435
1436 reg(ic[0].arg[0]) = addr + n * 4;
1437
1438 reg(rzp) -= (n * 4);
1439 cpu->n_translated_instrs += (3 * n);
1440
1441 a = reg(rzp);
1442
1443 cpu->cd.arm.cpsr &=
1444 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
1445 if (a != 0)
1446 cpu->cd.arm.cpsr |= ARM_FLAG_C;
1447 else
1448 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
1449 if ((int32_t)a < 0)
1450 cpu->cd.arm.cpsr |= ARM_FLAG_N;
1451
1452 if (max_pages_left-- > 0 && (int32_t)a > 0)
1453 goto restart_loop;
1454
1455 cpu->n_translated_instrs --;
1456
1457 if ((int32_t)a > 0)
1458 cpu->cd.arm.next_ic = ic;
1459 else
1460 cpu->cd.arm.next_ic = &ic[3];
1461 }
1462
1463
1464 /*****************************************************************************/
1465
1466
1467 X(end_of_page)
1468 {
1469 /* Update the PC: (offset 0, but on the next page) */
1470 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
1471 << ARM_INSTR_ALIGNMENT_SHIFT);
1472 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE
1473 << ARM_INSTR_ALIGNMENT_SHIFT);
1474 cpu->pc = cpu->cd.arm.r[ARM_PC];
1475
1476 /* Find the new physical page and update the translation pointers: */
1477 arm_pc_to_pointers(cpu);
1478
1479 /* end_of_page doesn't count as an executed instruction: */
1480 cpu->n_translated_instrs --;
1481 }
1482
1483
1484 /*****************************************************************************/
1485
1486
1487 /*
1488 * arm_combine_instructions():
1489 *
1490 * Combine two or more instructions, if possible, into a single function call.
1491 */
1492 void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic,
1493 uint32_t addr)
1494 {
1495 int n_back;
1496 n_back = (addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1497 & (ARM_IC_ENTRIES_PER_PAGE-1);
1498
1499 if (n_back >= 2) {
1500 if (ic[-2].f == instr(store_w0_word_u1_p0_imm) &&
1501 ic[-2].arg[1] == 4 &&
1502 ic[-1].f == instr(subs) &&
1503 ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 4 &&
1504 ic[ 0].f == instr(b_samepage__gt) &&
1505 ic[ 0].arg[0] == (size_t)&ic[-2]) {
1506 ic[-2].f = instr(fill_loop_test2);
1507 combined;
1508 }
1509 }
1510
1511 if (n_back >= 3) {
1512 if (ic[-3].f == instr(cmps) &&
1513 ic[-3].arg[0] == ic[-1].arg[0] &&
1514 ic[-3].arg[1] == 0 &&
1515 ic[-2].f == instr(store_w0_byte_u1_p0_imm) &&
1516 ic[-2].arg[1] == 1 &&
1517 ic[-1].f == instr(sub) &&
1518 ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 1 &&
1519 ic[ 0].f == instr(b_samepage__gt) &&
1520 ic[ 0].arg[0] == (size_t)&ic[-3]) {
1521 ic[-3].f = instr(fill_loop_test);
1522 combined;
1523 }
1524 }
1525
1526 /* TODO: Combine forward as well */
1527 }
1528
1529
1530 /*****************************************************************************/
1531
1532
1533 /*
1534 * arm_instr_to_be_translated():
1535 *
1536 * Translate an instruction word into an arm_instr_call. ic is filled in with
1537 * valid data for the translated instruction, or a "nothing" instruction if
1538 * there was a translation failure. The newly translated instruction is then
1539 * executed.
1540 */
1541 X(to_be_translated)
1542 {
1543 uint32_t addr, low_pc, iword, imm = 0;
1544 unsigned char *page;
1545 unsigned char ib[4];
1546 int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
1547 int p_bit, u_bit, b_bit, w_bit, l_bit, regform, rm, c, t;
1548 int any_pc_reg;
1549 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
1550
1551 /* Figure out the address of the instruction: */
1552 low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
1553 / sizeof(struct arm_instr_call);
1554 addr = cpu->cd.arm.r[ARM_PC] & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
1555 ARM_INSTR_ALIGNMENT_SHIFT);
1556 addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1557 cpu->pc = cpu->cd.arm.r[ARM_PC] = addr;
1558 addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
1559
1560 /* Read the instruction word from memory: */
1561 page = cpu->cd.arm.host_load[addr >> 12];
1562 if (page != NULL) {
1563 /* fatal("TRANSLATION HIT!\n"); */
1564 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
1565 } else {
1566 /* fatal("TRANSLATION MISS!\n"); */
1567 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
1568 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
1569 fatal("to_be_translated(): "
1570 "read failed: TODO\n");
1571 goto bad;
1572 }
1573 }
1574
1575 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1576 iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
1577 else
1578 iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
1579
1580
1581 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
1582 #include "cpu_dyntrans.c"
1583 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
1584
1585
1586 /* The idea of taking bits 27..24 was found here:
1587 http://armphetamine.sourceforge.net/oldinfo.html */
1588 condition_code = iword >> 28;
1589 main_opcode = (iword >> 24) & 15;
1590 secondary_opcode = (iword >> 21) & 15;
1591 u_bit = (iword >> 23) & 1;
1592 b_bit = (iword >> 22) & 1;
1593 w_bit = (iword >> 21) & 1;
1594 s_bit = l_bit = (iword >> 20) & 1;
1595 rn = (iword >> 16) & 15;
1596 rd = (iword >> 12) & 15;
1597 r8 = (iword >> 8) & 15;
1598 c = (iword >> 7) & 31;
1599 t = (iword >> 4) & 7;
1600 rm = iword & 15;
1601
1602 if (condition_code == 0xf) {
1603 if ((iword & 0xfc70f000) == 0xf450f000) {
1604 /* Preload: TODO. Treat as NOP for now. */
1605 ic->f = instr(nop);
1606 goto okay;
1607 }
1608
1609 fatal("TODO: ARM condition code 0x%x\n",
1610 condition_code);
1611 goto bad;
1612 }
1613
1614
1615 /*
1616 * Translate the instruction:
1617 */
1618
1619 switch (main_opcode) {
1620
1621 case 0x0:
1622 case 0x1:
1623 case 0x2:
1624 case 0x3:
1625 /* Check special cases first: */
1626 if ((iword & 0x0fc000f0) == 0x00000090) {
1627 /*
1628 * Multiplication:
1629 * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])
1630 */
1631 if (iword & 0x00200000) {
1632 if (s_bit)
1633 ic->f = cond_instr(mlas);
1634 else
1635 ic->f = cond_instr(mla);
1636 ic->arg[0] = iword;
1637 } else {
1638 if (s_bit)
1639 ic->f = cond_instr(muls);
1640 else
1641 ic->f = cond_instr(mul);
1642 /* NOTE: rn means rd in this case: */
1643 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1644 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
1645 ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]);
1646 }
1647 break;
1648 }
1649 if ((iword & 0x0f8000f0) == 0x00800090) {
1650 /* Long multiplication: */
1651 if (s_bit) {
1652 fatal("TODO: sbit mull\n");
1653 goto bad;
1654 }
1655 ic->f = cond_instr(mull);
1656 ic->arg[0] = iword;
1657 break;
1658 }
1659 if ((iword & 0x0ff000d0) == 0x01200010) {
1660 /* bx or blx */
1661 if (iword & 0x20)
1662 ic->f = cond_instr(blx);
1663 else {
1664 if (cpu->machine->show_trace_tree &&
1665 rm == ARM_LR)
1666 ic->f = cond_instr(bx_trace);
1667 else
1668 ic->f = cond_instr(bx);
1669 }
1670 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
1671 break;
1672 }
1673 if ((iword & 0x0fb00ff0) == 0x1000090) {
1674 if (iword & 0x00400000)
1675 ic->f = cond_instr(swpb);
1676 else
1677 ic->f = cond_instr(swp);
1678 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
1679 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
1680 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
1681 break;
1682 }
1683 if ((iword & 0x0fb0fff0) == 0x0120f000 ||
1684 (iword & 0x0fb0f000) == 0x0320f000) {
1685 /* msr: move to [S|C]PSR from a register or
1686 immediate value */
1687 if (rm == ARM_PC) {
1688 fatal("msr PC?\n");
1689 goto bad;
1690 }
1691 if (iword & 0x02000000) {
1692 if (iword & 0x00400000)
1693 ic->f = cond_instr(msr_imm_spsr);
1694 else
1695 ic->f = cond_instr(msr_imm);
1696 } else {
1697 if (iword & 0x00400000)
1698 ic->f = cond_instr(msr_spsr);
1699 else
1700 ic->f = cond_instr(msr);
1701 }
1702 imm = iword & 0xff;
1703 while (r8-- > 0)
1704 imm = (imm >> 2) | ((imm & 3) << 30);
1705 ic->arg[0] = imm;
1706 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
1707 switch ((iword >> 16) & 15) {
1708 case 1: ic->arg[1] = 0x000000ff; break;
1709 case 8: ic->arg[1] = 0xff000000; break;
1710 case 9: ic->arg[1] = 0xff0000ff; break;
1711 default:fatal("unimpl a: msr regform\n");
1712 goto bad;
1713 }
1714 break;
1715 }
1716 if ((iword & 0x0fbf0fff) == 0x010f0000) {
1717 /* mrs: move from CPSR/SPSR to a register: */
1718 if (rd == ARM_PC) {
1719 fatal("mrs PC?\n");
1720 goto bad;
1721 }
1722 if (iword & 0x00400000)
1723 ic->f = cond_instr(mrs_spsr);
1724 else
1725 ic->f = cond_instr(mrs);
1726 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
1727 break;
1728 }
1729 if ((iword & 0x0e000090) == 0x00000090) {
1730 int imm = ((iword >> 4) & 0xf0) | (iword & 0xf);
1731 int regform = !(iword & 0x00400000);
1732 p_bit = main_opcode & 1;
1733 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1734 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
1735 if (rd == ARM_PC || rn == ARM_PC) {
1736 ic->f = arm_load_store_instr_3_pc[
1737 condition_code + (l_bit? 16 : 0)
1738 + (iword & 0x40? 32 : 0)
1739 + (w_bit? 64 : 0)
1740 + (iword & 0x20? 128 : 0)
1741 + (u_bit? 256 : 0) + (p_bit? 512 : 0)
1742 + (regform? 1024 : 0)];
1743 if (rn == ARM_PC)
1744 ic->arg[0] = (size_t)
1745 (&cpu->cd.arm.tmp_pc);
1746 if (!l_bit && rd == ARM_PC)
1747 ic->arg[2] = (size_t)
1748 (&cpu->cd.arm.tmp_pc);
1749 } else
1750 ic->f = arm_load_store_instr_3[
1751 condition_code + (l_bit? 16 : 0)
1752 + (iword & 0x40? 32 : 0)
1753 + (w_bit? 64 : 0)
1754 + (iword & 0x20? 128 : 0)
1755 + (u_bit? 256 : 0) + (p_bit? 512 : 0)
1756 + (regform? 1024 : 0)];
1757 if (regform)
1758 ic->arg[1] = iword & 0xf;
1759 else
1760 ic->arg[1] = imm;
1761 break;
1762 }
1763
1764 if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
1765 fatal("reg form blah blah\n");
1766 goto bad;
1767 }
1768
1769 /* "mov pc,lr" with trace enabled: */
1770 if ((iword & 0x0fffffff) == 0x01a0f00e &&
1771 cpu->machine->show_trace_tree) {
1772 ic->f = cond_instr(ret_trace);
1773 break;
1774 }
1775
1776 /* "mov reg,reg": */
1777 if ((iword & 0x0fff0ff0) == 0x01a00000 &&
1778 (iword&15) != ARM_PC && rd != ARM_PC) {
1779 ic->f = cond_instr(mov_reg_reg);
1780 ic->arg[0] = (size_t)(&cpu->cd.arm.r[iword & 15]);
1781 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
1782 break;
1783 }
1784
1785 /*
1786 * Generic Data Processing Instructions:
1787 */
1788 if ((main_opcode & 2) == 0)
1789 regform = 1;
1790 else
1791 regform = 0;
1792
1793 if (regform)
1794 ic->arg[1] = iword;
1795 else {
1796 imm = iword & 0xff;
1797 while (r8-- > 0)
1798 imm = (imm >> 2) | ((imm & 3) << 30);
1799 ic->arg[1] = imm;
1800 }
1801
1802 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1803 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
1804 any_pc_reg = 0;
1805 if (rn == ARM_PC || rd == ARM_PC)
1806 any_pc_reg = 1;
1807
1808 ic->f = arm_dpi_instr[condition_code +
1809 16 * secondary_opcode + (s_bit? 256 : 0) +
1810 (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
1811 break;
1812
1813 case 0x4: /* Load and store... */
1814 case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
1815 case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
1816 case 0x7:
1817 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1818 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
1819 if (rd == ARM_PC || rn == ARM_PC) {
1820 ic->f = arm_load_store_instr_pc[((iword >> 16)
1821 & 0x3f0) + condition_code];
1822 if (rn == ARM_PC)
1823 ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc);
1824 if (!l_bit && rd == ARM_PC)
1825 ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc);
1826 } else {
1827 ic->f = arm_load_store_instr[((iword >> 16) &
1828 0x3f0) + condition_code];
1829 }
1830 imm = iword & 0xfff;
1831 if (main_opcode < 6)
1832 ic->arg[1] = imm;
1833 else
1834 ic->arg[1] = iword;
1835 if ((iword & 0x0e000010) == 0x06000010) {
1836 fatal("Not a Load/store TODO\n");
1837 goto bad;
1838 }
1839 break;
1840
1841 case 0x8: /* Multiple load/store... (Block data transfer) */
1842 case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
1843 if (l_bit)
1844 ic->f = cond_instr(bdt_load);
1845 else
1846 ic->f = cond_instr(bdt_store);
1847 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1848 ic->arg[1] = (size_t)iword;
1849 if (rn == ARM_PC) {
1850 fatal("TODO: bdt with PC as base\n");
1851 goto bad;
1852 }
1853 break;
1854
1855 case 0xa: /* B: branch */
1856 case 0xb: /* BL: branch+link */
1857 if (main_opcode == 0x0a) {
1858 ic->f = cond_instr(b);
1859 samepage_function = cond_instr(b_samepage);
1860 } else {
1861 if (cpu->machine->show_trace_tree) {
1862 ic->f = cond_instr(bl_trace);
1863 samepage_function =
1864 cond_instr(bl_samepage_trace);
1865 } else {
1866 ic->f = cond_instr(bl);
1867 samepage_function = cond_instr(bl_samepage);
1868 }
1869 }
1870
1871 ic->arg[0] = (iword & 0x00ffffff) << 2;
1872 /* Sign-extend: */
1873 if (ic->arg[0] & 0x02000000)
1874 ic->arg[0] |= 0xfc000000;
1875 /*
1876 * Branches are calculated as PC + 8 + offset.
1877 */
1878 ic->arg[0] = (int32_t)(ic->arg[0] + 8);
1879
1880 /* Special case: branch within the same page: */
1881 {
1882 uint32_t mask_within_page =
1883 ((ARM_IC_ENTRIES_PER_PAGE-1) <<
1884 ARM_INSTR_ALIGNMENT_SHIFT) |
1885 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
1886 uint32_t old_pc = addr;
1887 uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
1888 if ((old_pc & ~mask_within_page) ==
1889 (new_pc & ~mask_within_page)) {
1890 ic->f = samepage_function;
1891 ic->arg[0] = (size_t) (
1892 cpu->cd.arm.cur_ic_page +
1893 ((new_pc & mask_within_page) >>
1894 ARM_INSTR_ALIGNMENT_SHIFT));
1895 }
1896 }
1897 break;
1898
1899 case 0xe:
1900 if (iword & 0x10) {
1901 /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */
1902 ic->arg[0] = iword;
1903 ic->f = cond_instr(mcr_mrc);
1904 } else {
1905 /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */
1906 ic->arg[0] = iword;
1907 ic->f = cond_instr(cdp);
1908 }
1909 break;
1910
1911 case 0xf:
1912 /* SWI: */
1913 /* Default handler: */
1914 ic->f = cond_instr(swi);
1915 if (iword == 0xef8c64be) {
1916 /* Hack for openfirmware prom emulation: */
1917 ic->f = instr(openfirmware);
1918 } else if (cpu->machine->userland_emul != NULL) {
1919 if ((iword & 0x00f00000) == 0x00a00000) {
1920 ic->arg[0] = iword & 0x00ffffff;
1921 ic->f = cond_instr(swi_useremul);
1922 } else {
1923 fatal("Bad userland SWI?\n");
1924 goto bad;
1925 }
1926 }
1927 break;
1928
1929 default:goto bad;
1930 }
1931
1932 okay:
1933
1934 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
1935 #include "cpu_dyntrans.c"
1936 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
1937 }
1938

  ViewVC Help
Powered by ViewVC 1.1.26