/[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 44 - (hide annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 82254 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26