/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 79657 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26