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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show 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 /*
2 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_arm_instr.c,v 1.77 2007/06/28 13:36:46 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (If no instruction was executed, then it should be decreased. If, say, 4
34 * instructions were combined into one function and executed, then it should
35 * be increased by 3.)
36 *
37 * 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 */
41
42
43 /* #define GATHER_BDT_STATISTICS */
44
45
46 #ifdef GATHER_BDT_STATISTICS
47 /*
48 * 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 * 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 *
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 */
129
130 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 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
135 struct arm_instr_call *ic) \
136 { if (cpu->cd.arm.flags & ARM_F_Z) \
137 arm_instr_ ## n (cpu, ic); } \
138 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
139 struct arm_instr_call *ic) \
140 { if (!(cpu->cd.arm.flags & ARM_F_Z)) \
141 arm_instr_ ## n (cpu, ic); } \
142 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
143 struct arm_instr_call *ic) \
144 { if (cpu->cd.arm.flags & ARM_F_C) \
145 arm_instr_ ## n (cpu, ic); } \
146 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
147 struct arm_instr_call *ic) \
148 { if (!(cpu->cd.arm.flags & ARM_F_C)) \
149 arm_instr_ ## n (cpu, ic); } \
150 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
151 struct arm_instr_call *ic) \
152 { if (cpu->cd.arm.flags & ARM_F_N) \
153 arm_instr_ ## n (cpu, ic); } \
154 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
155 struct arm_instr_call *ic) \
156 { if (!(cpu->cd.arm.flags & ARM_F_N)) \
157 arm_instr_ ## n (cpu, ic); } \
158 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
159 struct arm_instr_call *ic) \
160 { if (cpu->cd.arm.flags & ARM_F_V) \
161 arm_instr_ ## n (cpu, ic); } \
162 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
163 struct arm_instr_call *ic) \
164 { if (!(cpu->cd.arm.flags & ARM_F_V)) \
165 arm_instr_ ## n (cpu, ic); } \
166 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
167 struct arm_instr_call *ic) \
168 { if (condition_hi[cpu->cd.arm.flags]) \
169 arm_instr_ ## n (cpu, ic); } \
170 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
171 struct arm_instr_call *ic) \
172 { if (!condition_hi[cpu->cd.arm.flags]) \
173 arm_instr_ ## n (cpu, ic); } \
174 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
175 struct arm_instr_call *ic) \
176 { if (condition_ge[cpu->cd.arm.flags]) \
177 arm_instr_ ## n (cpu, ic); } \
178 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
179 struct arm_instr_call *ic) \
180 { if (!condition_ge[cpu->cd.arm.flags]) \
181 arm_instr_ ## n (cpu, ic); } \
182 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
183 struct arm_instr_call *ic) \
184 { if (condition_gt[cpu->cd.arm.flags]) \
185 arm_instr_ ## n (cpu, ic); } \
186 void arm_instr_ ## n ## __le(struct cpu *cpu, \
187 struct arm_instr_call *ic) \
188 { if (!condition_gt[cpu->cd.arm.flags]) \
189 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
215 << ARM_INSTR_ALIGNMENT_SHIFT);
216 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
217
218 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
223 cpu->cd.arm.next_ic = &nothing_call;
224 }
225
226
227 /*
228 * nop: Do nothing.
229 */
230 X(nop)
231 {
232 }
233
234
235 /*
236 * b: Branch (to a different translated page)
237 *
238 * arg[0] = relative offset from start of page
239 */
240 X(b)
241 {
242 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
243
244 /* Find the new physical page and update the translation pointers: */
245 quick_pc_to_pointers(cpu);
246 }
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 * arg[1] = pointer to the next instruction.
255 *
256 * NOTE: This instruction is manually inlined.
257 */
258 X(b_samepage) {
259 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
260 }
261 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
331
332 /*
333 * bx: Branch, potentially exchanging Thumb/ARM encoding
334 *
335 * arg[0] = ptr to rm
336 */
337 X(bx)
338 {
339 cpu->pc = reg(ic->arg[0]);
340 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 quick_pc_to_pointers(cpu);
348 }
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 cpu->pc = cpu->cd.arm.r[ARM_LR];
360 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 quick_pc_to_pointers(cpu);
370 }
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 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
382 cpu->cd.arm.r[ARM_LR] = pc + 4;
383
384 /* Calculate new PC from this instruction + arg[0] */
385 cpu->pc = pc + (int32_t)ic->arg[0];
386
387 /* Find the new physical page and update the translation pointers: */
388 quick_pc_to_pointers(cpu);
389 }
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 uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
401 cpu->cd.arm.r[ARM_LR] = lr;
402 cpu->pc = reg(ic->arg[0]);
403 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 quick_pc_to_pointers(cpu);
411 }
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 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
423 cpu->cd.arm.r[ARM_LR] = pc + 4;
424
425 /* Calculate new PC from this instruction + arg[0] */
426 cpu->pc = pc + (int32_t)ic->arg[0];
427
428 cpu_functioncall_trace(cpu, cpu->pc);
429
430 /* Find the new physical page and update the translation pointers: */
431 quick_pc_to_pointers(cpu);
432 }
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 cpu->cd.arm.r[ARM_LR] =
444 ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
445 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 uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
458
459 /* Link and branch: */
460 cpu->cd.arm.r[ARM_LR] = lr;
461 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
462
463 /* Synchronize the program counter: */
464 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
465 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
466 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
467 << ARM_INSTR_ALIGNMENT_SHIFT);
468 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
469
470 /* ... and show trace: */
471 cpu_functioncall_trace(cpu, cpu->pc);
472 }
473 Y(bl_samepage_trace)
474
475
476 /*
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
505
506 /*
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 uint32_t result;
521 result = reg(ic->arg[1]) * reg(ic->arg[2]);
522 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
523 if (result == 0)
524 cpu->cd.arm.flags |= ARM_F_Z;
525 if (result & 0x80000000)
526 cpu->cd.arm.flags |= ARM_F_N;
527 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 int rd, rs, rn, rm;
542 rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
543 rs = (iw >> 8) & 15; rm = iw & 15;
544 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 int rd, rs, rn, rm;
553 rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
554 rs = (iw >> 8) & 15; rm = iw & 15;
555 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
556 + cpu->cd.arm.r[rn];
557 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
558 if (cpu->cd.arm.r[rd] == 0)
559 cpu->cd.arm.flags |= ARM_F_Z;
560 if (cpu->cd.arm.r[rd] & 0x80000000)
561 cpu->cd.arm.flags |= ARM_F_N;
562 }
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 uint32_t iw; uint64_t tmp; int u_bit, a_bit;
575 iw = ic->arg[0];
576 u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
577 tmp = cpu->cd.arm.r[iw & 15];
578 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 * 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 * 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 * 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 * ret_trace: "mov pc,lr" with trace enabled
658 * ret: "mov pc,lr" without trace enabled
659 *
660 * arg[0] = ignored
661 */
662 X(ret_trace)
663 {
664 uint32_t old_pc, mask_within_page;
665 old_pc = cpu->pc;
666 mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
667 << ARM_INSTR_ALIGNMENT_SHIFT) |
668 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
669
670 /* Update the PC register: */
671 cpu->pc = cpu->cd.arm.r[ARM_LR];
672
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 quick_pc_to_pointers(cpu);
685 }
686 }
687 Y(ret_trace)
688 X(ret)
689 {
690 cpu->pc = cpu->cd.arm.r[ARM_LR];
691 quick_pc_to_pointers(cpu);
692 }
693 Y(ret)
694
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 cpu->cd.arm.cpsr &= 0x0fffffff;
715 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
716
717 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 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
724
725 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 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 printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc);
770 }
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 cpu->cd.arm.cpsr &= 0x0fffffff;
791 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
792 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
793 }
794 Y(mrs)
795
796
797 /*
798 * mrs: Move from saved status/flag register to a normal register.
799 *
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 uint32_t low_pc = ((size_t)ic - (size_t)
828 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
829 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
830 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
831 arm_mcr_mrc(cpu, ic->arg[0]);
832 }
833 Y(mcr_mrc)
834 X(cdp) {
835 uint32_t low_pc = ((size_t)ic - (size_t)
836 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
837 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
838 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
839 arm_cdp(cpu, ic->arg[0]);
840 }
841 Y(cdp)
842
843
844 /*
845 * openfirmware:
846 */
847 X(openfirmware)
848 {
849 /* TODO: sync pc? */
850 of_emul(cpu);
851 cpu->pc = cpu->cd.arm.r[ARM_LR];
852 if (cpu->machine->show_trace_tree)
853 cpu_functioncall_trace_return(cpu);
854 quick_pc_to_pointers(cpu);
855 }
856
857
858 /*
859 * 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 * 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
880 << ARM_INSTR_ALIGNMENT_SHIFT);
881 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
882 old_pc = cpu->pc;
883
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 quick_pc_to_pointers(cpu);
893 }
894 }
895 Y(swi_useremul)
896
897
898 /*
899 * swi: Software interrupt.
900 */
901 X(swi)
902 {
903 /* Synchronize the program counter first: */
904 cpu->pc &= 0xfffff000;
905 cpu->pc += ic->arg[0];
906 arm_exception(cpu, ARM_EXCEPTION_SWI);
907 }
908 Y(swi)
909
910
911 /*
912 * 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 * 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
936 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
940 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
941
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
963 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
967 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
968
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 X(store_w1_word_u1_p0_imm);
989 X(store_w0_byte_u1_p0_imm);
990 X(store_w0_word_u1_p0_imm);
991 X(store_w0_word_u1_p1_imm);
992 X(load_w0_word_u1_p0_imm);
993 X(load_w0_word_u1_p1_imm);
994 X(load_w1_word_u1_p0_imm);
995 X(load_w0_byte_u1_p1_imm);
996 X(load_w0_byte_u1_p1_reg);
997 X(load_w1_byte_u1_p1_imm);
998
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 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1009 extern void arm_r_r3_t0_c0(void);
1010
1011 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1012 struct arm_instr_call *);
1013 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1014 struct arm_instr_call *);
1015 X(cmps);
1016 X(teqs);
1017 X(tsts);
1018 X(sub);
1019 X(add);
1020 X(subs);
1021 X(eor_regshort);
1022 X(cmps_regshort);
1023
1024
1025 #include "cpu_arm_instr_misc.c"
1026
1027
1028 /*
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 int i, return_flag = 0;
1046 uint32_t new_values[16];
1047
1048 #ifdef GATHER_BDT_STATISTICS
1049 if (!s_bit)
1050 update_bdt_statistics(iw);
1051 #endif
1052
1053 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1057 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1058
1059 if (s_bit) {
1060 /* Load to USR registers: */
1061 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 }
1065 if (iw & 0x8000) {
1066 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 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1138 case ARM_MODE_USR32:
1139 case ARM_MODE_SYS32:
1140 cpu->cd.arm.r[i] = new_values[i];
1141 break;
1142 case ARM_MODE_FIQ32:
1143 if (i >= 8 && i <= 14)
1144 cpu->cd.arm.default_r8_r14[i-8] =
1145 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 case ARM_MODE_IRQ32:
1153 if (i >= 13 && i <= 14)
1154 cpu->cd.arm.default_r8_r14[i-8] =
1155 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 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1194
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 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1202 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 quick_pc_to_pointers(cpu);
1210 }
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 int i;
1233
1234 #ifdef GATHER_BDT_STATISTICS
1235 if (!s_bit)
1236 update_bdt_statistics(iw);
1237 #endif
1238
1239 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1243 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1244
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 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1255 case ARM_MODE_FIQ32:
1256 if (i >= 8 && i <= 14)
1257 value = cpu->cd.arm.default_r8_r14[i-8];
1258 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 value = cpu->cd.arm.default_r8_r14[i-8];
1265 break;
1266 case ARM_MODE_USR32:
1267 case ARM_MODE_SYS32:
1268 break;
1269 }
1270 }
1271
1272 /* NOTE/TODO: 8 vs 12 on some ARMs */
1273 if (i == ARM_PC)
1274 value = cpu->pc + 12;
1275
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 /* Various load/store multiple instructions: */
1332 extern uint32_t *multi_opcode[256];
1333 extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1334 X(multi_0x08b15018);
1335 X(multi_0x08ac000c__ge);
1336 X(multi_0x08a05018);
1337
1338
1339 /*****************************************************************************/
1340
1341
1342 /*
1343 * 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 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1363 ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1364 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 } 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
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 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1453 ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1454
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 cpu->cd.arm.r[0] += r1;
1476 cpu->cd.arm.r[1] = 0;
1477 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 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1529 if (t == 0)
1530 cpu->cd.arm.flags |= ARM_F_Z;
1531
1532 cpu->n_translated_instrs += 2;
1533 cpu->cd.arm.next_ic = &ic[3];
1534 }
1535
1536
1537 /*
1538 * 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 static int x = 0;
1573
1574 /* 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 if (cpu->machine->ncpus == 1 && (++x) == 100) {
1584 usleep(50);
1585 x = 0;
1586 }
1587
1588 cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6;
1589 cpu->cd.arm.next_ic = &nothing_call;
1590 return;
1591 }
1592
1593 cpu->cd.arm.next_ic = &ic[5];
1594 }
1595
1596
1597 /*
1598 * 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 /*****************************************************************************/
2074
2075
2076 X(end_of_page)
2077 {
2078 /* Update the PC: (offset 0, but on the next page) */
2079 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
2082 /* Find the new physical page and update the translation pointers: */
2083 quick_pc_to_pointers(cpu);
2084
2085 /* end_of_page doesn't count as an executed instruction: */
2086 cpu->n_translated_instrs --;
2087 }
2088
2089
2090 /*****************************************************************************/
2091
2092
2093 /*
2094 * Combine: netbsd_memset():
2095 *
2096 * 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 */
2099 void COMBINE(netbsd_memset)(struct cpu *cpu,
2100 struct arm_instr_call *ic, int low_addr)
2101 {
2102 #ifdef HOST_LITTLE_ENDIAN
2103 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2104 & (ARM_IC_ENTRIES_PER_PAGE-1);
2105
2106 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 #endif
2119 }
2120
2121
2122 /*
2123 * Combine: netbsd_memcpy():
2124 *
2125 * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2126 * sequence of ldmia instructions.
2127 */
2128 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2129 int low_addr)
2130 {
2131 #ifdef HOST_LITTLE_ENDIAN
2132 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 #endif
2148 }
2149
2150
2151 /*
2152 * Combine: netbsd_cacheclean():
2153 *
2154 * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2155 */
2156 void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2157 struct arm_instr_call *ic, int low_addr)
2158 {
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 * Combine: netbsd_cacheclean2():
2176 *
2177 * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2178 */
2179 void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2180 struct arm_instr_call *ic, int low_addr)
2181 {
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 * Combine: netbsd_scanc():
2200 */
2201 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2202 struct arm_instr_call *ic, int low_addr)
2203 {
2204 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2205 & (ARM_IC_ENTRIES_PER_PAGE-1);
2206
2207 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 }
2220 }
2221
2222
2223 /*
2224 * Combine: strlen():
2225 */
2226 void COMBINE(strlen)(struct cpu *cpu,
2227 struct arm_instr_call *ic, int low_addr)
2228 {
2229 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2230 & (ARM_IC_ENTRIES_PER_PAGE-1);
2231
2232 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 }
2243 }
2244
2245
2246 /*
2247 * Combine: xchg():
2248 */
2249 void COMBINE(xchg)(struct cpu *cpu,
2250 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
2256 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 * Combine: netbsd_copyin():
2273 */
2274 void COMBINE(netbsd_copyin)(struct cpu *cpu,
2275 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 * Combine: netbsd_copyout():
2304 */
2305 void COMBINE(netbsd_copyout)(struct cpu *cpu,
2306 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 * Combine: cmps + beq, etc:
2335 */
2336 void COMBINE(beq_etc)(struct cpu *cpu,
2337 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 }
2352 return;
2353 }
2354 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 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 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
2432
2433 /*****************************************************************************/
2434
2435
2436 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 /*
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 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2523 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 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2529 ARM_INSTR_ALIGNMENT_SHIFT);
2530 addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2531 cpu->pc = addr;
2532 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
2537 if (page != NULL) {
2538 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2539 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2540 } else {
2541 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2542 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 return;
2547 }
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 u_bit = iword & 0x00800000;
2567 w_bit = iword & 0x00200000;
2568 s_bit = l_bit = iword & 0x00100000;
2569 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 if (!cpu->translation_readahead)
2584 fatal("TODO: ARM condition code 0x%x\n",
2585 condition_code);
2586 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 if (!cpu->translation_readahead)
2628 fatal("TODO: sbit mull\n");
2629 goto bad;
2630 }
2631 ic->f = cond_instr(mull);
2632 ic->arg[0] = iword;
2633 break;
2634 }
2635 if ((iword & 0x0f900ff0) == 0x01000050) {
2636 if (!cpu->translation_readahead)
2637 fatal("TODO: q{,d}{add,sub}\n");
2638 goto bad;
2639 }
2640 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 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 /* 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 }
2695 if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2696 /* TODO: smulwY */
2697 goto bad;
2698 }
2699 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 if (rm == ARM_PC) {
2710 if (!cpu->translation_readahead)
2711 fatal("msr PC?\n");
2712 goto bad;
2713 }
2714 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 default:if (!cpu->translation_readahead)
2729 fatal("unimpl a: msr regform\n");
2730 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 if (!cpu->translation_readahead)
2738 fatal("mrs PC?\n");
2739 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 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2778 else
2779 ic->arg[1] = imm;
2780 break;
2781 }
2782
2783 if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
2784 if (!cpu->translation_readahead)
2785 fatal("reg form blah blah\n");
2786 goto bad;
2787 }
2788
2789 /* "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 break;
2796 }
2797
2798 /* "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 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2808 break;
2809 }
2810
2811 /* "mov reg,#0": */
2812 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2813 arm_switch_clear(ic, rd, condition_code);
2814 break;
2815 }
2816
2817 /* "mov reg,#1": */
2818 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2819 arm_switch_mov1(ic, rd, condition_code);
2820 break;
2821 }
2822
2823 /* "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 /*
2831 * Generic Data Processing Instructions:
2832 */
2833 if ((main_opcode & 2) == 0)
2834 regform = 1;
2835 else
2836 regform = 0;
2837
2838 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 imm = iword & 0xff;
2852 while (r8-- > 0)
2853 imm = (imm >> 2) | ((imm & 3) << 30);
2854 ic->arg[1] = imm;
2855 }
2856
2857 /* mvn #imm ==> mov #~imm */
2858 if (secondary_opcode == 0xf && !regform) {
2859 secondary_opcode = 0xd;
2860 ic->arg[1] = ~ic->arg[1];
2861 }
2862
2863 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 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
2878 if (ic->f == instr(eor_regshort))
2879 cpu->cd.arm.combination_check = COMBINE(xchg);
2880 if (iword == 0xe113000c)
2881 cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2882 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 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2906 if ((iword & 0x0e000010) == 0x06000010) {
2907 if (!cpu->translation_readahead)
2908 fatal("Not a Load/store TODO\n");
2909 goto bad;
2910 }
2911 /* 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 p = page;
2932 if (p != NULL) {
2933 memcpy(c, p + (a & 0xfff), len);
2934 } else {
2935 fatal("Hm? Internal error in "
2936 "cpu_arm_instr.c!\n");
2937 goto bad;
2938 }
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 cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2952 if (iword == 0xe4a17004)
2953 cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2954 break;
2955
2956 case 0x8: /* Multiple load/store... (Block data transfer) */
2957 case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2958 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2959 ic->arg[1] = (size_t)iword;
2960 /* Generic case: */
2961 if (l_bit)
2962 ic->f = cond_instr(bdt_load);
2963 else
2964 ic->f = cond_instr(bdt_store);
2965 #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 if (rn == ARM_PC) {
2994 if (!cpu->translation_readahead)
2995 fatal("TODO: bdt with PC as base\n");
2996 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
3006 /* Abort read-ahead on unconditional branches: */
3007 if (condition_code == 0xe &&
3008 cpu->translation_readahead > 1)
3009 cpu->translation_readahead = 1;
3010
3011 if (iword == 0xcaffffed)
3012 cpu->cd.arm.combination_check =
3013 COMBINE(netbsd_memset);
3014 if (iword == 0xaafffff9)
3015 cpu->cd.arm.combination_check =
3016 COMBINE(netbsd_memcpy);
3017 } 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 /* 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 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 /*
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 {
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 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 }
3070 }
3071
3072 if (main_opcode == 0xa && (condition_code <= 1
3073 || condition_code == 3 || condition_code == 8
3074 || condition_code == 12 || condition_code == 13))
3075 cpu->cd.arm.combination_check = COMBINE(beq_etc);
3076
3077 if (iword == 0x1afffffc)
3078 cpu->cd.arm.combination_check = COMBINE(strlen);
3079
3080 /* Hm. Does this really increase performance? */
3081 if (iword == 0x8afffffa)
3082 cpu->cd.arm.combination_check =
3083 COMBINE(netbsd_cacheclean2);
3084 break;
3085
3086 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 if ((iword & 0x0fe00fff) == 0x0c400000) {
3093 /* Special case: mar/mra DSP instructions */
3094 if (!cpu->translation_readahead)
3095 fatal("TODO: mar/mra DSP instructions!\n");
3096 /* Perhaps these are actually identical to MCRR/MRRC */
3097 goto bad;
3098 }
3099
3100 if ((iword & 0x0fe00000) == 0x0c400000) {
3101 if (!cpu->translation_readahead)
3102 fatal("MCRR/MRRC: TODO\n");
3103 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 #if 0
3113 ic->f = cond_instr(und);
3114 ic->arg[0] = addr & 0xfff;
3115 #else
3116 if (!cpu->translation_readahead)
3117 fatal("LDC/STC: TODO\n");
3118 goto bad;
3119 #endif
3120 break;
3121
3122 case 0xe:
3123 if ((iword & 0x0ff00ff0) == 0x0e200010) {
3124 /* Special case: mia* DSP instructions */
3125 /* See Intel's 27343601.pdf, page 16-20 */
3126 if (!cpu->translation_readahead)
3127 fatal("TODO: mia* DSP instructions!\n");
3128 goto bad;
3129 }
3130 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 if (iword == 0xee070f9a)
3140 cpu->cd.arm.combination_check =
3141 COMBINE(netbsd_cacheclean);
3142 break;
3143
3144 case 0xf:
3145 /* SWI: */
3146 /* Default handler: */
3147 ic->f = cond_instr(swi);
3148 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 /* 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 if (!cpu->translation_readahead)
3161 fatal("Bad userland SWI?\n");
3162 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