/[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 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 78511 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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 dpavlin 20 * $Id: cpu_arm_instr.c,v 1.54 2005/11/19 18:53:07 debug Exp $
29 dpavlin 14 *
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 dpavlin 18 #include "arm_quick_pc_to_pointers.h"
40    
41     /* #define GATHER_BDT_STATISTICS */
42    
43    
44     #ifdef GATHER_BDT_STATISTICS
45 dpavlin 14 /*
46 dpavlin 18 * update_bdt_statistics():
47     *
48     * Gathers statistics about load/store multiple instructions.
49     *
50     * NOTE/TODO: Perhaps it would be more memory efficient to swap the high
51     * and low parts of the instruction word, so that the lllllll bits become
52     * the high bits; this would cause fewer host pages to be used. Anyway, the
53     * current implementation works on hosts with lots of RAM.
54     *
55     * The resulting file, bdt_statistics.txt, should then be processed like
56     * this to give a new cpu_arm_multi.txt:
57     *
58     * uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt
59     */
60     static void update_bdt_statistics(uint32_t iw)
61     {
62     static FILE *f = NULL;
63     static long long *counts;
64     static char *counts_used;
65     static long long n = 0;
66    
67     if (f == NULL) {
68     size_t s = (1 << 24) * sizeof(long long);
69     f = fopen("bdt_statistics.txt", "w");
70     if (f == NULL) {
71     fprintf(stderr, "update_bdt_statistics(): :-(\n");
72     exit(1);
73     }
74     counts = zeroed_alloc(s);
75     counts_used = zeroed_alloc(65536);
76     }
77    
78     /* Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll */
79     iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff);
80    
81     counts_used[iw & 0xffff] = 1;
82     counts[iw] ++;
83    
84     n ++;
85     if ((n % 500000) == 0) {
86     int i;
87     long long j;
88     fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n);
89     fseek(f, 0, SEEK_SET);
90     for (i=0; i<0x1000000; i++)
91     if (counts_used[i & 0xffff] && counts[i] != 0) {
92     /* Recreate the opcode: */
93     uint32_t opcode = ((i & 0x00c00000) << 1)
94     | (i & 0x003fffff) | 0x08000000;
95     for (j=0; j<counts[i]; j++)
96     fprintf(f, "0x%08x\n", opcode);
97     }
98     fflush(f);
99     }
100     }
101     #endif
102    
103    
104     /*****************************************************************************/
105    
106    
107     /*
108 dpavlin 14 * Helper definitions:
109     *
110     * Each instruction is defined like this:
111     *
112     * X(foo)
113     * {
114     * code for foo;
115     * }
116     * Y(foo)
117     *
118     * The Y macro defines 14 copies of the instruction, one for each possible
119     * condition code. (The NV condition code is not included, and the AL code
120     * uses the main foo function.) Y also defines an array with pointers to
121     * all of these functions.
122 dpavlin 18 *
123     * If the compiler is good enough (i.e. allows long enough code sequences
124     * to be inlined), then the Y functions will be compiled as full (inlined)
125     * functions, otherwise they will simply call the X function.
126 dpavlin 14 */
127    
128 dpavlin 20 uint8_t condition_hi[16] = { 0,0,1,1, 0,0,0,0, 0,0,1,1, 0,0,0,0 };
129     uint8_t condition_ge[16] = { 1,0,1,0, 1,0,1,0, 0,1,0,1, 0,1,0,1 };
130     uint8_t condition_gt[16] = { 1,0,1,0, 0,0,0,0, 0,1,0,1, 0,0,0,0 };
131    
132 dpavlin 14 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
133     struct arm_instr_call *ic) \
134 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_Z) \
135 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
136     void arm_instr_ ## n ## __ne(struct cpu *cpu, \
137     struct arm_instr_call *ic) \
138 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_Z)) \
139 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
140     void arm_instr_ ## n ## __cs(struct cpu *cpu, \
141     struct arm_instr_call *ic) \
142 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_C) \
143 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
144     void arm_instr_ ## n ## __cc(struct cpu *cpu, \
145     struct arm_instr_call *ic) \
146 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_C)) \
147 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
148     void arm_instr_ ## n ## __mi(struct cpu *cpu, \
149     struct arm_instr_call *ic) \
150 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_N) \
151 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
152     void arm_instr_ ## n ## __pl(struct cpu *cpu, \
153     struct arm_instr_call *ic) \
154 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_N)) \
155 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
156     void arm_instr_ ## n ## __vs(struct cpu *cpu, \
157     struct arm_instr_call *ic) \
158 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_V) \
159 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
160     void arm_instr_ ## n ## __vc(struct cpu *cpu, \
161     struct arm_instr_call *ic) \
162 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_V)) \
163 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
164     void arm_instr_ ## n ## __hi(struct cpu *cpu, \
165     struct arm_instr_call *ic) \
166 dpavlin 20 { if (condition_hi[cpu->cd.arm.flags]) \
167 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
168     void arm_instr_ ## n ## __ls(struct cpu *cpu, \
169     struct arm_instr_call *ic) \
170 dpavlin 20 { if (!condition_hi[cpu->cd.arm.flags]) \
171 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
172     void arm_instr_ ## n ## __ge(struct cpu *cpu, \
173     struct arm_instr_call *ic) \
174 dpavlin 20 { if (condition_ge[cpu->cd.arm.flags]) \
175 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
176     void arm_instr_ ## n ## __lt(struct cpu *cpu, \
177     struct arm_instr_call *ic) \
178 dpavlin 20 { if (!condition_ge[cpu->cd.arm.flags]) \
179 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
180     void arm_instr_ ## n ## __gt(struct cpu *cpu, \
181     struct arm_instr_call *ic) \
182 dpavlin 20 { if (condition_gt[cpu->cd.arm.flags]) \
183 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
184     void arm_instr_ ## n ## __le(struct cpu *cpu, \
185     struct arm_instr_call *ic) \
186 dpavlin 20 { if (!condition_gt[cpu->cd.arm.flags]) \
187 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
188     void (*arm_cond_instr_ ## n [16])(struct cpu *, \
189     struct arm_instr_call *) = { \
190     arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
191     arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
192     arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
193     arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
194     arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
195     arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
196     arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
197     arm_instr_ ## n , arm_instr_nop };
198    
199     #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
200    
201    
202     /*****************************************************************************/
203    
204    
205     /*
206     * nop: Do nothing.
207     * invalid: Invalid instructions end up here.
208     */
209     X(nop) { }
210     X(invalid) {
211     uint32_t low_pc;
212     low_pc = ((size_t)ic - (size_t)
213     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
214 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
215 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
216 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
217 dpavlin 14
218     fatal("Invalid ARM instruction: pc=0x%08x\n", (int)cpu->pc);
219    
220     cpu->running = 0;
221     cpu->running_translated = 0;
222     cpu->n_translated_instrs --;
223     cpu->cd.arm.next_ic = &nothing_call;
224     }
225    
226    
227     /*
228     * b: Branch (to a different translated page)
229     *
230     * arg[0] = relative offset
231     */
232     X(b)
233     {
234 dpavlin 20 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
235 dpavlin 14
236     /* Find the new physical page and update the translation pointers: */
237 dpavlin 18 quick_pc_to_pointers(cpu);
238 dpavlin 14 }
239     Y(b)
240    
241    
242     /*
243     * b_samepage: Branch (to within the same translated page)
244     *
245     * arg[0] = pointer to new arm_instr_call
246 dpavlin 20 * arg[1] = pointer to the next instruction.
247     *
248     * NOTE: This instruction is manually inlined.
249 dpavlin 14 */
250 dpavlin 20 X(b_samepage) {
251 dpavlin 14 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
252     }
253 dpavlin 20 X(b_samepage__eq) {
254     cpu->cd.arm.next_ic = (struct arm_instr_call *)
255     ic->arg[cpu->cd.arm.flags & ARM_F_Z? 0 : 1];
256     }
257     X(b_samepage__ne) {
258     cpu->cd.arm.next_ic = (struct arm_instr_call *)
259     ic->arg[cpu->cd.arm.flags & ARM_F_Z? 1 : 0];
260     }
261     X(b_samepage__cs) {
262     cpu->cd.arm.next_ic = (struct arm_instr_call *)
263     ic->arg[cpu->cd.arm.flags & ARM_F_C? 0 : 1];
264     }
265     X(b_samepage__cc) {
266     cpu->cd.arm.next_ic = (struct arm_instr_call *)
267     ic->arg[cpu->cd.arm.flags & ARM_F_C? 1 : 0];
268     }
269     X(b_samepage__mi) {
270     cpu->cd.arm.next_ic = (struct arm_instr_call *)
271     ic->arg[cpu->cd.arm.flags & ARM_F_N? 0 : 1];
272     }
273     X(b_samepage__pl) {
274     cpu->cd.arm.next_ic = (struct arm_instr_call *)
275     ic->arg[cpu->cd.arm.flags & ARM_F_N? 1 : 0];
276     }
277     X(b_samepage__vs) {
278     cpu->cd.arm.next_ic = (struct arm_instr_call *)
279     ic->arg[cpu->cd.arm.flags & ARM_F_V? 0 : 1];
280     }
281     X(b_samepage__vc) {
282     cpu->cd.arm.next_ic = (struct arm_instr_call *)
283     ic->arg[cpu->cd.arm.flags & ARM_F_V? 1 : 0];
284     }
285     X(b_samepage__hi) {
286     cpu->cd.arm.next_ic = (condition_hi[cpu->cd.arm.flags])?
287     (struct arm_instr_call *) ic->arg[0] :
288     (struct arm_instr_call *) ic->arg[1];
289     }
290     X(b_samepage__ls) {
291     cpu->cd.arm.next_ic = (struct arm_instr_call *)
292     ic->arg[condition_hi[cpu->cd.arm.flags]];
293     }
294     X(b_samepage__ge) {
295     cpu->cd.arm.next_ic = (condition_ge[cpu->cd.arm.flags])?
296     (struct arm_instr_call *) ic->arg[0] :
297     (struct arm_instr_call *) ic->arg[1];
298     }
299     X(b_samepage__lt) {
300     cpu->cd.arm.next_ic = (struct arm_instr_call *)
301     ic->arg[condition_ge[cpu->cd.arm.flags]];
302     }
303     X(b_samepage__gt) {
304     cpu->cd.arm.next_ic = (condition_gt[cpu->cd.arm.flags])?
305     (struct arm_instr_call *) ic->arg[0] :
306     (struct arm_instr_call *) ic->arg[1];
307     }
308     X(b_samepage__le) {
309     cpu->cd.arm.next_ic = (struct arm_instr_call *)
310     ic->arg[condition_gt[cpu->cd.arm.flags]];
311     }
312     void (*arm_cond_instr_b_samepage[16])(struct cpu *,
313     struct arm_instr_call *) = {
314     arm_instr_b_samepage__eq, arm_instr_b_samepage__ne,
315     arm_instr_b_samepage__cs, arm_instr_b_samepage__cc,
316     arm_instr_b_samepage__mi, arm_instr_b_samepage__pl,
317     arm_instr_b_samepage__vs, arm_instr_b_samepage__vc,
318     arm_instr_b_samepage__hi, arm_instr_b_samepage__ls,
319     arm_instr_b_samepage__ge, arm_instr_b_samepage__lt,
320     arm_instr_b_samepage__gt, arm_instr_b_samepage__le,
321     arm_instr_b_samepage, arm_instr_nop };
322 dpavlin 14
323    
324     /*
325     * bx: Branch, potentially exchanging Thumb/ARM encoding
326     *
327     * arg[0] = ptr to rm
328     */
329     X(bx)
330     {
331 dpavlin 20 cpu->pc = reg(ic->arg[0]);
332 dpavlin 14 if (cpu->pc & 1) {
333     fatal("thumb: TODO\n");
334     exit(1);
335     }
336     cpu->pc &= ~3;
337    
338     /* Find the new physical page and update the translation pointers: */
339 dpavlin 18 quick_pc_to_pointers(cpu);
340 dpavlin 14 }
341     Y(bx)
342    
343    
344     /*
345     * bx_trace: As bx, but with trace enabled, arg[0] = the link register.
346     *
347     * arg[0] = ignored
348     */
349     X(bx_trace)
350     {
351 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
352 dpavlin 14 if (cpu->pc & 1) {
353     fatal("thumb: TODO\n");
354     exit(1);
355     }
356     cpu->pc &= ~3;
357    
358     cpu_functioncall_trace_return(cpu);
359    
360     /* Find the new physical page and update the translation pointers: */
361 dpavlin 18 quick_pc_to_pointers(cpu);
362 dpavlin 14 }
363     Y(bx_trace)
364    
365    
366     /*
367     * bl: Branch and Link (to a different translated page)
368     *
369     * arg[0] = relative address
370     */
371     X(bl)
372     {
373 dpavlin 20 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
374     cpu->cd.arm.r[ARM_LR] = pc + 4;
375 dpavlin 14
376     /* Calculate new PC from this instruction + arg[0] */
377 dpavlin 20 cpu->pc = pc + (int32_t)ic->arg[0];
378 dpavlin 14
379     /* Find the new physical page and update the translation pointers: */
380 dpavlin 18 quick_pc_to_pointers(cpu);
381 dpavlin 14 }
382     Y(bl)
383    
384    
385     /*
386     * blx: Branch and Link, potentially exchanging Thumb/ARM encoding
387     *
388     * arg[0] = ptr to rm
389     */
390     X(blx)
391     {
392 dpavlin 20 uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
393 dpavlin 14 cpu->cd.arm.r[ARM_LR] = lr;
394 dpavlin 20 cpu->pc = reg(ic->arg[0]);
395 dpavlin 14 if (cpu->pc & 1) {
396     fatal("thumb: TODO\n");
397     exit(1);
398     }
399     cpu->pc &= ~3;
400    
401     /* Find the new physical page and update the translation pointers: */
402 dpavlin 18 quick_pc_to_pointers(cpu);
403 dpavlin 14 }
404     Y(blx)
405    
406    
407     /*
408     * bl_trace: Branch and Link (to a different translated page), with trace
409     *
410     * Same as for bl.
411     */
412     X(bl_trace)
413     {
414 dpavlin 20 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
415     cpu->cd.arm.r[ARM_LR] = pc + 4;
416 dpavlin 14
417     /* Calculate new PC from this instruction + arg[0] */
418 dpavlin 20 cpu->pc = pc + (int32_t)ic->arg[0];
419 dpavlin 14
420     cpu_functioncall_trace(cpu, cpu->pc);
421    
422     /* Find the new physical page and update the translation pointers: */
423 dpavlin 18 quick_pc_to_pointers(cpu);
424 dpavlin 14 }
425     Y(bl_trace)
426    
427    
428     /*
429     * bl_samepage: A branch + link within the same page
430     *
431     * arg[0] = pointer to new arm_instr_call
432     */
433     X(bl_samepage)
434     {
435 dpavlin 20 cpu->cd.arm.r[ARM_LR] =
436     ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
437 dpavlin 14 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
438     }
439     Y(bl_samepage)
440    
441    
442     /*
443     * bl_samepage_trace: Branch and Link (to the same page), with trace
444     *
445     * Same as for bl_samepage.
446     */
447     X(bl_samepage_trace)
448     {
449 dpavlin 20 uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
450 dpavlin 14
451 dpavlin 20 /* Link and branch: */
452 dpavlin 14 cpu->cd.arm.r[ARM_LR] = lr;
453     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
454    
455 dpavlin 20 /* Synchronize the program counter: */
456 dpavlin 14 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
457     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
458 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
459 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
460 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
461    
462     /* ... and show trace: */
463     cpu_functioncall_trace(cpu, cpu->pc);
464 dpavlin 14 }
465     Y(bl_samepage_trace)
466    
467    
468 dpavlin 20 /*
469     * clz: Count leading zeroes.
470     *
471     * arg[0] = ptr to rm
472     * arg[1] = ptr to rd
473     */
474     X(clz)
475     {
476     uint32_t rm = reg(ic->arg[0]);
477     int i = 32, n = 0, j;
478     while (i>0) {
479     if (rm & 0xff000000) {
480     for (j=0; j<8; j++) {
481     if (rm & 0x80000000)
482     break;
483     n ++;
484     rm <<= 1;
485     }
486     break;
487     } else {
488     rm <<= 8;
489     i -= 8;
490     n += 8;
491     }
492     }
493     reg(ic->arg[1]) = n;
494     }
495     Y(clz)
496 dpavlin 18
497    
498 dpavlin 14 /*
499     * mul: Multiplication
500     *
501     * arg[0] = ptr to rd
502     * arg[1] = ptr to rm
503     * arg[2] = ptr to rs
504     */
505     X(mul)
506     {
507     reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
508     }
509     Y(mul)
510     X(muls)
511     {
512 dpavlin 18 uint32_t result;
513     result = reg(ic->arg[1]) * reg(ic->arg[2]);
514 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
515 dpavlin 14 if (result == 0)
516 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
517 dpavlin 14 if (result & 0x80000000)
518 dpavlin 20 cpu->cd.arm.flags |= ARM_F_N;
519 dpavlin 14 reg(ic->arg[0]) = result;
520     }
521     Y(muls)
522    
523    
524     /*
525     * mla: Multiplication with addition
526     *
527     * arg[0] = copy of instruction word
528     */
529     X(mla)
530     {
531     /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
532     uint32_t iw = ic->arg[0];
533 dpavlin 18 int rd, rs, rn, rm;
534     rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
535     rs = (iw >> 8) & 15; rm = iw & 15;
536 dpavlin 14 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
537     + cpu->cd.arm.r[rn];
538     }
539     Y(mla)
540     X(mlas)
541     {
542     /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
543     uint32_t iw = ic->arg[0];
544 dpavlin 18 int rd, rs, rn, rm;
545     rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
546     rs = (iw >> 8) & 15; rm = iw & 15;
547 dpavlin 14 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
548     + cpu->cd.arm.r[rn];
549 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
550 dpavlin 14 if (cpu->cd.arm.r[rd] == 0)
551 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
552 dpavlin 14 if (cpu->cd.arm.r[rd] & 0x80000000)
553 dpavlin 20 cpu->cd.arm.flags |= ARM_F_N;
554 dpavlin 14 }
555     Y(mlas)
556    
557    
558     /*
559     * mull: Long multiplication
560     *
561     * arg[0] = copy of instruction word
562     */
563     X(mull)
564     {
565     /* xxxx0000 1UAShhhh llllssss 1001mmmm */
566 dpavlin 18 uint32_t iw; uint64_t tmp; int u_bit, a_bit;
567     iw = ic->arg[0];
568 dpavlin 20 u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
569 dpavlin 18 tmp = cpu->cd.arm.r[iw & 15];
570 dpavlin 14 if (u_bit)
571     tmp = (int64_t)(int32_t)tmp
572     * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
573     else
574     tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
575     if (a_bit) {
576     uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
577     | cpu->cd.arm.r[(iw >> 12) & 15];
578     x += tmp;
579     cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
580     cpu->cd.arm.r[(iw >> 12) & 15] = x;
581     } else {
582     cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
583     cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
584     }
585     }
586     Y(mull)
587    
588    
589     /*
590     * mov_reg_reg: Move a register to another.
591     *
592     * arg[0] = ptr to source register
593     * arg[1] = ptr to destination register
594     */
595     X(mov_reg_reg)
596     {
597     reg(ic->arg[1]) = reg(ic->arg[0]);
598     }
599     Y(mov_reg_reg)
600    
601    
602     /*
603 dpavlin 20 * mov_reg_pc: Move the PC register to a normal register.
604     *
605     * arg[0] = offset compared to start of current page + 8
606     * arg[1] = ptr to destination register
607     */
608     X(mov_reg_pc)
609     {
610     reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0];
611     }
612     Y(mov_reg_pc)
613    
614    
615     /*
616 dpavlin 14 * ret_trace: "mov pc,lr" with trace enabled
617 dpavlin 18 * ret: "mov pc,lr" without trace enabled
618 dpavlin 14 *
619     * arg[0] = ignored
620     */
621     X(ret_trace)
622     {
623 dpavlin 18 uint32_t old_pc, mask_within_page;
624 dpavlin 20 old_pc = cpu->pc;
625 dpavlin 18 mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
626 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT) |
627     ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
628    
629     /* Update the PC register: */
630 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
631 dpavlin 14
632     cpu_functioncall_trace_return(cpu);
633    
634     /*
635     * Is this a return to code within the same page? Then there is no
636     * need to update all pointers, just next_ic.
637     */
638     if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
639     cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
640     ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
641     } else {
642     /* Find the new physical page and update pointers: */
643 dpavlin 18 quick_pc_to_pointers(cpu);
644 dpavlin 14 }
645     }
646     Y(ret_trace)
647 dpavlin 18 X(ret)
648     {
649 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
650 dpavlin 18 quick_pc_to_pointers(cpu);
651     }
652     Y(ret)
653 dpavlin 14
654    
655     /*
656     * msr: Move to status register from a normal register or immediate value.
657     *
658     * arg[0] = immediate value
659     * arg[1] = mask
660     * arg[2] = pointer to rm
661     *
662     * msr_imm and msr_imm_spsr use arg[1] and arg[0].
663     * msr and msr_spsr use arg[1] and arg[2].
664     */
665     X(msr_imm)
666     {
667     uint32_t mask = ic->arg[1];
668     int switch_register_banks = (mask & ARM_FLAG_MODE) &&
669     ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
670     (ic->arg[0] & ARM_FLAG_MODE));
671     uint32_t new_value = ic->arg[0];
672    
673 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
674     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
675    
676 dpavlin 14 if (switch_register_banks)
677     arm_save_register_bank(cpu);
678    
679     cpu->cd.arm.cpsr &= ~mask;
680     cpu->cd.arm.cpsr |= (new_value & mask);
681    
682 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
683    
684 dpavlin 14 if (switch_register_banks)
685     arm_load_register_bank(cpu);
686     }
687     Y(msr_imm)
688     X(msr)
689     {
690     ic->arg[0] = reg(ic->arg[2]);
691     instr(msr_imm)(cpu, ic);
692     }
693     Y(msr)
694     X(msr_imm_spsr)
695     {
696     uint32_t mask = ic->arg[1];
697     uint32_t new_value = ic->arg[0];
698     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
699     case ARM_MODE_FIQ32:
700     cpu->cd.arm.spsr_fiq &= ~mask;
701     cpu->cd.arm.spsr_fiq |= (new_value & mask);
702     break;
703     case ARM_MODE_ABT32:
704     cpu->cd.arm.spsr_abt &= ~mask;
705     cpu->cd.arm.spsr_abt |= (new_value & mask);
706     break;
707     case ARM_MODE_UND32:
708     cpu->cd.arm.spsr_und &= ~mask;
709     cpu->cd.arm.spsr_und |= (new_value & mask);
710     break;
711     case ARM_MODE_IRQ32:
712     cpu->cd.arm.spsr_irq &= ~mask;
713     cpu->cd.arm.spsr_irq |= (new_value & mask);
714     break;
715     case ARM_MODE_SVC32:
716     cpu->cd.arm.spsr_svc &= ~mask;
717     cpu->cd.arm.spsr_svc |= (new_value & mask);
718     break;
719     default:fatal("msr_spsr: unimplemented mode %i\n",
720     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
721     {
722     /* Synchronize the program counter: */
723     uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
724     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
725 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
726     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
727     old_pc = cpu->pc;
728     printf("msr_spsr: old pc = 0x%08x\n", old_pc);
729 dpavlin 14 }
730     exit(1);
731     }
732     }
733     Y(msr_imm_spsr)
734     X(msr_spsr)
735     {
736     ic->arg[0] = reg(ic->arg[2]);
737     instr(msr_imm_spsr)(cpu, ic);
738     }
739     Y(msr_spsr)
740    
741    
742     /*
743     * mrs: Move from status/flag register to a normal register.
744     *
745     * arg[0] = pointer to rd
746     */
747     X(mrs)
748     {
749 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
750     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
751 dpavlin 14 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
752     }
753     Y(mrs)
754    
755    
756     /*
757 dpavlin 20 * mrs: Move from saved status/flag register to a normal register.
758 dpavlin 14 *
759     * arg[0] = pointer to rd
760     */
761     X(mrs_spsr)
762     {
763     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
764     case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
765     case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
766     case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
767     case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
768     case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
769     case ARM_MODE_USR32:
770     case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
771     default:fatal("mrs_spsr: unimplemented mode %i\n",
772     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
773     exit(1);
774     }
775     }
776     Y(mrs_spsr)
777    
778    
779     /*
780     * mcr_mrc: Coprocessor move
781     * cdp: Coprocessor operation
782     *
783     * arg[0] = copy of the instruction word
784     */
785     X(mcr_mrc) {
786 dpavlin 20 uint32_t low_pc = ((size_t)ic - (size_t)
787 dpavlin 14 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
788 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
789     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
790 dpavlin 14 arm_mcr_mrc(cpu, ic->arg[0]);
791     }
792     Y(mcr_mrc)
793     X(cdp) {
794 dpavlin 20 uint32_t low_pc = ((size_t)ic - (size_t)
795 dpavlin 14 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
796 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
797     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
798 dpavlin 14 arm_cdp(cpu, ic->arg[0]);
799     }
800     Y(cdp)
801    
802    
803     /*
804     * openfirmware:
805     */
806     X(openfirmware)
807     {
808 dpavlin 20 /* TODO: sync pc? */
809 dpavlin 14 of_emul(cpu);
810 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
811 dpavlin 14 if (cpu->machine->show_trace_tree)
812     cpu_functioncall_trace_return(cpu);
813 dpavlin 18 quick_pc_to_pointers(cpu);
814 dpavlin 14 }
815    
816    
817     /*
818 dpavlin 20 * reboot:
819     */
820     X(reboot)
821     {
822     cpu->running = 0;
823     cpu->running_translated = 0;
824     cpu->n_translated_instrs --;
825     cpu->cd.arm.next_ic = &nothing_call;
826     }
827    
828    
829     /*
830 dpavlin 14 * swi_useremul: Syscall.
831     *
832     * arg[0] = swi number
833     */
834     X(swi_useremul)
835     {
836     /* Synchronize the program counter: */
837     uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
838     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
839 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
840 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
841 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
842     old_pc = cpu->pc;
843 dpavlin 14
844     useremul_syscall(cpu, ic->arg[0]);
845    
846     if (!cpu->running) {
847     cpu->running_translated = 0;
848     cpu->n_translated_instrs --;
849     cpu->cd.arm.next_ic = &nothing_call;
850     } else if (cpu->pc != old_pc) {
851     /* PC was changed by the SWI call. Find the new physical
852     page and update the translation pointers: */
853 dpavlin 18 quick_pc_to_pointers(cpu);
854 dpavlin 14 }
855     }
856     Y(swi_useremul)
857    
858    
859     /*
860     * swi: Software interrupt.
861     */
862     X(swi)
863     {
864 dpavlin 20 /* Synchronize the program counter first: */
865     cpu->pc &= 0xfffff000;
866     cpu->pc += ic->arg[0];
867 dpavlin 14 arm_exception(cpu, ARM_EXCEPTION_SWI);
868     }
869     Y(swi)
870    
871    
872     /*
873 dpavlin 20 * und: Undefined instruction.
874     */
875     X(und)
876     {
877     /* Synchronize the program counter first: */
878     cpu->pc &= 0xfffff000;
879     cpu->pc += ic->arg[0];
880     arm_exception(cpu, ARM_EXCEPTION_UND);
881     }
882     Y(und)
883    
884    
885     /*
886 dpavlin 14 * swp, swpb: Swap (word or byte).
887     *
888     * arg[0] = ptr to rd
889     * arg[1] = ptr to rm
890     * arg[2] = ptr to rn
891     */
892     X(swp)
893     {
894     uint32_t addr = reg(ic->arg[2]), data, data2;
895     unsigned char d[4];
896 dpavlin 20
897 dpavlin 14 /* Synchronize the program counter: */
898     uint32_t low_pc = ((size_t)ic - (size_t)
899     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
900 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
901     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
902 dpavlin 14
903     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
904     CACHE_DATA)) {
905     fatal("swp: load failed\n");
906     return;
907     }
908     data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
909     data2 = reg(ic->arg[1]);
910     d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
911     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
912     CACHE_DATA)) {
913     fatal("swp: store failed\n");
914     return;
915     }
916     reg(ic->arg[0]) = data;
917     }
918     Y(swp)
919     X(swpb)
920     {
921     uint32_t addr = reg(ic->arg[2]), data;
922     unsigned char d[1];
923 dpavlin 20
924 dpavlin 14 /* Synchronize the program counter: */
925     uint32_t low_pc = ((size_t)ic - (size_t)
926     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
927 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
928     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
929 dpavlin 14
930     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
931     CACHE_DATA)) {
932     fatal("swp: load failed\n");
933     return;
934     }
935     data = d[0];
936     d[0] = reg(ic->arg[1]);
937     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
938     CACHE_DATA)) {
939     fatal("swp: store failed\n");
940     return;
941     }
942     reg(ic->arg[0]) = data;
943     }
944     Y(swpb)
945    
946    
947     extern void (*arm_load_store_instr[1024])(struct cpu *,
948     struct arm_instr_call *);
949 dpavlin 20 X(store_w1_word_u1_p0_imm);
950 dpavlin 14 X(store_w0_byte_u1_p0_imm);
951     X(store_w0_word_u1_p0_imm);
952 dpavlin 20 X(store_w0_word_u1_p1_imm);
953     X(load_w1_word_u1_p0_imm);
954 dpavlin 18 X(load_w0_word_u1_p0_imm);
955     X(load_w0_byte_u1_p1_imm);
956     X(load_w0_byte_u1_p1_reg);
957 dpavlin 20 X(load_w1_byte_u1_p1_imm);
958 dpavlin 14
959     extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
960     struct arm_instr_call *);
961    
962     extern void (*arm_load_store_instr_3[2048])(struct cpu *,
963     struct arm_instr_call *);
964    
965     extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
966     struct arm_instr_call *);
967    
968 dpavlin 16 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
969 dpavlin 20 extern void arm_r_r3_t0_c0(void);
970 dpavlin 16
971 dpavlin 14 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
972     struct arm_instr_call *);
973 dpavlin 20 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
974     struct arm_instr_call *);
975 dpavlin 14 X(cmps);
976 dpavlin 20 X(teqs);
977     X(tsts);
978 dpavlin 14 X(sub);
979 dpavlin 18 X(add);
980 dpavlin 14 X(subs);
981 dpavlin 20 X(eor_regshort);
982     X(cmps_regshort);
983 dpavlin 14
984    
985 dpavlin 20 #include "cpu_arm_instr_misc.c"
986 dpavlin 14
987 dpavlin 20
988 dpavlin 14 /*
989     * bdt_load: Block Data Transfer, Load
990     *
991     * arg[0] = pointer to uint32_t in host memory, pointing to the base register
992     * arg[1] = 32-bit instruction word. Most bits are read from this.
993     */
994     X(bdt_load)
995     {
996     unsigned char data[4];
997     uint32_t *np = (uint32_t *)ic->arg[0];
998     uint32_t addr = *np, low_pc;
999     unsigned char *page;
1000     uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1001     int p_bit = iw & 0x01000000;
1002     int u_bit = iw & 0x00800000;
1003     int s_bit = iw & 0x00400000;
1004     int w_bit = iw & 0x00200000;
1005 dpavlin 16 int i, return_flag = 0;
1006 dpavlin 14 uint32_t new_values[16];
1007    
1008 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1009     if (!s_bit)
1010     update_bdt_statistics(iw);
1011     #endif
1012    
1013 dpavlin 14 /* Synchronize the program counter: */
1014     low_pc = ((size_t)ic - (size_t)
1015     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1016 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1017     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1018 dpavlin 14
1019     if (s_bit) {
1020 dpavlin 16 /* Load to USR registers: */
1021 dpavlin 14 if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
1022     fatal("[ bdt_load: s-bit: in usermode? ]\n");
1023     s_bit = 0;
1024 dpavlin 16 }
1025     if (iw & 0x8000) {
1026 dpavlin 14 s_bit = 0;
1027     return_flag = 1;
1028     }
1029     }
1030    
1031     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1032     uint32_t value;
1033    
1034     if (!((iw >> i) & 1)) {
1035     /* Skip register i: */
1036     continue;
1037     }
1038    
1039     if (p_bit) {
1040     if (u_bit)
1041     addr += sizeof(uint32_t);
1042     else
1043     addr -= sizeof(uint32_t);
1044     }
1045    
1046     page = cpu->cd.arm.host_load[addr >> 12];
1047     if (page != NULL) {
1048     uint32_t *p32 = (uint32_t *) page;
1049     value = p32[(addr & 0xfff) >> 2];
1050     /* Change byte order of value if
1051     host and emulated endianness differ: */
1052     #ifdef HOST_LITTLE_ENDIAN
1053     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1054     #else
1055     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1056     #endif
1057     value = ((value & 0xff) << 24) |
1058     ((value & 0xff00) << 8) |
1059     ((value & 0xff0000) >> 8) |
1060     ((value & 0xff000000) >> 24);
1061     } else {
1062     if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1063     sizeof(data), MEM_READ, CACHE_DATA)) {
1064     /* load failed */
1065     return;
1066     }
1067     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1068     value = data[0] +
1069     (data[1] << 8) + (data[2] << 16)
1070     + (data[3] << 24);
1071     } else {
1072     value = data[3] +
1073     (data[2] << 8) + (data[1] << 16)
1074     + (data[0] << 24);
1075     }
1076     }
1077    
1078     new_values[i] = value;
1079    
1080     if (!p_bit) {
1081     if (u_bit)
1082     addr += sizeof(uint32_t);
1083     else
1084     addr -= sizeof(uint32_t);
1085     }
1086     }
1087    
1088     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1089     if (!((iw >> i) & 1)) {
1090     /* Skip register i: */
1091     continue;
1092     }
1093    
1094     if (!s_bit) {
1095     cpu->cd.arm.r[i] = new_values[i];
1096     } else {
1097 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1098 dpavlin 14 case ARM_MODE_USR32:
1099     case ARM_MODE_SYS32:
1100 dpavlin 16 cpu->cd.arm.r[i] = new_values[i];
1101 dpavlin 14 break;
1102     case ARM_MODE_FIQ32:
1103     if (i >= 8 && i <= 14)
1104 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1105 dpavlin 14 new_values[i];
1106     else
1107     cpu->cd.arm.r[i] = new_values[i];
1108     break;
1109     case ARM_MODE_SVC32:
1110     case ARM_MODE_ABT32:
1111     case ARM_MODE_UND32:
1112 dpavlin 16 case ARM_MODE_IRQ32:
1113 dpavlin 14 if (i >= 13 && i <= 14)
1114 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1115 dpavlin 14 new_values[i];
1116     else
1117     cpu->cd.arm.r[i] = new_values[i];
1118     break;
1119     }
1120     }
1121     }
1122    
1123     if (w_bit)
1124     *np = addr;
1125    
1126     if (return_flag) {
1127     uint32_t new_cpsr;
1128     int switch_register_banks;
1129    
1130     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1131     case ARM_MODE_FIQ32:
1132     new_cpsr = cpu->cd.arm.spsr_fiq; break;
1133     case ARM_MODE_ABT32:
1134     new_cpsr = cpu->cd.arm.spsr_abt; break;
1135     case ARM_MODE_UND32:
1136     new_cpsr = cpu->cd.arm.spsr_und; break;
1137     case ARM_MODE_IRQ32:
1138     new_cpsr = cpu->cd.arm.spsr_irq; break;
1139     case ARM_MODE_SVC32:
1140     new_cpsr = cpu->cd.arm.spsr_svc; break;
1141     default:fatal("bdt_load: unimplemented mode %i\n",
1142     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1143     exit(1);
1144     }
1145    
1146     switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
1147     (new_cpsr & ARM_FLAG_MODE);
1148    
1149     if (switch_register_banks)
1150     arm_save_register_bank(cpu);
1151    
1152     cpu->cd.arm.cpsr = new_cpsr;
1153 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1154 dpavlin 14
1155     if (switch_register_banks)
1156     arm_load_register_bank(cpu);
1157     }
1158    
1159     /* NOTE: Special case: Loading the PC */
1160     if (iw & 0x8000) {
1161 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1162 dpavlin 14 if (cpu->machine->show_trace_tree)
1163     cpu_functioncall_trace_return(cpu);
1164     /* TODO: There is no need to update the
1165     pointers if this is a return to the
1166     same page! */
1167     /* Find the new physical page and update the
1168     translation pointers: */
1169 dpavlin 18 quick_pc_to_pointers(cpu);
1170 dpavlin 14 }
1171     }
1172     Y(bdt_load)
1173    
1174    
1175     /*
1176     * bdt_store: Block Data Transfer, Store
1177     *
1178     * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1179     * arg[1] = 32-bit instruction word. Most bits are read from this.
1180     */
1181     X(bdt_store)
1182     {
1183     unsigned char data[4];
1184     uint32_t *np = (uint32_t *)ic->arg[0];
1185     uint32_t low_pc, value, addr = *np;
1186     uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1187     unsigned char *page;
1188     int p_bit = iw & 0x01000000;
1189     int u_bit = iw & 0x00800000;
1190     int s_bit = iw & 0x00400000;
1191     int w_bit = iw & 0x00200000;
1192 dpavlin 16 int i;
1193 dpavlin 14
1194 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1195     if (!s_bit)
1196     update_bdt_statistics(iw);
1197     #endif
1198    
1199 dpavlin 14 /* Synchronize the program counter: */
1200     low_pc = ((size_t)ic - (size_t)
1201     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1202 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1203     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1204 dpavlin 14
1205     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1206     if (!((iw >> i) & 1)) {
1207     /* Skip register i: */
1208     continue;
1209     }
1210    
1211     value = cpu->cd.arm.r[i];
1212    
1213     if (s_bit) {
1214 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1215 dpavlin 14 case ARM_MODE_FIQ32:
1216     if (i >= 8 && i <= 14)
1217 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1218 dpavlin 14 break;
1219     case ARM_MODE_ABT32:
1220     case ARM_MODE_UND32:
1221     case ARM_MODE_IRQ32:
1222     case ARM_MODE_SVC32:
1223     if (i >= 13 && i <= 14)
1224 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1225 dpavlin 14 break;
1226     case ARM_MODE_USR32:
1227     case ARM_MODE_SYS32:
1228     break;
1229     }
1230     }
1231    
1232 dpavlin 20 /* NOTE/TODO: 8 vs 12 on some ARMs */
1233 dpavlin 14 if (i == ARM_PC)
1234 dpavlin 20 value = cpu->pc + 12;
1235 dpavlin 14
1236     if (p_bit) {
1237     if (u_bit)
1238     addr += sizeof(uint32_t);
1239     else
1240     addr -= sizeof(uint32_t);
1241     }
1242    
1243     page = cpu->cd.arm.host_store[addr >> 12];
1244     if (page != NULL) {
1245     uint32_t *p32 = (uint32_t *) page;
1246     /* Change byte order of value if
1247     host and emulated endianness differ: */
1248     #ifdef HOST_LITTLE_ENDIAN
1249     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1250     #else
1251     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1252     #endif
1253     value = ((value & 0xff) << 24) |
1254     ((value & 0xff00) << 8) |
1255     ((value & 0xff0000) >> 8) |
1256     ((value & 0xff000000) >> 24);
1257     p32[(addr & 0xfff) >> 2] = value;
1258     } else {
1259     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1260     data[0] = value;
1261     data[1] = value >> 8;
1262     data[2] = value >> 16;
1263     data[3] = value >> 24;
1264     } else {
1265     data[0] = value >> 24;
1266     data[1] = value >> 16;
1267     data[2] = value >> 8;
1268     data[3] = value;
1269     }
1270     if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1271     sizeof(data), MEM_WRITE, CACHE_DATA)) {
1272     /* store failed */
1273     return;
1274     }
1275     }
1276    
1277     if (!p_bit) {
1278     if (u_bit)
1279     addr += sizeof(uint32_t);
1280     else
1281     addr -= sizeof(uint32_t);
1282     }
1283     }
1284    
1285     if (w_bit)
1286     *np = addr;
1287     }
1288     Y(bdt_store)
1289    
1290    
1291 dpavlin 18 /* Various load/store multiple instructions: */
1292 dpavlin 20 uint32_t *multi_opcode[256];
1293     void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1294     X(multi_0x08b15018);
1295     X(multi_0x08ac000c__ge);
1296     X(multi_0x08a05018);
1297 dpavlin 18
1298    
1299 dpavlin 14 /*****************************************************************************/
1300    
1301    
1302     /*
1303 dpavlin 18 * netbsd_memset:
1304     *
1305     * The core of a NetBSD/arm memset.
1306     *
1307     * f01bc420: e25XX080 subs rX,rX,#0x80
1308     * f01bc424: a8ac000c stmgeia ip!,{r2,r3} (16 of these)
1309     * ..
1310     * f01bc464: caffffed bgt 0xf01bc420 <memset+0x38>
1311     */
1312     X(netbsd_memset)
1313     {
1314     unsigned char *page;
1315     uint32_t addr;
1316    
1317     do {
1318     addr = cpu->cd.arm.r[ARM_IP];
1319    
1320     instr(subs)(cpu, ic);
1321    
1322 dpavlin 20 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1323     ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1324 dpavlin 18 cpu->n_translated_instrs += 16;
1325     /* Skip the store multiples: */
1326     cpu->cd.arm.next_ic = &ic[17];
1327     return;
1328     }
1329    
1330     /* Crossing a page boundary? Then continue non-combined. */
1331     if ((addr & 0xfff) + 128 > 0x1000)
1332     return;
1333    
1334     /* R2/R3 non-zero? Not allowed here. */
1335     if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0)
1336     return;
1337    
1338     /* printf("addr = 0x%08x\n", addr); */
1339    
1340     page = cpu->cd.arm.host_store[addr >> 12];
1341     /* No page translation? Continue non-combined. */
1342     if (page == NULL)
1343     return;
1344    
1345     /* Clear: */
1346     memset(page + (addr & 0xfff), 0, 128);
1347     cpu->cd.arm.r[ARM_IP] = addr + 128;
1348     cpu->n_translated_instrs += 16;
1349    
1350     /* Branch back if greater: */
1351     cpu->n_translated_instrs += 1;
1352 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1353     ((cpu->cd.arm.flags & ARM_F_V)?1:0) &&
1354     !(cpu->cd.arm.flags & ARM_F_Z));
1355 dpavlin 18
1356     /* Continue at the instruction after the bgt: */
1357     cpu->cd.arm.next_ic = &ic[18];
1358     }
1359    
1360    
1361     /*
1362     * netbsd_memcpy:
1363     *
1364     * The core of a NetBSD/arm memcpy.
1365     *
1366     * f01bc530: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1367     * f01bc534: e8a05018 stmia r0!,{r3,r4,ip,lr}
1368     * f01bc538: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1369     * f01bc53c: e8a05018 stmia r0!,{r3,r4,ip,lr}
1370     * f01bc540: e2522020 subs r2,r2,#0x20
1371     * f01bc544: aafffff9 bge 0xf01bc530
1372     */
1373     X(netbsd_memcpy)
1374     {
1375     unsigned char *page_0, *page_1;
1376     uint32_t addr_r0, addr_r1;
1377    
1378     do {
1379     addr_r0 = cpu->cd.arm.r[0];
1380     addr_r1 = cpu->cd.arm.r[1];
1381    
1382     /* printf("addr_r0 = %08x r1 = %08x\n", addr_r0, addr_r1); */
1383    
1384     /* Crossing a page boundary? Then continue non-combined. */
1385     if ((addr_r0 & 0xfff) + 32 > 0x1000 ||
1386     (addr_r1 & 0xfff) + 32 > 0x1000) {
1387     instr(multi_0x08b15018)(cpu, ic);
1388     return;
1389     }
1390    
1391     page_0 = cpu->cd.arm.host_store[addr_r0 >> 12];
1392     page_1 = cpu->cd.arm.host_store[addr_r1 >> 12];
1393    
1394     /* No page translations? Continue non-combined. */
1395     if (page_0 == NULL || page_1 == NULL) {
1396     instr(multi_0x08b15018)(cpu, ic);
1397     return;
1398     }
1399    
1400     memcpy(page_0 + (addr_r0 & 0xfff),
1401     page_1 + (addr_r1 & 0xfff), 32);
1402     cpu->cd.arm.r[0] = addr_r0 + 32;
1403     cpu->cd.arm.r[1] = addr_r1 + 32;
1404    
1405     cpu->n_translated_instrs += 4;
1406    
1407     instr(subs)(cpu, ic + 4);
1408     cpu->n_translated_instrs ++;
1409    
1410     /* Loop while greater or equal: */
1411     cpu->n_translated_instrs ++;
1412 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1413     ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1414 dpavlin 18
1415     /* Continue at the instruction after the bge: */
1416     cpu->cd.arm.next_ic = &ic[6];
1417     cpu->n_translated_instrs --;
1418     }
1419    
1420    
1421     /*
1422     * netbsd_cacheclean:
1423     *
1424     * The core of a NetBSD/arm cache clean routine, variant 1:
1425     *
1426     * f015f88c: e4902020 ldr r2,[r0],#32
1427     * f015f890: e2511020 subs r1,r1,#0x20
1428     * f015f894: 1afffffc bne 0xf015f88c
1429     * f015f898: ee070f9a mcr 15,0,r0,cr7,cr10,4
1430     */
1431     X(netbsd_cacheclean)
1432     {
1433     uint32_t r1 = cpu->cd.arm.r[1];
1434     cpu->n_translated_instrs += ((r1 >> 5) * 3);
1435 dpavlin 20 cpu->cd.arm.r[0] += r1;
1436     cpu->cd.arm.r[1] = 0;
1437 dpavlin 18 cpu->cd.arm.next_ic = &ic[4];
1438     }
1439    
1440    
1441     /*
1442     * netbsd_cacheclean2:
1443     *
1444     * The core of a NetBSD/arm cache clean routine, variant 2:
1445     *
1446     * f015f93c: ee070f3a mcr 15,0,r0,cr7,cr10,1
1447     * f015f940: ee070f36 mcr 15,0,r0,cr7,cr6,1
1448     * f015f944: e2800020 add r0,r0,#0x20
1449     * f015f948: e2511020 subs r1,r1,#0x20
1450     * f015f94c: 8afffffa bhi 0xf015f93c
1451     */
1452     X(netbsd_cacheclean2)
1453     {
1454     cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1;
1455     cpu->cd.arm.next_ic = &ic[5];
1456     }
1457    
1458    
1459     /*
1460     * netbsd_scanc:
1461     *
1462     * f01bccbc: e5d13000 ldrb r3,[r1]
1463     * f01bccc0: e7d23003 ldrb r3,[r2,r3]
1464     * f01bccc4: e113000c tsts r3,ip
1465     */
1466     X(netbsd_scanc)
1467     {
1468     unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12];
1469     uint32_t t;
1470    
1471     if (page == NULL) {
1472     instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1473     return;
1474     }
1475    
1476     t = page[cpu->cd.arm.r[1] & 0xfff];
1477     t += cpu->cd.arm.r[2];
1478     page = cpu->cd.arm.host_load[t >> 12];
1479    
1480     if (page == NULL) {
1481     instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1482     return;
1483     }
1484    
1485     cpu->cd.arm.r[3] = page[t & 0xfff];
1486    
1487     t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP];
1488 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1489 dpavlin 18 if (t == 0)
1490 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
1491 dpavlin 18
1492     cpu->n_translated_instrs += 2;
1493     cpu->cd.arm.next_ic = &ic[3];
1494     }
1495    
1496    
1497 dpavlin 20 /*
1498     * strlen:
1499     *
1500     * S: e5f03001 ldrb rY,[rX,#1]!
1501     * e3530000 cmps rY,#0
1502     * 1afffffc bne S
1503     */
1504     X(strlen)
1505     {
1506     unsigned int n_loops = 0;
1507     uint32_t rY, rX = reg(ic[0].arg[0]);
1508     unsigned char *p;
1509    
1510     do {
1511     rX ++;
1512     p = cpu->cd.arm.host_load[rX >> 12];
1513     if (p == NULL) {
1514     cpu->n_translated_instrs += (n_loops * 3);
1515     instr(load_w1_byte_u1_p1_imm)(cpu, ic);
1516     return;
1517     }
1518    
1519     rY = reg(ic[0].arg[2]) = p[rX & 0xfff]; /* load */
1520     reg(ic[0].arg[0]) = rX; /* writeback */
1521     n_loops ++;
1522    
1523     /* Compare rY to zero: */
1524     cpu->cd.arm.flags = ARM_F_C;
1525     if (rY == 0)
1526     cpu->cd.arm.flags |= ARM_F_Z;
1527     } while (rY != 0);
1528    
1529     cpu->n_translated_instrs += (n_loops * 3) - 1;
1530     cpu->cd.arm.next_ic = &ic[3];
1531     }
1532    
1533    
1534     /*
1535     * xchg:
1536     *
1537     * e02YX00X eor rX,rY,rX
1538     * e02XY00Y eor rY,rX,rY
1539     * e02YX00X eor rX,rY,rX
1540     */
1541     X(xchg)
1542     {
1543     uint32_t tmp = reg(ic[0].arg[0]);
1544     cpu->n_translated_instrs += 2;
1545     cpu->cd.arm.next_ic = &ic[3];
1546     reg(ic[0].arg[0]) = reg(ic[1].arg[0]);
1547     reg(ic[1].arg[0]) = tmp;
1548     }
1549    
1550    
1551     /*
1552     * netbsd_copyin:
1553     *
1554     * e4b0a004 ldrt sl,[r0],#4
1555     * e4b0b004 ldrt fp,[r0],#4
1556     * e4b06004 ldrt r6,[r0],#4
1557     * e4b07004 ldrt r7,[r0],#4
1558     * e4b08004 ldrt r8,[r0],#4
1559     * e4b09004 ldrt r9,[r0],#4
1560     */
1561     X(netbsd_copyin)
1562     {
1563     uint32_t r0 = cpu->cd.arm.r[0], ofs = (r0 & 0xffc), index = r0 >> 12;
1564     unsigned char *p = cpu->cd.arm.host_load[index];
1565     uint32_t *p32 = (uint32_t *) p, *q32;
1566     int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1567    
1568     if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1569     instr(load_w1_word_u1_p0_imm)(cpu, ic);
1570     return;
1571     }
1572     q32 = &cpu->cd.arm.r[6];
1573     ofs >>= 2;
1574     q32[0] = p32[ofs+2];
1575     q32[1] = p32[ofs+3];
1576     q32[2] = p32[ofs+4];
1577     q32[3] = p32[ofs+5];
1578     q32[4] = p32[ofs+0];
1579     q32[5] = p32[ofs+1];
1580     cpu->cd.arm.r[0] = r0 + 24;
1581     cpu->n_translated_instrs += 5;
1582     cpu->cd.arm.next_ic = &ic[6];
1583     }
1584    
1585    
1586     /*
1587     * netbsd_copyout:
1588     *
1589     * e4a18004 strt r8,[r1],#4
1590     * e4a19004 strt r9,[r1],#4
1591     * e4a1a004 strt sl,[r1],#4
1592     * e4a1b004 strt fp,[r1],#4
1593     * e4a16004 strt r6,[r1],#4
1594     * e4a17004 strt r7,[r1],#4
1595     */
1596     X(netbsd_copyout)
1597     {
1598     uint32_t r1 = cpu->cd.arm.r[1], ofs = (r1 & 0xffc), index = r1 >> 12;
1599     unsigned char *p = cpu->cd.arm.host_store[index];
1600     uint32_t *p32 = (uint32_t *) p, *q32;
1601     int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1602    
1603     if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1604     instr(store_w1_word_u1_p0_imm)(cpu, ic);
1605     return;
1606     }
1607     q32 = &cpu->cd.arm.r[6];
1608     ofs >>= 2;
1609     p32[ofs ] = q32[2];
1610     p32[ofs+1] = q32[3];
1611     p32[ofs+2] = q32[4];
1612     p32[ofs+3] = q32[5];
1613     p32[ofs+4] = q32[0];
1614     p32[ofs+5] = q32[1];
1615     cpu->cd.arm.r[1] = r1 + 24;
1616     cpu->n_translated_instrs += 5;
1617     cpu->cd.arm.next_ic = &ic[6];
1618     }
1619    
1620    
1621     /*
1622     * cmps by 0, followed by beq (inside the same page):
1623     */
1624     X(cmps0_beq_samepage)
1625     {
1626     uint32_t a = reg(ic->arg[0]);
1627     cpu->n_translated_instrs ++;
1628     if (a == 0) {
1629     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1630     } else {
1631     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1632     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1633     }
1634     if (a == 0)
1635     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1636     else
1637     cpu->cd.arm.next_ic = &ic[2];
1638     }
1639    
1640    
1641     /*
1642     * cmps followed by beq (inside the same page):
1643     */
1644     X(cmps_beq_samepage)
1645     {
1646     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1647     cpu->n_translated_instrs ++;
1648     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1649     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1650     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1651     cpu->cd.arm.flags |= ARM_F_V;
1652     if (c == 0) {
1653     cpu->cd.arm.flags |= ARM_F_Z;
1654     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1655     } else {
1656     cpu->cd.arm.next_ic = &ic[2];
1657     if (c & 0x80000000)
1658     cpu->cd.arm.flags |= ARM_F_N;
1659     }
1660     }
1661    
1662    
1663     /*
1664     * cmps followed by beq (not the same page):
1665     */
1666     X(cmps_0_beq)
1667     {
1668     uint32_t a = reg(ic->arg[0]);
1669     cpu->n_translated_instrs ++;
1670     if (a == 0) {
1671     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1672     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1673     + (int32_t)ic[1].arg[0]);
1674     quick_pc_to_pointers(cpu);
1675     } else {
1676     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1677     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1678     cpu->cd.arm.next_ic = &ic[2];
1679     }
1680     }
1681     X(cmps_pos_beq)
1682     {
1683     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1684     cpu->n_translated_instrs ++;
1685     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1686     if ((int32_t)a < 0 && (int32_t)c >= 0)
1687     cpu->cd.arm.flags |= ARM_F_V;
1688     if (c == 0) {
1689     cpu->cd.arm.flags |= ARM_F_Z;
1690     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1691     + (int32_t)ic[1].arg[0]);
1692     quick_pc_to_pointers(cpu);
1693     } else {
1694     cpu->cd.arm.next_ic = &ic[2];
1695     if (c & 0x80000000)
1696     cpu->cd.arm.flags |= ARM_F_N;
1697     }
1698     }
1699     X(cmps_neg_beq)
1700     {
1701     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1702     cpu->n_translated_instrs ++;
1703     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1704     if ((int32_t)a >= 0 && (int32_t)c < 0)
1705     cpu->cd.arm.flags |= ARM_F_V;
1706     if (c == 0) {
1707     cpu->cd.arm.flags |= ARM_F_Z;
1708     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1709     + (int32_t)ic[1].arg[0]);
1710     quick_pc_to_pointers(cpu);
1711     } else {
1712     cpu->cd.arm.next_ic = &ic[2];
1713     if (c & 0x80000000)
1714     cpu->cd.arm.flags |= ARM_F_N;
1715     }
1716     }
1717    
1718    
1719     /*
1720     * cmps by 0, followed by bne (inside the same page):
1721     */
1722     X(cmps0_bne_samepage)
1723     {
1724     uint32_t a = reg(ic->arg[0]);
1725     cpu->n_translated_instrs ++;
1726     if (a == 0) {
1727     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1728     } else {
1729     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1730     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1731     }
1732     if (a == 0)
1733     cpu->cd.arm.next_ic = &ic[2];
1734     else
1735     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1736     }
1737    
1738    
1739     /*
1740     * cmps followed by bne (inside the same page):
1741     */
1742     X(cmps_bne_samepage)
1743     {
1744     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1745     cpu->n_translated_instrs ++;
1746     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1747     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1748     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1749     cpu->cd.arm.flags |= ARM_F_V;
1750     if (c == 0) {
1751     cpu->cd.arm.flags |= ARM_F_Z;
1752     cpu->cd.arm.next_ic = &ic[2];
1753     } else {
1754     if (c & 0x80000000)
1755     cpu->cd.arm.flags |= ARM_F_N;
1756     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1757     }
1758     }
1759    
1760    
1761     /*
1762     * cmps followed by bcc (inside the same page):
1763     */
1764     X(cmps_bcc_samepage)
1765     {
1766     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1767     cpu->n_translated_instrs ++;
1768     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1769     if (c & 0x80000000)
1770     cpu->cd.arm.flags |= ARM_F_N;
1771     else if (c == 0)
1772     cpu->cd.arm.flags |= ARM_F_Z;
1773     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1774     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1775     cpu->cd.arm.flags |= ARM_F_V;
1776     if (a >= b)
1777     cpu->cd.arm.next_ic = &ic[2];
1778     else
1779     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1780     }
1781    
1782    
1783     /*
1784     * cmps (reg) followed by bcc (inside the same page):
1785     */
1786     X(cmps_reg_bcc_samepage)
1787     {
1788     uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1789     cpu->n_translated_instrs ++;
1790     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1791     if (c & 0x80000000)
1792     cpu->cd.arm.flags |= ARM_F_N;
1793     else if (c == 0)
1794     cpu->cd.arm.flags |= ARM_F_Z;
1795     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1796     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1797     cpu->cd.arm.flags |= ARM_F_V;
1798     if (a >= b)
1799     cpu->cd.arm.next_ic = &ic[2];
1800     else
1801     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1802     }
1803    
1804    
1805     /*
1806     * cmps followed by bhi (inside the same page):
1807     */
1808     X(cmps_bhi_samepage)
1809     {
1810     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1811     cpu->n_translated_instrs ++;
1812     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1813     if (c & 0x80000000)
1814     cpu->cd.arm.flags |= ARM_F_N;
1815     else if (c == 0)
1816     cpu->cd.arm.flags |= ARM_F_Z;
1817     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1818     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1819     cpu->cd.arm.flags |= ARM_F_V;
1820     if (a > b)
1821     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1822     else
1823     cpu->cd.arm.next_ic = &ic[2];
1824     }
1825    
1826    
1827     /*
1828     * cmps (reg) followed by bhi (inside the same page):
1829     */
1830     X(cmps_reg_bhi_samepage)
1831     {
1832     uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1833     cpu->n_translated_instrs ++;
1834     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1835     if (c & 0x80000000)
1836     cpu->cd.arm.flags |= ARM_F_N;
1837     else if (c == 0)
1838     cpu->cd.arm.flags |= ARM_F_Z;
1839     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1840     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1841     cpu->cd.arm.flags |= ARM_F_V;
1842     if (a > b)
1843     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1844     else
1845     cpu->cd.arm.next_ic = &ic[2];
1846     }
1847    
1848    
1849     /*
1850     * cmps followed by bgt (inside the same page):
1851     */
1852     X(cmps_bgt_samepage)
1853     {
1854     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1855     cpu->n_translated_instrs ++;
1856     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1857     if (c & 0x80000000)
1858     cpu->cd.arm.flags |= ARM_F_N;
1859     else if (c == 0)
1860     cpu->cd.arm.flags |= ARM_F_Z;
1861     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1862     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1863     cpu->cd.arm.flags |= ARM_F_V;
1864     if ((int32_t)a > (int32_t)b)
1865     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1866     else
1867     cpu->cd.arm.next_ic = &ic[2];
1868     }
1869    
1870    
1871     /*
1872     * cmps followed by ble (inside the same page):
1873     */
1874     X(cmps_ble_samepage)
1875     {
1876     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1877     cpu->n_translated_instrs ++;
1878     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1879     if (c & 0x80000000)
1880     cpu->cd.arm.flags |= ARM_F_N;
1881     else if (c == 0)
1882     cpu->cd.arm.flags |= ARM_F_Z;
1883     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1884     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1885     cpu->cd.arm.flags |= ARM_F_V;
1886     if ((int32_t)a <= (int32_t)b)
1887     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1888     else
1889     cpu->cd.arm.next_ic = &ic[2];
1890     }
1891    
1892    
1893     /*
1894     * teqs followed by beq (inside the same page):
1895     */
1896     X(teqs_beq_samepage)
1897     {
1898     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1899     cpu->n_translated_instrs ++;
1900     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1901     if (c == 0) {
1902     cpu->cd.arm.flags |= ARM_F_Z;
1903     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1904     ic[1].arg[0];
1905     } else {
1906     if (c & 0x80000000)
1907     cpu->cd.arm.flags |= ARM_F_N;
1908     cpu->cd.arm.next_ic = &ic[2];
1909     }
1910     }
1911    
1912    
1913     /*
1914     * tsts followed by beq (inside the same page):
1915     * (arg[1] must not have its highest bit set))
1916     */
1917     X(tsts_lo_beq_samepage)
1918     {
1919     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
1920     cpu->n_translated_instrs ++;
1921     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1922     if (c == 0)
1923     cpu->cd.arm.flags |= ARM_F_Z;
1924     if (c == 0)
1925     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1926     ic[1].arg[0];
1927     else
1928     cpu->cd.arm.next_ic = &ic[2];
1929     }
1930    
1931    
1932     /*
1933     * teqs followed by bne (inside the same page):
1934     */
1935     X(teqs_bne_samepage)
1936     {
1937     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1938     cpu->n_translated_instrs ++;
1939     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1940     if (c == 0) {
1941     cpu->cd.arm.flags |= ARM_F_Z;
1942     } else {
1943     if (c & 0x80000000)
1944     cpu->cd.arm.flags |= ARM_F_N;
1945     }
1946     if (c == 0)
1947     cpu->cd.arm.next_ic = &ic[2];
1948     else
1949     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1950     ic[1].arg[0];
1951     }
1952    
1953    
1954     /*
1955     * tsts followed by bne (inside the same page):
1956     * (arg[1] must not have its highest bit set))
1957     */
1958     X(tsts_lo_bne_samepage)
1959     {
1960     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
1961     cpu->n_translated_instrs ++;
1962     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1963     if (c == 0)
1964     cpu->cd.arm.flags |= ARM_F_Z;
1965     if (c == 0)
1966     cpu->cd.arm.next_ic = &ic[2];
1967     else
1968     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1969     ic[1].arg[0];
1970     }
1971    
1972    
1973 dpavlin 14 /*****************************************************************************/
1974    
1975    
1976     X(end_of_page)
1977     {
1978     /* Update the PC: (offset 0, but on the next page) */
1979 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1980     cpu->pc += (ARM_IC_ENTRIES_PER_PAGE << ARM_INSTR_ALIGNMENT_SHIFT);
1981 dpavlin 14
1982     /* Find the new physical page and update the translation pointers: */
1983 dpavlin 18 quick_pc_to_pointers(cpu);
1984 dpavlin 14
1985     /* end_of_page doesn't count as an executed instruction: */
1986     cpu->n_translated_instrs --;
1987     }
1988    
1989    
1990     /*****************************************************************************/
1991    
1992    
1993     /*
1994 dpavlin 18 * arm_combine_netbsd_memset():
1995 dpavlin 14 *
1996 dpavlin 18 * Check for the core of a NetBSD/arm memset; large memsets use a sequence
1997     * of 16 store-multiple instructions, each storing 2 registers at a time.
1998 dpavlin 14 */
1999 dpavlin 20 void arm_combine_netbsd_memset(struct cpu *cpu,
2000     struct arm_instr_call *ic, int low_addr)
2001 dpavlin 14 {
2002 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2003 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2004 dpavlin 14 & (ARM_IC_ENTRIES_PER_PAGE-1);
2005    
2006 dpavlin 18 if (n_back >= 17) {
2007     int i;
2008     for (i=-16; i<=-1; i++)
2009     if (ic[i].f != instr(multi_0x08ac000c__ge))
2010     return;
2011     if (ic[-17].f == instr(subs) &&
2012     ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 &&
2013     ic[ 0].f == instr(b_samepage__gt) &&
2014     ic[ 0].arg[0] == (size_t)&ic[-17]) {
2015     ic[-17].f = instr(netbsd_memset);
2016     combined;
2017     }
2018     }
2019 dpavlin 20 #endif
2020 dpavlin 18 }
2021    
2022    
2023     /*
2024     * arm_combine_netbsd_memcpy():
2025     *
2026     * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2027     * sequence of ldmia instructions.
2028     */
2029 dpavlin 20 void arm_combine_netbsd_memcpy(struct cpu *cpu,
2030     struct arm_instr_call *ic, int low_addr)
2031 dpavlin 18 {
2032 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2033 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2034     & (ARM_IC_ENTRIES_PER_PAGE-1);
2035    
2036     if (n_back >= 5) {
2037     if (ic[-5].f==instr(multi_0x08b15018) &&
2038     ic[-4].f==instr(multi_0x08a05018) &&
2039     ic[-3].f==instr(multi_0x08b15018) &&
2040     ic[-2].f==instr(multi_0x08a05018) &&
2041     ic[-1].f == instr(subs) &&
2042     ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 &&
2043     ic[ 0].f == instr(b_samepage__ge) &&
2044     ic[ 0].arg[0] == (size_t)&ic[-5]) {
2045     ic[-5].f = instr(netbsd_memcpy);
2046     combined;
2047     }
2048     }
2049 dpavlin 20 #endif
2050 dpavlin 18 }
2051    
2052    
2053     /*
2054     * arm_combine_netbsd_cacheclean():
2055     *
2056     * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2057     */
2058 dpavlin 20 void arm_combine_netbsd_cacheclean(struct cpu *cpu,
2059     struct arm_instr_call *ic, int low_addr)
2060 dpavlin 18 {
2061     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2062     & (ARM_IC_ENTRIES_PER_PAGE-1);
2063    
2064     if (n_back >= 3) {
2065     if (ic[-3].f==instr(load_w0_word_u1_p0_imm) &&
2066     ic[-2].f == instr(subs) &&
2067     ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2068     ic[-1].f == instr(b_samepage__ne) &&
2069     ic[-1].arg[0] == (size_t)&ic[-3]) {
2070     ic[-3].f = instr(netbsd_cacheclean);
2071     combined;
2072     }
2073     }
2074     }
2075    
2076    
2077     /*
2078     * arm_combine_netbsd_cacheclean2():
2079     *
2080     * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2081     */
2082 dpavlin 20 void arm_combine_netbsd_cacheclean2(struct cpu *cpu,
2083     struct arm_instr_call *ic, int low_addr)
2084 dpavlin 18 {
2085     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2086     & (ARM_IC_ENTRIES_PER_PAGE-1);
2087    
2088     if (n_back >= 4) {
2089     if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
2090     ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
2091     ic[-2].f == instr(add) &&
2092     ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2093     ic[-1].f == instr(subs) &&
2094     ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
2095     ic[-4].f = instr(netbsd_cacheclean2);
2096     combined;
2097     }
2098     }
2099     }
2100    
2101    
2102     /*
2103     * arm_combine_netbsd_scanc():
2104     */
2105 dpavlin 20 void arm_combine_netbsd_scanc(struct cpu *cpu,
2106     struct arm_instr_call *ic, int low_addr)
2107 dpavlin 18 {
2108     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2109     & (ARM_IC_ENTRIES_PER_PAGE-1);
2110    
2111 dpavlin 20 if (n_back < 2)
2112     return;
2113    
2114     if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) &&
2115     ic[-2].arg[0] == (size_t)(&cpu->cd.arm.r[1]) &&
2116     ic[-2].arg[1] == 0 &&
2117     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2118     ic[-1].f == instr(load_w0_byte_u1_p1_reg) &&
2119     ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[2]) &&
2120     ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 &&
2121     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) {
2122     ic[-2].f = instr(netbsd_scanc);
2123     combined;
2124 dpavlin 18 }
2125     }
2126    
2127    
2128     /*
2129 dpavlin 20 * arm_combine_strlen():
2130 dpavlin 18 */
2131 dpavlin 20 void arm_combine_strlen(struct cpu *cpu,
2132     struct arm_instr_call *ic, int low_addr)
2133 dpavlin 18 {
2134     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2135     & (ARM_IC_ENTRIES_PER_PAGE-1);
2136    
2137 dpavlin 20 if (n_back < 2)
2138     return;
2139    
2140     if (ic[-2].f == instr(load_w1_byte_u1_p1_imm) &&
2141     ic[-2].arg[1] == 1 &&
2142     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2143     ic[-1].f == instr(cmps) &&
2144     ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) &&
2145     ic[-1].arg[1] == 0) {
2146     ic[-2].f = instr(strlen);
2147     combined;
2148 dpavlin 14 }
2149 dpavlin 18 }
2150 dpavlin 14
2151 dpavlin 18
2152 dpavlin 20 /*
2153     * arm_combine_xchg():
2154     */
2155     void arm_combine_xchg(struct cpu *cpu,
2156     struct arm_instr_call *ic, int low_addr)
2157     {
2158     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2159     & (ARM_IC_ENTRIES_PER_PAGE-1);
2160     size_t a, b;
2161 dpavlin 18
2162 dpavlin 20 if (n_back < 2)
2163     return;
2164    
2165     a = ic[-2].arg[0]; b = ic[-1].arg[0];
2166    
2167     if (ic[-2].f == instr(eor_regshort) &&
2168     ic[-1].f == instr(eor_regshort) &&
2169     ic[-2].arg[0] == a && ic[-2].arg[1] == b && ic[-2].arg[2] == b &&
2170     ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a &&
2171     ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) {
2172     ic[-2].f = instr(xchg);
2173     combined;
2174     }
2175     }
2176    
2177    
2178     /*
2179     * arm_combine_netbsd_copyin():
2180     */
2181     void arm_combine_netbsd_copyin(struct cpu *cpu,
2182     struct arm_instr_call *ic, int low_addr)
2183     {
2184     #ifdef HOST_LITTLE_ENDIAN
2185     int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2186     & (ARM_IC_ENTRIES_PER_PAGE-1);
2187    
2188     if (n_back < 5)
2189     return;
2190    
2191     for (i=-5; i<0; i++) {
2192     if (ic[i].f != instr(load_w1_word_u1_p0_imm) ||
2193     ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[0]) ||
2194     ic[i].arg[1] != 4)
2195     return;
2196     }
2197    
2198     if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2199     ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2200     ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[6]) &&
2201     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) &&
2202     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) {
2203     ic[-5].f = instr(netbsd_copyin);
2204     combined;
2205     }
2206     #endif
2207     }
2208    
2209    
2210     /*
2211     * arm_combine_netbsd_copyout():
2212     */
2213     void arm_combine_netbsd_copyout(struct cpu *cpu,
2214     struct arm_instr_call *ic, int low_addr)
2215     {
2216     #ifdef HOST_LITTLE_ENDIAN
2217     int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2218     & (ARM_IC_ENTRIES_PER_PAGE-1);
2219    
2220     if (n_back < 5)
2221     return;
2222    
2223     for (i=-5; i<0; i++) {
2224     if (ic[i].f != instr(store_w1_word_u1_p0_imm) ||
2225     ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[1]) ||
2226     ic[i].arg[1] != 4)
2227     return;
2228     }
2229    
2230     if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[8]) &&
2231     ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[9]) &&
2232     ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2233     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2234     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) {
2235     ic[-5].f = instr(netbsd_copyout);
2236     combined;
2237     }
2238     #endif
2239     }
2240    
2241    
2242     /*
2243     * arm_combine_cmps_b():
2244     */
2245     void arm_combine_cmps_b(struct cpu *cpu,
2246     struct arm_instr_call *ic, int low_addr)
2247     {
2248     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2249     & (ARM_IC_ENTRIES_PER_PAGE-1);
2250     if (n_back < 1)
2251     return;
2252     if (ic[0].f == instr(b__eq)) {
2253     if (ic[-1].f == instr(cmps)) {
2254     if (ic[-1].arg[1] == 0)
2255     ic[-1].f = instr(cmps_0_beq);
2256     else if (ic[-1].arg[1] & 0x80000000)
2257     ic[-1].f = instr(cmps_neg_beq);
2258     else
2259     ic[-1].f = instr(cmps_pos_beq);
2260 dpavlin 14 combined;
2261     }
2262 dpavlin 20 return;
2263 dpavlin 14 }
2264 dpavlin 20 if (ic[0].f == instr(b_samepage__eq)) {
2265     if (ic[-1].f == instr(cmps)) {
2266     if (ic[-1].arg[1] == 0)
2267     ic[-1].f = instr(cmps0_beq_samepage);
2268     else
2269     ic[-1].f = instr(cmps_beq_samepage);
2270     combined;
2271     }
2272     if (ic[-1].f == instr(tsts) &&
2273     !(ic[-1].arg[1] & 0x80000000)) {
2274     ic[-1].f = instr(tsts_lo_beq_samepage);
2275     combined;
2276     }
2277     if (ic[-1].f == instr(teqs)) {
2278     ic[-1].f = instr(teqs_beq_samepage);
2279     combined;
2280     }
2281     return;
2282     }
2283     if (ic[0].f == instr(b_samepage__ne)) {
2284     if (ic[-1].f == instr(cmps)) {
2285     if (ic[-1].arg[1] == 0)
2286     ic[-1].f = instr(cmps0_bne_samepage);
2287     else
2288     ic[-1].f = instr(cmps_bne_samepage);
2289     combined;
2290     }
2291     if (ic[-1].f == instr(tsts) &&
2292     !(ic[-1].arg[1] & 0x80000000)) {
2293     ic[-1].f = instr(tsts_lo_bne_samepage);
2294     combined;
2295     }
2296     if (ic[-1].f == instr(teqs)) {
2297     ic[-1].f = instr(teqs_bne_samepage);
2298     combined;
2299     }
2300     return;
2301     }
2302     if (ic[0].f == instr(b_samepage__cc)) {
2303     if (ic[-1].f == instr(cmps)) {
2304     ic[-1].f = instr(cmps_bcc_samepage);
2305     combined;
2306     }
2307     if (ic[-1].f == instr(cmps_regshort)) {
2308     ic[-1].f = instr(cmps_reg_bcc_samepage);
2309     combined;
2310     }
2311     return;
2312     }
2313     if (ic[0].f == instr(b_samepage__hi)) {
2314     if (ic[-1].f == instr(cmps)) {
2315     ic[-1].f = instr(cmps_bhi_samepage);
2316     combined;
2317     }
2318     if (ic[-1].f == instr(cmps_regshort)) {
2319     ic[-1].f = instr(cmps_reg_bhi_samepage);
2320     combined;
2321     }
2322     return;
2323     }
2324     if (ic[0].f == instr(b_samepage__gt)) {
2325     if (ic[-1].f == instr(cmps)) {
2326     ic[-1].f = instr(cmps_bgt_samepage);
2327     combined;
2328     }
2329     return;
2330     }
2331     if (ic[0].f == instr(b_samepage__le)) {
2332     if (ic[-1].f == instr(cmps)) {
2333     ic[-1].f = instr(cmps_ble_samepage);
2334     combined;
2335     }
2336     return;
2337     }
2338     }
2339 dpavlin 14
2340    
2341     /*****************************************************************************/
2342    
2343    
2344 dpavlin 20 static void arm_switch_clear(struct arm_instr_call *ic, int rd,
2345     int condition_code)
2346     {
2347     switch (rd) {
2348     case 0: ic->f = cond_instr(clear_r0); break;
2349     case 1: ic->f = cond_instr(clear_r1); break;
2350     case 2: ic->f = cond_instr(clear_r2); break;
2351     case 3: ic->f = cond_instr(clear_r3); break;
2352     case 4: ic->f = cond_instr(clear_r4); break;
2353     case 5: ic->f = cond_instr(clear_r5); break;
2354     case 6: ic->f = cond_instr(clear_r6); break;
2355     case 7: ic->f = cond_instr(clear_r7); break;
2356     case 8: ic->f = cond_instr(clear_r8); break;
2357     case 9: ic->f = cond_instr(clear_r9); break;
2358     case 10: ic->f = cond_instr(clear_r10); break;
2359     case 11: ic->f = cond_instr(clear_r11); break;
2360     case 12: ic->f = cond_instr(clear_r12); break;
2361     case 13: ic->f = cond_instr(clear_r13); break;
2362     case 14: ic->f = cond_instr(clear_r14); break;
2363     }
2364     }
2365    
2366    
2367     static void arm_switch_mov1(struct arm_instr_call *ic, int rd,
2368     int condition_code)
2369     {
2370     switch (rd) {
2371     case 0: ic->f = cond_instr(mov1_r0); break;
2372     case 1: ic->f = cond_instr(mov1_r1); break;
2373     case 2: ic->f = cond_instr(mov1_r2); break;
2374     case 3: ic->f = cond_instr(mov1_r3); break;
2375     case 4: ic->f = cond_instr(mov1_r4); break;
2376     case 5: ic->f = cond_instr(mov1_r5); break;
2377     case 6: ic->f = cond_instr(mov1_r6); break;
2378     case 7: ic->f = cond_instr(mov1_r7); break;
2379     case 8: ic->f = cond_instr(mov1_r8); break;
2380     case 9: ic->f = cond_instr(mov1_r9); break;
2381     case 10: ic->f = cond_instr(mov1_r10); break;
2382     case 11: ic->f = cond_instr(mov1_r11); break;
2383     case 12: ic->f = cond_instr(mov1_r12); break;
2384     case 13: ic->f = cond_instr(mov1_r13); break;
2385     case 14: ic->f = cond_instr(mov1_r14); break;
2386     }
2387     }
2388    
2389    
2390     static void arm_switch_add1(struct arm_instr_call *ic, int rd,
2391     int condition_code)
2392     {
2393     switch (rd) {
2394     case 0: ic->f = cond_instr(add1_r0); break;
2395     case 1: ic->f = cond_instr(add1_r1); break;
2396     case 2: ic->f = cond_instr(add1_r2); break;
2397     case 3: ic->f = cond_instr(add1_r3); break;
2398     case 4: ic->f = cond_instr(add1_r4); break;
2399     case 5: ic->f = cond_instr(add1_r5); break;
2400     case 6: ic->f = cond_instr(add1_r6); break;
2401     case 7: ic->f = cond_instr(add1_r7); break;
2402     case 8: ic->f = cond_instr(add1_r8); break;
2403     case 9: ic->f = cond_instr(add1_r9); break;
2404     case 10: ic->f = cond_instr(add1_r10); break;
2405     case 11: ic->f = cond_instr(add1_r11); break;
2406     case 12: ic->f = cond_instr(add1_r12); break;
2407     case 13: ic->f = cond_instr(add1_r13); break;
2408     case 14: ic->f = cond_instr(add1_r14); break;
2409     }
2410     }
2411    
2412    
2413     /*****************************************************************************/
2414    
2415    
2416 dpavlin 14 /*
2417     * arm_instr_to_be_translated():
2418     *
2419     * Translate an instruction word into an arm_instr_call. ic is filled in with
2420     * valid data for the translated instruction, or a "nothing" instruction if
2421     * there was a translation failure. The newly translated instruction is then
2422     * executed.
2423     */
2424     X(to_be_translated)
2425     {
2426     uint32_t addr, low_pc, iword, imm = 0;
2427     unsigned char *page;
2428     unsigned char ib[4];
2429     int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
2430 dpavlin 20 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2431 dpavlin 14 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
2432    
2433     /* Figure out the address of the instruction: */
2434     low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
2435     / sizeof(struct arm_instr_call);
2436 dpavlin 20 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2437 dpavlin 14 ARM_INSTR_ALIGNMENT_SHIFT);
2438     addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2439 dpavlin 20 cpu->pc = addr;
2440 dpavlin 14 addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2441    
2442     /* Read the instruction word from memory: */
2443     page = cpu->cd.arm.host_load[addr >> 12];
2444     if (page != NULL) {
2445 dpavlin 20 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2446 dpavlin 14 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2447     } else {
2448 dpavlin 20 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2449 dpavlin 14 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
2450     sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
2451     fatal("to_be_translated(): "
2452     "read failed: TODO\n");
2453 dpavlin 18 return;
2454 dpavlin 14 }
2455     }
2456    
2457     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2458     iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
2459     else
2460     iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
2461    
2462    
2463     #define DYNTRANS_TO_BE_TRANSLATED_HEAD
2464     #include "cpu_dyntrans.c"
2465     #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
2466    
2467    
2468     /* The idea of taking bits 27..24 was found here:
2469     http://armphetamine.sourceforge.net/oldinfo.html */
2470     condition_code = iword >> 28;
2471     main_opcode = (iword >> 24) & 15;
2472     secondary_opcode = (iword >> 21) & 15;
2473 dpavlin 20 u_bit = iword & 0x00800000;
2474     w_bit = iword & 0x00200000;
2475     s_bit = l_bit = iword & 0x00100000;
2476 dpavlin 14 rn = (iword >> 16) & 15;
2477     rd = (iword >> 12) & 15;
2478     r8 = (iword >> 8) & 15;
2479     c = (iword >> 7) & 31;
2480     t = (iword >> 4) & 7;
2481     rm = iword & 15;
2482    
2483     if (condition_code == 0xf) {
2484     if ((iword & 0xfc70f000) == 0xf450f000) {
2485     /* Preload: TODO. Treat as NOP for now. */
2486     ic->f = instr(nop);
2487     goto okay;
2488     }
2489    
2490     fatal("TODO: ARM condition code 0x%x\n",
2491     condition_code);
2492     goto bad;
2493     }
2494    
2495    
2496     /*
2497     * Translate the instruction:
2498     */
2499    
2500     switch (main_opcode) {
2501    
2502     case 0x0:
2503     case 0x1:
2504     case 0x2:
2505     case 0x3:
2506     /* Check special cases first: */
2507     if ((iword & 0x0fc000f0) == 0x00000090) {
2508     /*
2509     * Multiplication:
2510     * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])
2511     */
2512     if (iword & 0x00200000) {
2513     if (s_bit)
2514     ic->f = cond_instr(mlas);
2515     else
2516     ic->f = cond_instr(mla);
2517     ic->arg[0] = iword;
2518     } else {
2519     if (s_bit)
2520     ic->f = cond_instr(muls);
2521     else
2522     ic->f = cond_instr(mul);
2523     /* NOTE: rn means rd in this case: */
2524     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2525     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2526     ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]);
2527     }
2528     break;
2529     }
2530     if ((iword & 0x0f8000f0) == 0x00800090) {
2531     /* Long multiplication: */
2532     if (s_bit) {
2533     fatal("TODO: sbit mull\n");
2534     goto bad;
2535     }
2536     ic->f = cond_instr(mull);
2537     ic->arg[0] = iword;
2538     break;
2539     }
2540 dpavlin 20 if ((iword & 0x0f900ff0) == 0x01000050) {
2541     fatal("TODO: q{,d}{add,sub}\n");
2542     goto bad;
2543     }
2544 dpavlin 14 if ((iword & 0x0ff000d0) == 0x01200010) {
2545     /* bx or blx */
2546     if (iword & 0x20)
2547     ic->f = cond_instr(blx);
2548     else {
2549     if (cpu->machine->show_trace_tree &&
2550     rm == ARM_LR)
2551     ic->f = cond_instr(bx_trace);
2552     else
2553     ic->f = cond_instr(bx);
2554     }
2555     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2556     break;
2557     }
2558     if ((iword & 0x0fb00ff0) == 0x1000090) {
2559     if (iword & 0x00400000)
2560     ic->f = cond_instr(swpb);
2561     else
2562     ic->f = cond_instr(swp);
2563     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
2564     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2565     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
2566     break;
2567     }
2568 dpavlin 20 if ((iword & 0x0fff0ff0) == 0x016f0f10) {
2569     ic->f = cond_instr(clz);
2570     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2571     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2572     break;
2573     }
2574     if ((iword & 0x0ff00090) == 0x01000080) {
2575     /* TODO: smlaXX */
2576     goto bad;
2577     }
2578     if ((iword & 0x0ff00090) == 0x01400080) {
2579     /* TODO: smlalY */
2580     goto bad;
2581     }
2582     if ((iword & 0x0ff000b0) == 0x01200080) {
2583     /* TODO: smlawY */
2584     goto bad;
2585     }
2586     if ((iword & 0x0ff0f090) == 0x01600080) {
2587     /* TODO: smulXY */
2588     goto bad;
2589     }
2590     if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2591     /* TODO: smulwY */
2592     goto bad;
2593     }
2594 dpavlin 14 if ((iword & 0x0fb0fff0) == 0x0120f000 ||
2595     (iword & 0x0fb0f000) == 0x0320f000) {
2596     /* msr: move to [S|C]PSR from a register or
2597     immediate value */
2598     if (rm == ARM_PC) {
2599     fatal("msr PC?\n");
2600     goto bad;
2601     }
2602     if (iword & 0x02000000) {
2603     if (iword & 0x00400000)
2604     ic->f = cond_instr(msr_imm_spsr);
2605     else
2606     ic->f = cond_instr(msr_imm);
2607     } else {
2608     if (iword & 0x00400000)
2609     ic->f = cond_instr(msr_spsr);
2610     else
2611     ic->f = cond_instr(msr);
2612     }
2613     imm = iword & 0xff;
2614     while (r8-- > 0)
2615     imm = (imm >> 2) | ((imm & 3) << 30);
2616     ic->arg[0] = imm;
2617     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
2618     switch ((iword >> 16) & 15) {
2619     case 1: ic->arg[1] = 0x000000ff; break;
2620     case 8: ic->arg[1] = 0xff000000; break;
2621     case 9: ic->arg[1] = 0xff0000ff; break;
2622     default:fatal("unimpl a: msr regform\n");
2623     goto bad;
2624     }
2625     break;
2626     }
2627     if ((iword & 0x0fbf0fff) == 0x010f0000) {
2628     /* mrs: move from CPSR/SPSR to a register: */
2629     if (rd == ARM_PC) {
2630     fatal("mrs PC?\n");
2631     goto bad;
2632     }
2633     if (iword & 0x00400000)
2634     ic->f = cond_instr(mrs_spsr);
2635     else
2636     ic->f = cond_instr(mrs);
2637     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
2638     break;
2639     }
2640     if ((iword & 0x0e000090) == 0x00000090) {
2641     int imm = ((iword >> 4) & 0xf0) | (iword & 0xf);
2642     int regform = !(iword & 0x00400000);
2643     p_bit = main_opcode & 1;
2644     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2645     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2646     if (rd == ARM_PC || rn == ARM_PC) {
2647     ic->f = arm_load_store_instr_3_pc[
2648     condition_code + (l_bit? 16 : 0)
2649     + (iword & 0x40? 32 : 0)
2650     + (w_bit? 64 : 0)
2651     + (iword & 0x20? 128 : 0)
2652     + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2653     + (regform? 1024 : 0)];
2654     if (rn == ARM_PC)
2655     ic->arg[0] = (size_t)
2656     (&cpu->cd.arm.tmp_pc);
2657     if (!l_bit && rd == ARM_PC)
2658     ic->arg[2] = (size_t)
2659     (&cpu->cd.arm.tmp_pc);
2660     } else
2661     ic->f = arm_load_store_instr_3[
2662     condition_code + (l_bit? 16 : 0)
2663     + (iword & 0x40? 32 : 0)
2664     + (w_bit? 64 : 0)
2665     + (iword & 0x20? 128 : 0)
2666     + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2667     + (regform? 1024 : 0)];
2668     if (regform)
2669 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2670 dpavlin 14 else
2671     ic->arg[1] = imm;
2672     break;
2673     }
2674    
2675     if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
2676     fatal("reg form blah blah\n");
2677     goto bad;
2678     }
2679    
2680 dpavlin 18 /* "mov pc,lr": */
2681     if ((iword & 0x0fffffff) == 0x01a0f00e) {
2682     if (cpu->machine->show_trace_tree)
2683     ic->f = cond_instr(ret_trace);
2684     else
2685     ic->f = cond_instr(ret);
2686 dpavlin 14 break;
2687     }
2688    
2689 dpavlin 20 /* "mov reg,reg" or "mov reg,pc": */
2690     if ((iword & 0x0fff0ff0) == 0x01a00000 && rd != ARM_PC) {
2691     if (rm != ARM_PC) {
2692     ic->f = cond_instr(mov_reg_reg);
2693     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2694     } else {
2695     ic->f = cond_instr(mov_reg_pc);
2696     ic->arg[0] = (addr & 0xfff) + 8;
2697     }
2698 dpavlin 14 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2699     break;
2700     }
2701    
2702 dpavlin 18 /* "mov reg,#0": */
2703 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2704     arm_switch_clear(ic, rd, condition_code);
2705 dpavlin 18 break;
2706     }
2707    
2708     /* "mov reg,#1": */
2709 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2710     arm_switch_mov1(ic, rd, condition_code);
2711 dpavlin 18 break;
2712     }
2713    
2714 dpavlin 20 /* "add reg,reg,#1": */
2715     if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC
2716     && rn == rd) {
2717     arm_switch_add1(ic, rd, condition_code);
2718     break;
2719     }
2720    
2721 dpavlin 14 /*
2722     * Generic Data Processing Instructions:
2723     */
2724     if ((main_opcode & 2) == 0)
2725     regform = 1;
2726     else
2727     regform = 0;
2728    
2729 dpavlin 16 if (regform) {
2730     /* 0x1000 signifies Carry bit update on rotation,
2731     which is not necessary for add,adc,sub,sbc,
2732     rsb,rsc,cmp, or cmn, because they update the
2733     Carry bit manually anyway. */
2734     int q = 0x1000;
2735     if (s_bit == 0)
2736     q = 0;
2737     if ((secondary_opcode >= 2 && secondary_opcode <= 7)
2738     || secondary_opcode==0xa || secondary_opcode==0xb)
2739     q = 0;
2740     ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q];
2741     } else {
2742 dpavlin 14 imm = iword & 0xff;
2743     while (r8-- > 0)
2744     imm = (imm >> 2) | ((imm & 3) << 30);
2745     ic->arg[1] = imm;
2746     }
2747    
2748 dpavlin 20 /* mvn #imm ==> mov #~imm */
2749     if (secondary_opcode == 0xf && !regform) {
2750     secondary_opcode = 0xd;
2751     ic->arg[1] = ~ic->arg[1];
2752     }
2753    
2754 dpavlin 14 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2755     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2756     any_pc_reg = 0;
2757     if (rn == ARM_PC || rd == ARM_PC)
2758     any_pc_reg = 1;
2759    
2760 dpavlin 20 if (!any_pc_reg && regform && (iword & 0xfff) < ARM_PC) {
2761     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2762     ic->f = arm_dpi_instr_regshort[condition_code +
2763     16 * secondary_opcode + (s_bit? 256 : 0)];
2764     } else
2765     ic->f = arm_dpi_instr[condition_code +
2766     16 * secondary_opcode + (s_bit? 256 : 0) +
2767     (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
2768 dpavlin 18
2769 dpavlin 20 if (ic->f == instr(eor_regshort))
2770     cpu->cd.arm.combination_check = arm_combine_xchg;
2771 dpavlin 18 if (iword == 0xe113000c)
2772 dpavlin 20 cpu->cd.arm.combination_check =
2773     arm_combine_netbsd_scanc;
2774 dpavlin 14 break;
2775    
2776     case 0x4: /* Load and store... */
2777     case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
2778     case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
2779     case 0x7:
2780     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2781     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2782     if (rd == ARM_PC || rn == ARM_PC) {
2783     ic->f = arm_load_store_instr_pc[((iword >> 16)
2784     & 0x3f0) + condition_code];
2785     if (rn == ARM_PC)
2786     ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc);
2787     if (!l_bit && rd == ARM_PC)
2788     ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc);
2789     } else {
2790     ic->f = arm_load_store_instr[((iword >> 16) &
2791     0x3f0) + condition_code];
2792     }
2793     imm = iword & 0xfff;
2794     if (main_opcode < 6)
2795     ic->arg[1] = imm;
2796     else
2797 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2798 dpavlin 14 if ((iword & 0x0e000010) == 0x06000010) {
2799     fatal("Not a Load/store TODO\n");
2800     goto bad;
2801     }
2802 dpavlin 20 /* Special case: pc-relative load within the same page: */
2803     if (rn == ARM_PC && rd != ARM_PC && main_opcode < 6) {
2804     int ofs = (addr & 0xfff) + 8, max = 0xffc;
2805     int b_bit = iword & 0x00400000;
2806     if (b_bit)
2807     max = 0xfff;
2808     if (u_bit)
2809     ofs += (iword & 0xfff);
2810     else
2811     ofs -= (iword & 0xfff);
2812     /* NOTE/TODO: This assumes 4KB pages,
2813     it will not work with 1KB pages. */
2814     if (ofs >= 0 && ofs <= max) {
2815     unsigned char *p;
2816     unsigned char c[4];
2817     int len = b_bit? 1 : 4;
2818     uint32_t x, a = (addr & 0xfffff000) | ofs;
2819     /* ic->f = cond_instr(mov); */
2820     ic->f = arm_dpi_instr[condition_code + 16*0xd];
2821     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2822     p = cpu->cd.arm.host_load[a >> 12];
2823     if (p != NULL) {
2824     memcpy(c, p + (a & 0xfff), len);
2825     } else {
2826     if (!cpu->memory_rw(cpu, cpu->mem, a,
2827     c, len, MEM_READ, CACHE_DATA)) {
2828     fatal("to_be_translated(): "
2829     "read failed X: TODO\n");
2830     goto bad;
2831     }
2832     }
2833     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2834     x = c[0] + (c[1]<<8) +
2835     (c[2]<<16) + (c[3]<<24);
2836     else
2837     x = c[3] + (c[2]<<8) +
2838     (c[1]<<16) + (c[0]<<24);
2839     if (b_bit)
2840     x = c[0];
2841     ic->arg[1] = x;
2842     }
2843     }
2844     if (iword == 0xe4b09004)
2845     cpu->cd.arm.combination_check =
2846     arm_combine_netbsd_copyin;
2847     if (iword == 0xe4a17004)
2848     cpu->cd.arm.combination_check =
2849     arm_combine_netbsd_copyout;
2850 dpavlin 14 break;
2851    
2852     case 0x8: /* Multiple load/store... (Block data transfer) */
2853     case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2854 dpavlin 18 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2855     ic->arg[1] = (size_t)iword;
2856     /* Generic case: */
2857 dpavlin 14 if (l_bit)
2858     ic->f = cond_instr(bdt_load);
2859     else
2860     ic->f = cond_instr(bdt_store);
2861 dpavlin 18 #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS)
2862     /*
2863     * Check for availability of optimized implementation:
2864     * xxxx100P USWLnnnn llllllll llllllll
2865     * ^ ^ ^ ^ ^ ^ ^ ^ (0x00950154)
2866     * These bits are used to select which list to scan, and then
2867     * the list is scanned linearly.
2868     *
2869     * The optimized functions do not support show_trace_tree,
2870     * but it's ok to use the unoptimized version in that case.
2871     */
2872     if (!cpu->machine->show_trace_tree) {
2873     int i = 0, j = iword;
2874     j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14)
2875     | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12)
2876     | ((j & 0x00000100) >> 5) | ((j & 0x00000040) >> 4)
2877     | ((j & 0x00000010) >> 3) | ((j & 0x00000004) >> 2);
2878     while (multi_opcode[j][i] != 0) {
2879     if ((iword & 0x0fffffff) ==
2880     multi_opcode[j][i]) {
2881     ic->f = multi_opcode_f[j]
2882     [i*16 + condition_code];
2883     break;
2884     }
2885     i ++;
2886     }
2887     }
2888     #endif
2889 dpavlin 14 if (rn == ARM_PC) {
2890     fatal("TODO: bdt with PC as base\n");
2891     goto bad;
2892     }
2893     break;
2894    
2895     case 0xa: /* B: branch */
2896     case 0xb: /* BL: branch+link */
2897     if (main_opcode == 0x0a) {
2898     ic->f = cond_instr(b);
2899     samepage_function = cond_instr(b_samepage);
2900 dpavlin 18 if (iword == 0xcaffffed)
2901 dpavlin 20 cpu->cd.arm.combination_check =
2902 dpavlin 18 arm_combine_netbsd_memset;
2903     if (iword == 0xaafffff9)
2904 dpavlin 20 cpu->cd.arm.combination_check =
2905 dpavlin 18 arm_combine_netbsd_memcpy;
2906 dpavlin 14 } else {
2907     if (cpu->machine->show_trace_tree) {
2908     ic->f = cond_instr(bl_trace);
2909     samepage_function =
2910     cond_instr(bl_samepage_trace);
2911     } else {
2912     ic->f = cond_instr(bl);
2913     samepage_function = cond_instr(bl_samepage);
2914     }
2915     }
2916    
2917 dpavlin 20 /* arg 1 = offset of current instruction */
2918     /* arg 2 = offset of the following instruction */
2919     ic->arg[1] = addr & 0xffc;
2920     ic->arg[2] = (addr & 0xffc) + 4;
2921    
2922 dpavlin 14 ic->arg[0] = (iword & 0x00ffffff) << 2;
2923     /* Sign-extend: */
2924     if (ic->arg[0] & 0x02000000)
2925     ic->arg[0] |= 0xfc000000;
2926     /*
2927     * Branches are calculated as PC + 8 + offset.
2928     */
2929     ic->arg[0] = (int32_t)(ic->arg[0] + 8);
2930    
2931 dpavlin 20 /*
2932     * Special case: branch within the same page:
2933     *
2934     * arg[0] = addr of the arm_instr_call of the target
2935     * arg[1] = addr of the next arm_instr_call.
2936     */
2937 dpavlin 14 {
2938     uint32_t mask_within_page =
2939     ((ARM_IC_ENTRIES_PER_PAGE-1) <<
2940     ARM_INSTR_ALIGNMENT_SHIFT) |
2941     ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2942     uint32_t old_pc = addr;
2943     uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
2944     if ((old_pc & ~mask_within_page) ==
2945     (new_pc & ~mask_within_page)) {
2946     ic->f = samepage_function;
2947     ic->arg[0] = (size_t) (
2948     cpu->cd.arm.cur_ic_page +
2949     ((new_pc & mask_within_page) >>
2950     ARM_INSTR_ALIGNMENT_SHIFT));
2951 dpavlin 20 ic->arg[1] = (size_t) (
2952     cpu->cd.arm.cur_ic_page +
2953     (((addr & mask_within_page) + 4) >>
2954     ARM_INSTR_ALIGNMENT_SHIFT));
2955     } else if (main_opcode == 0x0a) {
2956     /* Special hack for a plain "b": */
2957     ic->arg[0] += ic->arg[1];
2958 dpavlin 14 }
2959     }
2960 dpavlin 18
2961 dpavlin 20 if (main_opcode == 0xa && (condition_code <= 1
2962     || condition_code == 3 || condition_code == 8
2963     || condition_code == 12 || condition_code == 13))
2964     cpu->cd.arm.combination_check = arm_combine_cmps_b;
2965    
2966     if (iword == 0x1afffffc)
2967     cpu->cd.arm.combination_check = arm_combine_strlen;
2968    
2969     /* Hm. Does this really increase performance? */
2970 dpavlin 18 if (iword == 0x8afffffa)
2971 dpavlin 20 cpu->cd.arm.combination_check =
2972     arm_combine_netbsd_cacheclean2;
2973 dpavlin 14 break;
2974    
2975 dpavlin 20 case 0xc:
2976     case 0xd:
2977     /*
2978     * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm
2979     * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm
2980     */
2981     if ((iword & 0x0fe00000) == 0x0c400000) {
2982     fatal("MCRR/MRRC: TODO\n");
2983     goto bad;
2984     }
2985    
2986     /*
2987     * TODO: LDC/STC
2988     *
2989     * For now, treat as Undefined instructions. This causes e.g.
2990     * Linux/ARM to emulate these instructions (floating point).
2991     */
2992     ic->f = cond_instr(und);
2993     ic->arg[0] = addr & 0xfff;
2994     break;
2995    
2996 dpavlin 14 case 0xe:
2997     if (iword & 0x10) {
2998     /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */
2999     ic->arg[0] = iword;
3000     ic->f = cond_instr(mcr_mrc);
3001     } else {
3002     /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */
3003     ic->arg[0] = iword;
3004     ic->f = cond_instr(cdp);
3005     }
3006 dpavlin 18 if (iword == 0xee070f9a)
3007 dpavlin 20 cpu->cd.arm.combination_check =
3008     arm_combine_netbsd_cacheclean;
3009 dpavlin 14 break;
3010    
3011     case 0xf:
3012     /* SWI: */
3013     /* Default handler: */
3014     ic->f = cond_instr(swi);
3015 dpavlin 20 ic->arg[0] = addr & 0xfff;
3016     if (iword == 0xef8c64eb) {
3017     /* Hack for rebooting a machine: */
3018     ic->f = instr(reboot);
3019     } else if (iword == 0xef8c64be) {
3020 dpavlin 14 /* Hack for openfirmware prom emulation: */
3021     ic->f = instr(openfirmware);
3022     } else if (cpu->machine->userland_emul != NULL) {
3023     if ((iword & 0x00f00000) == 0x00a00000) {
3024     ic->arg[0] = iword & 0x00ffffff;
3025     ic->f = cond_instr(swi_useremul);
3026     } else {
3027     fatal("Bad userland SWI?\n");
3028     goto bad;
3029     }
3030     }
3031     break;
3032    
3033     default:goto bad;
3034     }
3035    
3036     okay:
3037    
3038     #define DYNTRANS_TO_BE_TRANSLATED_TAIL
3039     #include "cpu_dyntrans.c"
3040     #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
3041     }
3042    

  ViewVC Help
Powered by ViewVC 1.1.26