/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 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 dpavlin 14 /*
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