/[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 16 - (show annotations)
Mon Oct 8 16:19:01 2007 UTC (12 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 45576 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.988 2005/10/11 03:53:57 debug Exp $

==============  RELEASE 0.3.6  ==============

20051008	The bug was not because of faulty ARM documentation after all,
		but it was related to those parts of the code.
		Fixing the RTC (dev_mc146818) to work with CATS.
20051009	Rewriting the R() function; now there are 8192 automatically
		generated smaller functions doing the same thing, but hopefully
		faster. This also fixes some bugs which were triggered when
		trying to compile GXemul inside itself. :-)
		Adding a dummy dev_lpt.
20051010	Small hack to not update virtual translation tables if memory
		accesses are done with the NO_EXCEPTION flag; a time reduction
		of almost a factor 2 for a full NetBSD/cats install. :-)
20051011	Passing -A as the default boot arg for CATS (works fine with
		OpenBSD/cats).

==============  RELEASE 0.3.6.1  ==============


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_arm_instr.c,v 1.29 2005/10/11 03:31:28 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (If no instruction was executed, then it should be decreased. If, say, 4
34 * instructions were combined into one function and executed, then it should
35 * be increased by 3.)
36 */
37
38
39 /*
40 * Helper definitions:
41 *
42 * Each instruction is defined like this:
43 *
44 * X(foo)
45 * {
46 * code for foo;
47 * }
48 * Y(foo)
49 *
50 * The Y macro defines 14 copies of the instruction, one for each possible
51 * condition code. (The NV condition code is not included, and the AL code
52 * uses the main foo function.) Y also defines an array with pointers to
53 * all of these functions.
54 */
55
56 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
57 struct arm_instr_call *ic) \
58 { if (cpu->cd.arm.cpsr & ARM_FLAG_Z) \
59 arm_instr_ ## n (cpu, ic); } \
60 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
61 struct arm_instr_call *ic) \
62 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
63 arm_instr_ ## n (cpu, ic); } \
64 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
65 struct arm_instr_call *ic) \
66 { if (cpu->cd.arm.cpsr & ARM_FLAG_C) \
67 arm_instr_ ## n (cpu, ic); } \
68 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
69 struct arm_instr_call *ic) \
70 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_C)) \
71 arm_instr_ ## n (cpu, ic); } \
72 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
73 struct arm_instr_call *ic) \
74 { if (cpu->cd.arm.cpsr & ARM_FLAG_N) \
75 arm_instr_ ## n (cpu, ic); } \
76 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
77 struct arm_instr_call *ic) \
78 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_N)) \
79 arm_instr_ ## n (cpu, ic); } \
80 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
81 struct arm_instr_call *ic) \
82 { if (cpu->cd.arm.cpsr & ARM_FLAG_V) \
83 arm_instr_ ## n (cpu, ic); } \
84 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
85 struct arm_instr_call *ic) \
86 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_V)) \
87 arm_instr_ ## n (cpu, ic); } \
88 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
89 struct arm_instr_call *ic) \
90 { if (cpu->cd.arm.cpsr & ARM_FLAG_C && \
91 !(cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
92 arm_instr_ ## n (cpu, ic); } \
93 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
94 struct arm_instr_call *ic) \
95 { if (cpu->cd.arm.cpsr & ARM_FLAG_Z || \
96 !(cpu->cd.arm.cpsr & ARM_FLAG_C)) \
97 arm_instr_ ## n (cpu, ic); } \
98 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
99 struct arm_instr_call *ic) \
100 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == \
101 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) \
102 arm_instr_ ## n (cpu, ic); } \
103 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
104 struct arm_instr_call *ic) \
105 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != \
106 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) \
107 arm_instr_ ## n (cpu, ic); } \
108 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
109 struct arm_instr_call *ic) \
110 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == \
111 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) && \
112 !(cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
113 arm_instr_ ## n (cpu, ic); } \
114 void arm_instr_ ## n ## __le(struct cpu *cpu, \
115 struct arm_instr_call *ic) \
116 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != \
117 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) || \
118 (cpu->cd.arm.cpsr & ARM_FLAG_Z)) \
119 arm_instr_ ## n (cpu, ic); } \
120 void (*arm_cond_instr_ ## n [16])(struct cpu *, \
121 struct arm_instr_call *) = { \
122 arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
123 arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
124 arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
125 arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
126 arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
127 arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
128 arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
129 arm_instr_ ## n , arm_instr_nop };
130
131 #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
132
133
134 /*****************************************************************************/
135
136
137 /*
138 * nop: Do nothing.
139 * invalid: Invalid instructions end up here.
140 */
141 X(nop) { }
142 X(invalid) {
143 uint32_t low_pc;
144 low_pc = ((size_t)ic - (size_t)
145 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
146 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
147 << ARM_INSTR_ALIGNMENT_SHIFT);
148 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
149 cpu->pc = cpu->cd.arm.r[ARM_PC];
150
151 fatal("Invalid ARM instruction: pc=0x%08x\n", (int)cpu->pc);
152
153 cpu->running = 0;
154 cpu->running_translated = 0;
155 cpu->n_translated_instrs --;
156 cpu->cd.arm.next_ic = &nothing_call;
157 }
158
159
160 /*
161 * b: Branch (to a different translated page)
162 *
163 * arg[0] = relative offset
164 */
165 X(b)
166 {
167 uint32_t low_pc;
168
169 /* Calculate new PC from this instruction + arg[0] */
170 low_pc = ((size_t)ic - (size_t)
171 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
172 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
173 << ARM_INSTR_ALIGNMENT_SHIFT);
174 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
175 cpu->cd.arm.r[ARM_PC] += (int32_t)ic->arg[0];
176 cpu->pc = cpu->cd.arm.r[ARM_PC];
177
178 /* Find the new physical page and update the translation pointers: */
179 arm_pc_to_pointers(cpu);
180 }
181 Y(b)
182
183
184 /*
185 * b_samepage: Branch (to within the same translated page)
186 *
187 * arg[0] = pointer to new arm_instr_call
188 */
189 X(b_samepage)
190 {
191 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
192 }
193 Y(b_samepage)
194
195
196 /*
197 * bx: Branch, potentially exchanging Thumb/ARM encoding
198 *
199 * arg[0] = ptr to rm
200 */
201 X(bx)
202 {
203 cpu->pc = cpu->cd.arm.r[ARM_PC] = reg(ic->arg[0]);
204 if (cpu->pc & 1) {
205 fatal("thumb: TODO\n");
206 exit(1);
207 }
208 cpu->pc &= ~3;
209
210 /* Find the new physical page and update the translation pointers: */
211 arm_pc_to_pointers(cpu);
212 }
213 Y(bx)
214
215
216 /*
217 * bx_trace: As bx, but with trace enabled, arg[0] = the link register.
218 *
219 * arg[0] = ignored
220 */
221 X(bx_trace)
222 {
223 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
224 if (cpu->pc & 1) {
225 fatal("thumb: TODO\n");
226 exit(1);
227 }
228 cpu->pc &= ~3;
229
230 cpu_functioncall_trace_return(cpu);
231
232 /* Find the new physical page and update the translation pointers: */
233 arm_pc_to_pointers(cpu);
234 }
235 Y(bx_trace)
236
237
238 /*
239 * bl: Branch and Link (to a different translated page)
240 *
241 * arg[0] = relative address
242 */
243 X(bl)
244 {
245 uint32_t lr, low_pc;
246
247 /* Figure out what the return (link) address will be: */
248 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
249 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
250 lr = cpu->cd.arm.r[ARM_PC];
251 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
252 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
253
254 /* Link: */
255 cpu->cd.arm.r[ARM_LR] = lr;
256
257 /* Calculate new PC from this instruction + arg[0] */
258 cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
259
260 /* Find the new physical page and update the translation pointers: */
261 arm_pc_to_pointers(cpu);
262 }
263 Y(bl)
264
265
266 /*
267 * blx: Branch and Link, potentially exchanging Thumb/ARM encoding
268 *
269 * arg[0] = ptr to rm
270 */
271 X(blx)
272 {
273 uint32_t lr, low_pc;
274
275 /* Figure out what the return (link) address will be: */
276 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
277 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
278 lr = cpu->cd.arm.r[ARM_PC];
279 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
280 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
281
282 /* Link: */
283 cpu->cd.arm.r[ARM_LR] = lr;
284
285 cpu->pc = cpu->cd.arm.r[ARM_PC] = reg(ic->arg[0]);
286 if (cpu->pc & 1) {
287 fatal("thumb: TODO\n");
288 exit(1);
289 }
290 cpu->pc &= ~3;
291
292 /* Find the new physical page and update the translation pointers: */
293 arm_pc_to_pointers(cpu);
294 }
295 Y(blx)
296
297
298 /*
299 * bl_trace: Branch and Link (to a different translated page), with trace
300 *
301 * Same as for bl.
302 */
303 X(bl_trace)
304 {
305 uint32_t lr, low_pc;
306
307 /* Figure out what the return (link) address will be: */
308 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
309 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
310 lr = cpu->cd.arm.r[ARM_PC];
311 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
312 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
313
314 /* Link: */
315 cpu->cd.arm.r[ARM_LR] = lr;
316
317 /* Calculate new PC from this instruction + arg[0] */
318 cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];
319
320 cpu_functioncall_trace(cpu, cpu->pc);
321
322 /* Find the new physical page and update the translation pointers: */
323 arm_pc_to_pointers(cpu);
324 }
325 Y(bl_trace)
326
327
328 /*
329 * bl_samepage: A branch + link within the same page
330 *
331 * arg[0] = pointer to new arm_instr_call
332 */
333 X(bl_samepage)
334 {
335 uint32_t lr, low_pc;
336
337 /* Figure out what the return (link) address will be: */
338 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
339 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
340 lr = cpu->cd.arm.r[ARM_PC];
341 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
342 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
343
344 /* Link: */
345 cpu->cd.arm.r[ARM_LR] = lr;
346
347 /* Branch: */
348 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
349 }
350 Y(bl_samepage)
351
352
353 /*
354 * bl_samepage_trace: Branch and Link (to the same page), with trace
355 *
356 * Same as for bl_samepage.
357 */
358 X(bl_samepage_trace)
359 {
360 uint32_t tmp_pc, lr, low_pc;
361
362 /* Figure out what the return (link) address will be: */
363 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
364 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
365 lr = cpu->cd.arm.r[ARM_PC];
366 lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
367 lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
368
369 /* Link: */
370 cpu->cd.arm.r[ARM_LR] = lr;
371
372 /* Branch: */
373 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
374
375 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
376 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
377 tmp_pc = cpu->cd.arm.r[ARM_PC];
378 tmp_pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
379 << ARM_INSTR_ALIGNMENT_SHIFT);
380 tmp_pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
381 cpu_functioncall_trace(cpu, tmp_pc);
382 }
383 Y(bl_samepage_trace)
384
385
386 /*
387 * mul: Multiplication
388 *
389 * arg[0] = ptr to rd
390 * arg[1] = ptr to rm
391 * arg[2] = ptr to rs
392 */
393 X(mul)
394 {
395 reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
396 }
397 Y(mul)
398 X(muls)
399 {
400 uint32_t result = reg(ic->arg[1]) * reg(ic->arg[2]);
401 cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
402 if (result == 0)
403 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
404 if (result & 0x80000000)
405 cpu->cd.arm.cpsr |= ARM_FLAG_N;
406 reg(ic->arg[0]) = result;
407 }
408 Y(muls)
409
410
411 /*
412 * mla: Multiplication with addition
413 *
414 * arg[0] = copy of instruction word
415 */
416 X(mla)
417 {
418 /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
419 uint32_t iw = ic->arg[0];
420 int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,
421 rs = (iw >> 8) & 15, rm = iw & 15;
422 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
423 + cpu->cd.arm.r[rn];
424 }
425 Y(mla)
426 X(mlas)
427 {
428 /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
429 uint32_t iw = ic->arg[0];
430 int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,
431 rs = (iw >> 8) & 15, rm = iw & 15;
432 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
433 + cpu->cd.arm.r[rn];
434 cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);
435 if (cpu->cd.arm.r[rd] == 0)
436 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
437 if (cpu->cd.arm.r[rd] & 0x80000000)
438 cpu->cd.arm.cpsr |= ARM_FLAG_N;
439 }
440 Y(mlas)
441
442
443 /*
444 * mull: Long multiplication
445 *
446 * arg[0] = copy of instruction word
447 */
448 X(mull)
449 {
450 /* xxxx0000 1UAShhhh llllssss 1001mmmm */
451 uint32_t iw = ic->arg[0];
452 int u_bit = (iw >> 22) & 1, a_bit = (iw >> 21) & 1;
453 uint64_t tmp = cpu->cd.arm.r[iw & 15];
454 if (u_bit)
455 tmp = (int64_t)(int32_t)tmp
456 * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
457 else
458 tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
459 if (a_bit) {
460 uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
461 | cpu->cd.arm.r[(iw >> 12) & 15];
462 x += tmp;
463 cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
464 cpu->cd.arm.r[(iw >> 12) & 15] = x;
465 } else {
466 cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
467 cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
468 }
469 }
470 Y(mull)
471
472
473 /*
474 * mov_reg_reg: Move a register to another.
475 *
476 * arg[0] = ptr to source register
477 * arg[1] = ptr to destination register
478 */
479 X(mov_reg_reg)
480 {
481 reg(ic->arg[1]) = reg(ic->arg[0]);
482 }
483 Y(mov_reg_reg)
484
485
486 /*
487 * ret_trace: "mov pc,lr" with trace enabled
488 *
489 * arg[0] = ignored
490 */
491 X(ret_trace)
492 {
493 uint32_t old_pc = cpu->cd.arm.r[ARM_PC];
494 uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
495 << ARM_INSTR_ALIGNMENT_SHIFT) |
496 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
497
498 /* Update the PC register: */
499 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
500
501 cpu_functioncall_trace_return(cpu);
502
503 /*
504 * Is this a return to code within the same page? Then there is no
505 * need to update all pointers, just next_ic.
506 */
507 if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
508 cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
509 ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
510 } else {
511 /* Find the new physical page and update pointers: */
512 arm_pc_to_pointers(cpu);
513 }
514 }
515 Y(ret_trace)
516
517
518 /*
519 * msr: Move to status register from a normal register or immediate value.
520 *
521 * arg[0] = immediate value
522 * arg[1] = mask
523 * arg[2] = pointer to rm
524 *
525 * msr_imm and msr_imm_spsr use arg[1] and arg[0].
526 * msr and msr_spsr use arg[1] and arg[2].
527 */
528 X(msr_imm)
529 {
530 uint32_t mask = ic->arg[1];
531 int switch_register_banks = (mask & ARM_FLAG_MODE) &&
532 ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
533 (ic->arg[0] & ARM_FLAG_MODE));
534 uint32_t new_value = ic->arg[0];
535
536 if (switch_register_banks)
537 arm_save_register_bank(cpu);
538
539 cpu->cd.arm.cpsr &= ~mask;
540 cpu->cd.arm.cpsr |= (new_value & mask);
541
542 if (switch_register_banks)
543 arm_load_register_bank(cpu);
544 }
545 Y(msr_imm)
546 X(msr)
547 {
548 ic->arg[0] = reg(ic->arg[2]);
549 instr(msr_imm)(cpu, ic);
550 }
551 Y(msr)
552 X(msr_imm_spsr)
553 {
554 uint32_t mask = ic->arg[1];
555 uint32_t new_value = ic->arg[0];
556 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
557 case ARM_MODE_FIQ32:
558 cpu->cd.arm.spsr_fiq &= ~mask;
559 cpu->cd.arm.spsr_fiq |= (new_value & mask);
560 break;
561 case ARM_MODE_ABT32:
562 cpu->cd.arm.spsr_abt &= ~mask;
563 cpu->cd.arm.spsr_abt |= (new_value & mask);
564 break;
565 case ARM_MODE_UND32:
566 cpu->cd.arm.spsr_und &= ~mask;
567 cpu->cd.arm.spsr_und |= (new_value & mask);
568 break;
569 case ARM_MODE_IRQ32:
570 cpu->cd.arm.spsr_irq &= ~mask;
571 cpu->cd.arm.spsr_irq |= (new_value & mask);
572 break;
573 case ARM_MODE_SVC32:
574 cpu->cd.arm.spsr_svc &= ~mask;
575 cpu->cd.arm.spsr_svc |= (new_value & mask);
576 break;
577 default:fatal("msr_spsr: unimplemented mode %i\n",
578 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
579 {
580 /* Synchronize the program counter: */
581 uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
582 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
583 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
584 << ARM_INSTR_ALIGNMENT_SHIFT);
585 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
586 old_pc = cpu->pc = cpu->cd.arm.r[ARM_PC];
587 printf("msr_spsr: old pc = 0x%08x\n", old_pc);
588 }
589 exit(1);
590 }
591 }
592 Y(msr_imm_spsr)
593 X(msr_spsr)
594 {
595 ic->arg[0] = reg(ic->arg[2]);
596 instr(msr_imm_spsr)(cpu, ic);
597 }
598 Y(msr_spsr)
599
600
601 /*
602 * mrs: Move from status/flag register to a normal register.
603 *
604 * arg[0] = pointer to rd
605 */
606 X(mrs)
607 {
608 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
609 }
610 Y(mrs)
611
612
613 /*
614 * mrs: Move from status/flag register to a normal register.
615 *
616 * arg[0] = pointer to rd
617 */
618 X(mrs_spsr)
619 {
620 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
621 case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
622 case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
623 case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
624 case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
625 case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
626 case ARM_MODE_USR32:
627 case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
628 default:fatal("mrs_spsr: unimplemented mode %i\n",
629 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
630 exit(1);
631 }
632 }
633 Y(mrs_spsr)
634
635
636 /*
637 * mcr_mrc: Coprocessor move
638 * cdp: Coprocessor operation
639 *
640 * arg[0] = copy of the instruction word
641 */
642 X(mcr_mrc) {
643 uint32_t low_pc;
644 low_pc = ((size_t)ic - (size_t)
645 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
646 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
647 << ARM_INSTR_ALIGNMENT_SHIFT);
648 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
649 cpu->pc = cpu->cd.arm.r[ARM_PC];
650 arm_mcr_mrc(cpu, ic->arg[0]);
651 }
652 Y(mcr_mrc)
653 X(cdp) {
654 uint32_t low_pc;
655 low_pc = ((size_t)ic - (size_t)
656 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
657 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
658 << ARM_INSTR_ALIGNMENT_SHIFT);
659 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
660 cpu->pc = cpu->cd.arm.r[ARM_PC];
661 arm_cdp(cpu, ic->arg[0]);
662 }
663 Y(cdp)
664
665
666 /*
667 * openfirmware:
668 */
669 X(openfirmware)
670 {
671 of_emul(cpu);
672 cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];
673 if (cpu->machine->show_trace_tree)
674 cpu_functioncall_trace_return(cpu);
675 arm_pc_to_pointers(cpu);
676 }
677
678
679 /*
680 * swi_useremul: Syscall.
681 *
682 * arg[0] = swi number
683 */
684 X(swi_useremul)
685 {
686 /* Synchronize the program counter: */
687 uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
688 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
689 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
690 << ARM_INSTR_ALIGNMENT_SHIFT);
691 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
692 old_pc = cpu->pc = cpu->cd.arm.r[ARM_PC];
693
694 useremul_syscall(cpu, ic->arg[0]);
695
696 if (!cpu->running) {
697 cpu->running_translated = 0;
698 cpu->n_translated_instrs --;
699 cpu->cd.arm.next_ic = &nothing_call;
700 } else if (cpu->pc != old_pc) {
701 /* PC was changed by the SWI call. Find the new physical
702 page and update the translation pointers: */
703 arm_pc_to_pointers(cpu);
704 }
705 }
706 Y(swi_useremul)
707
708
709 /*
710 * swi: Software interrupt.
711 */
712 X(swi)
713 {
714 /* Synchronize the program counter: */
715 uint32_t low_pc = ((size_t)ic - (size_t)
716 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
717 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
718 << ARM_INSTR_ALIGNMENT_SHIFT);
719 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
720 cpu->pc = cpu->cd.arm.r[ARM_PC];
721
722 arm_exception(cpu, ARM_EXCEPTION_SWI);
723 }
724 Y(swi)
725
726
727 /*
728 * swp, swpb: Swap (word or byte).
729 *
730 * arg[0] = ptr to rd
731 * arg[1] = ptr to rm
732 * arg[2] = ptr to rn
733 */
734 X(swp)
735 {
736 uint32_t addr = reg(ic->arg[2]), data, data2;
737 unsigned char d[4];
738 /* Synchronize the program counter: */
739 uint32_t low_pc = ((size_t)ic - (size_t)
740 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
741 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
742 << ARM_INSTR_ALIGNMENT_SHIFT);
743 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
744 cpu->pc = cpu->cd.arm.r[ARM_PC];
745
746 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
747 CACHE_DATA)) {
748 fatal("swp: load failed\n");
749 return;
750 }
751 data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
752 data2 = reg(ic->arg[1]);
753 d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
754 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
755 CACHE_DATA)) {
756 fatal("swp: store failed\n");
757 return;
758 }
759 reg(ic->arg[0]) = data;
760 }
761 Y(swp)
762 X(swpb)
763 {
764 uint32_t addr = reg(ic->arg[2]), data;
765 unsigned char d[1];
766 /* Synchronize the program counter: */
767 uint32_t low_pc = ((size_t)ic - (size_t)
768 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
769 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
770 << ARM_INSTR_ALIGNMENT_SHIFT);
771 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
772 cpu->pc = cpu->cd.arm.r[ARM_PC];
773
774 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
775 CACHE_DATA)) {
776 fatal("swp: load failed\n");
777 return;
778 }
779 data = d[0];
780 d[0] = reg(ic->arg[1]);
781 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
782 CACHE_DATA)) {
783 fatal("swp: store failed\n");
784 return;
785 }
786 reg(ic->arg[0]) = data;
787 }
788 Y(swpb)
789
790
791 extern void (*arm_load_store_instr[1024])(struct cpu *,
792 struct arm_instr_call *);
793 X(store_w0_byte_u1_p0_imm);
794 X(store_w0_word_u1_p0_imm);
795
796 extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
797 struct arm_instr_call *);
798
799 extern void (*arm_load_store_instr_3[2048])(struct cpu *,
800 struct arm_instr_call *);
801
802 extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
803 struct arm_instr_call *);
804
805 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
806
807 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
808 struct arm_instr_call *);
809 X(cmps);
810 X(sub);
811 X(subs);
812
813
814
815 /*
816 * bdt_load: Block Data Transfer, Load
817 *
818 * arg[0] = pointer to uint32_t in host memory, pointing to the base register
819 * arg[1] = 32-bit instruction word. Most bits are read from this.
820 */
821 X(bdt_load)
822 {
823 unsigned char data[4];
824 uint32_t *np = (uint32_t *)ic->arg[0];
825 uint32_t addr = *np, low_pc;
826 unsigned char *page;
827 uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
828 int p_bit = iw & 0x01000000;
829 int u_bit = iw & 0x00800000;
830 int s_bit = iw & 0x00400000;
831 int w_bit = iw & 0x00200000;
832 int i, return_flag = 0;
833 uint32_t new_values[16];
834
835 /* Synchronize the program counter: */
836 low_pc = ((size_t)ic - (size_t)
837 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
838 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
839 ARM_INSTR_ALIGNMENT_SHIFT);
840 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
841 cpu->pc = cpu->cd.arm.r[ARM_PC];
842
843 if (s_bit) {
844 /* Load to USR registers: */
845 if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
846 fatal("[ bdt_load: s-bit: in usermode? ]\n");
847 s_bit = 0;
848 }
849 if (iw & 0x8000) {
850 s_bit = 0;
851 return_flag = 1;
852 }
853 }
854
855 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
856 uint32_t value;
857
858 if (!((iw >> i) & 1)) {
859 /* Skip register i: */
860 continue;
861 }
862
863 if (p_bit) {
864 if (u_bit)
865 addr += sizeof(uint32_t);
866 else
867 addr -= sizeof(uint32_t);
868 }
869
870 page = cpu->cd.arm.host_load[addr >> 12];
871 if (page != NULL) {
872 uint32_t *p32 = (uint32_t *) page;
873 value = p32[(addr & 0xfff) >> 2];
874 /* Change byte order of value if
875 host and emulated endianness differ: */
876 #ifdef HOST_LITTLE_ENDIAN
877 if (cpu->byte_order == EMUL_BIG_ENDIAN)
878 #else
879 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
880 #endif
881 value = ((value & 0xff) << 24) |
882 ((value & 0xff00) << 8) |
883 ((value & 0xff0000) >> 8) |
884 ((value & 0xff000000) >> 24);
885 } else {
886 if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
887 sizeof(data), MEM_READ, CACHE_DATA)) {
888 /* load failed */
889 return;
890 }
891 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
892 value = data[0] +
893 (data[1] << 8) + (data[2] << 16)
894 + (data[3] << 24);
895 } else {
896 value = data[3] +
897 (data[2] << 8) + (data[1] << 16)
898 + (data[0] << 24);
899 }
900 }
901
902 new_values[i] = value;
903
904 if (!p_bit) {
905 if (u_bit)
906 addr += sizeof(uint32_t);
907 else
908 addr -= sizeof(uint32_t);
909 }
910 }
911
912 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
913 if (!((iw >> i) & 1)) {
914 /* Skip register i: */
915 continue;
916 }
917
918 if (!s_bit) {
919 cpu->cd.arm.r[i] = new_values[i];
920 } else {
921 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
922 case ARM_MODE_USR32:
923 case ARM_MODE_SYS32:
924 cpu->cd.arm.r[i] = new_values[i];
925 break;
926 case ARM_MODE_FIQ32:
927 if (i >= 8 && i <= 14)
928 cpu->cd.arm.default_r8_r14[i-8] =
929 new_values[i];
930 else
931 cpu->cd.arm.r[i] = new_values[i];
932 break;
933 case ARM_MODE_SVC32:
934 case ARM_MODE_ABT32:
935 case ARM_MODE_UND32:
936 case ARM_MODE_IRQ32:
937 if (i >= 13 && i <= 14)
938 cpu->cd.arm.default_r8_r14[i-8] =
939 new_values[i];
940 else
941 cpu->cd.arm.r[i] = new_values[i];
942 break;
943 }
944 }
945 }
946
947 if (w_bit)
948 *np = addr;
949
950 if (return_flag) {
951 uint32_t new_cpsr;
952 int switch_register_banks;
953
954 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
955 case ARM_MODE_FIQ32:
956 new_cpsr = cpu->cd.arm.spsr_fiq; break;
957 case ARM_MODE_ABT32:
958 new_cpsr = cpu->cd.arm.spsr_abt; break;
959 case ARM_MODE_UND32:
960 new_cpsr = cpu->cd.arm.spsr_und; break;
961 case ARM_MODE_IRQ32:
962 new_cpsr = cpu->cd.arm.spsr_irq; break;
963 case ARM_MODE_SVC32:
964 new_cpsr = cpu->cd.arm.spsr_svc; break;
965 default:fatal("bdt_load: unimplemented mode %i\n",
966 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
967 exit(1);
968 }
969
970 switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
971 (new_cpsr & ARM_FLAG_MODE);
972
973 if (switch_register_banks)
974 arm_save_register_bank(cpu);
975
976 cpu->cd.arm.cpsr = new_cpsr;
977
978 if (switch_register_banks)
979 arm_load_register_bank(cpu);
980 }
981
982 /* NOTE: Special case: Loading the PC */
983 if (iw & 0x8000) {
984 cpu->cd.arm.r[ARM_PC] &= ~3;
985 cpu->pc = cpu->cd.arm.r[ARM_PC];
986 if (cpu->machine->show_trace_tree)
987 cpu_functioncall_trace_return(cpu);
988 /* TODO: There is no need to update the
989 pointers if this is a return to the
990 same page! */
991 /* Find the new physical page and update the
992 translation pointers: */
993 arm_pc_to_pointers(cpu);
994 }
995 }
996 Y(bdt_load)
997
998
999 /*
1000 * bdt_store: Block Data Transfer, Store
1001 *
1002 * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1003 * arg[1] = 32-bit instruction word. Most bits are read from this.
1004 */
1005 X(bdt_store)
1006 {
1007 unsigned char data[4];
1008 uint32_t *np = (uint32_t *)ic->arg[0];
1009 uint32_t low_pc, value, addr = *np;
1010 uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1011 unsigned char *page;
1012 int p_bit = iw & 0x01000000;
1013 int u_bit = iw & 0x00800000;
1014 int s_bit = iw & 0x00400000;
1015 int w_bit = iw & 0x00200000;
1016 int i;
1017
1018 /* Synchronize the program counter: */
1019 low_pc = ((size_t)ic - (size_t)
1020 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1021 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
1022 ARM_INSTR_ALIGNMENT_SHIFT);
1023 cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1024 cpu->pc = cpu->cd.arm.r[ARM_PC];
1025
1026 for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1027 if (!((iw >> i) & 1)) {
1028 /* Skip register i: */
1029 continue;
1030 }
1031
1032 value = cpu->cd.arm.r[i];
1033
1034 if (s_bit) {
1035 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1036 case ARM_MODE_FIQ32:
1037 if (i >= 8 && i <= 14)
1038 value = cpu->cd.arm.default_r8_r14[i-8];
1039 break;
1040 case ARM_MODE_ABT32:
1041 case ARM_MODE_UND32:
1042 case ARM_MODE_IRQ32:
1043 case ARM_MODE_SVC32:
1044 if (i >= 13 && i <= 14)
1045 value = cpu->cd.arm.default_r8_r14[i-8];
1046 break;
1047 case ARM_MODE_USR32:
1048 case ARM_MODE_SYS32:
1049 break;
1050 }
1051 }
1052
1053 if (i == ARM_PC)
1054 value += 12; /* NOTE/TODO: 8 on some ARMs */
1055
1056 if (p_bit) {
1057 if (u_bit)
1058 addr += sizeof(uint32_t);
1059 else
1060 addr -= sizeof(uint32_t);
1061 }
1062
1063 page = cpu->cd.arm.host_store[addr >> 12];
1064 if (page != NULL) {
1065 uint32_t *p32 = (uint32_t *) page;
1066 /* Change byte order of value if
1067 host and emulated endianness differ: */
1068 #ifdef HOST_LITTLE_ENDIAN
1069 if (cpu->byte_order == EMUL_BIG_ENDIAN)
1070 #else
1071 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1072 #endif
1073 value = ((value & 0xff) << 24) |
1074 ((value & 0xff00) << 8) |
1075 ((value & 0xff0000) >> 8) |
1076 ((value & 0xff000000) >> 24);
1077 p32[(addr & 0xfff) >> 2] = value;
1078 } else {
1079 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1080 data[0] = value;
1081 data[1] = value >> 8;
1082 data[2] = value >> 16;
1083 data[3] = value >> 24;
1084 } else {
1085 data[0] = value >> 24;
1086 data[1] = value >> 16;
1087 data[2] = value >> 8;
1088 data[3] = value;
1089 }
1090 if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1091 sizeof(data), MEM_WRITE, CACHE_DATA)) {
1092 /* store failed */
1093 return;
1094 }
1095 }
1096
1097 if (!p_bit) {
1098 if (u_bit)
1099 addr += sizeof(uint32_t);
1100 else
1101 addr -= sizeof(uint32_t);
1102 }
1103 }
1104
1105 if (w_bit)
1106 *np = addr;
1107 }
1108 Y(bdt_store)
1109
1110
1111 /*****************************************************************************/
1112
1113
1114 /*
1115 * fill_loop_test:
1116 *
1117 * A byte-fill loop. Fills at most one page at a time. If the page was not
1118 * in the host_store table, then the original sequence (beginning with
1119 * cmps rZ,#0) is executed instead.
1120 *
1121 * L: cmps rZ,#0 ic[0]
1122 * strb rX,[rY],#1 ic[1]
1123 * sub rZ,rZ,#1 ic[2]
1124 * bgt L ic[3]
1125 *
1126 * A maximum of 4 pages are filled before returning.
1127 */
1128 X(fill_loop_test)
1129 {
1130 int max_pages_left = 4;
1131 uint32_t addr, a, n, ofs, maxlen;
1132 uint32_t *rzp = (uint32_t *)(size_t)ic[0].arg[0];
1133 unsigned char *page;
1134
1135 restart_loop:
1136 addr = reg(ic[1].arg[0]);
1137 page = cpu->cd.arm.host_store[addr >> 12];
1138 if (page == NULL) {
1139 instr(cmps)(cpu, ic);
1140 return;
1141 }
1142
1143 n = reg(rzp) + 1;
1144 ofs = addr & 0xfff;
1145 maxlen = 4096 - ofs;
1146 if (n > maxlen)
1147 n = maxlen;
1148
1149 /* printf("x = %x, n = %i\n", reg(ic[1].arg[2]), n); */
1150 memset(page + ofs, reg(ic[1].arg[2]), n);
1151
1152 reg(ic[1].arg[0]) = addr + n;
1153
1154 reg(rzp) -= n;
1155 cpu->n_translated_instrs += (4 * n);
1156
1157 a = reg(rzp);
1158
1159 cpu->cd.arm.cpsr &=
1160 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
1161 if (a != 0)
1162 cpu->cd.arm.cpsr |= ARM_FLAG_C;
1163 else
1164 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
1165 if ((int32_t)a < 0)
1166 cpu->cd.arm.cpsr |= ARM_FLAG_N;
1167
1168 if (max_pages_left-- > 0 && (int32_t)a > 0)
1169 goto restart_loop;
1170
1171 cpu->n_translated_instrs --;
1172
1173 if ((int32_t)a > 0)
1174 cpu->cd.arm.next_ic = ic;
1175 else
1176 cpu->cd.arm.next_ic = &ic[4];
1177 }
1178
1179
1180 /*
1181 * fill_loop_test2:
1182 *
1183 * A word-fill loop. Fills at most one page at a time. If the page was not
1184 * in the host_store table, then the original sequence (beginning with
1185 * cmps rZ,#0) is executed instead.
1186 *
1187 * L: str rX,[rY],#4 ic[0]
1188 * subs rZ,rZ,#4 ic[1]
1189 * bgt L ic[2]
1190 *
1191 * A maximum of 5 pages are filled before returning.
1192 */
1193 X(fill_loop_test2)
1194 {
1195 int max_pages_left = 5;
1196 unsigned char x1,x2,x3,x4;
1197 uint32_t addr, a, n, x, ofs, maxlen;
1198 uint32_t *rzp = (uint32_t *)(size_t)ic[1].arg[0];
1199 unsigned char *page;
1200
1201 x = reg(ic[0].arg[2]);
1202 x1 = x; x2 = x >> 8; x3 = x >> 16; x4 = x >> 24;
1203 if (x1 != x2 || x1 != x3 || x1 != x4) {
1204 instr(store_w0_word_u1_p0_imm)(cpu, ic);
1205 return;
1206 }
1207
1208 restart_loop:
1209 addr = reg(ic[0].arg[0]);
1210 page = cpu->cd.arm.host_store[addr >> 12];
1211 if (page == NULL || (addr & 3) != 0) {
1212 instr(store_w0_word_u1_p0_imm)(cpu, ic);
1213 return;
1214 }
1215
1216 /* printf("addr = 0x%08x, page = %p\n", addr, page);
1217 printf("*rzp = 0x%08x\n", reg(rzp)); */
1218
1219 n = reg(rzp) / 4;
1220 if (n == 0)
1221 n++;
1222 /* n = nr of _words_ */
1223 ofs = addr & 0xfff;
1224 maxlen = 4096 - ofs;
1225 if (n*4 > maxlen)
1226 n = maxlen / 4;
1227
1228 /* printf("x = %x, n = %i\n", x1, n); */
1229 memset(page + ofs, x1, n * 4);
1230
1231 reg(ic[0].arg[0]) = addr + n * 4;
1232
1233 reg(rzp) -= (n * 4);
1234 cpu->n_translated_instrs += (3 * n);
1235
1236 a = reg(rzp);
1237
1238 cpu->cd.arm.cpsr &=
1239 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
1240 if (a != 0)
1241 cpu->cd.arm.cpsr |= ARM_FLAG_C;
1242 else
1243 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
1244 if ((int32_t)a < 0)
1245 cpu->cd.arm.cpsr |= ARM_FLAG_N;
1246
1247 if (max_pages_left-- > 0 && (int32_t)a > 0)
1248 goto restart_loop;
1249
1250 cpu->n_translated_instrs --;
1251
1252 if ((int32_t)a > 0)
1253 cpu->cd.arm.next_ic = ic;
1254 else
1255 cpu->cd.arm.next_ic = &ic[3];
1256 }
1257
1258
1259 /*****************************************************************************/
1260
1261
1262 X(end_of_page)
1263 {
1264 /* Update the PC: (offset 0, but on the next page) */
1265 cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
1266 << ARM_INSTR_ALIGNMENT_SHIFT);
1267 cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE
1268 << ARM_INSTR_ALIGNMENT_SHIFT);
1269 cpu->pc = cpu->cd.arm.r[ARM_PC];
1270
1271 /* Find the new physical page and update the translation pointers: */
1272 arm_pc_to_pointers(cpu);
1273
1274 /* end_of_page doesn't count as an executed instruction: */
1275 cpu->n_translated_instrs --;
1276 }
1277
1278
1279 /*****************************************************************************/
1280
1281
1282 /*
1283 * arm_combine_instructions():
1284 *
1285 * Combine two or more instructions, if possible, into a single function call.
1286 */
1287 void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic,
1288 uint32_t addr)
1289 {
1290 int n_back;
1291 n_back = (addr >> ARM_INSTR_ALIGNMENT_SHIFT)
1292 & (ARM_IC_ENTRIES_PER_PAGE-1);
1293
1294 if (n_back >= 2) {
1295 if (ic[-2].f == instr(store_w0_word_u1_p0_imm) &&
1296 ic[-2].arg[1] == 4 &&
1297 ic[-1].f == instr(subs) &&
1298 ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 4 &&
1299 ic[ 0].f == instr(b_samepage__gt) &&
1300 ic[ 0].arg[0] == (size_t)&ic[-2]) {
1301 ic[-2].f = instr(fill_loop_test2);
1302 combined;
1303 }
1304 }
1305
1306 if (n_back >= 3) {
1307 if (ic[-3].f == instr(cmps) &&
1308 ic[-3].arg[0] == ic[-1].arg[0] &&
1309 ic[-3].arg[1] == 0 &&
1310 ic[-2].f == instr(store_w0_byte_u1_p0_imm) &&
1311 ic[-2].arg[1] == 1 &&
1312 ic[-1].f == instr(sub) &&
1313 ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 1 &&
1314 ic[ 0].f == instr(b_samepage__gt) &&
1315 ic[ 0].arg[0] == (size_t)&ic[-3]) {
1316 ic[-3].f = instr(fill_loop_test);
1317 combined;
1318 }
1319 }
1320
1321 /* TODO: Combine forward as well */
1322 }
1323
1324
1325 /*****************************************************************************/
1326
1327
1328 /*
1329 * arm_instr_to_be_translated():
1330 *
1331 * Translate an instruction word into an arm_instr_call. ic is filled in with
1332 * valid data for the translated instruction, or a "nothing" instruction if
1333 * there was a translation failure. The newly translated instruction is then
1334 * executed.
1335 */
1336 X(to_be_translated)
1337 {
1338 uint32_t addr, low_pc, iword, imm = 0;
1339 unsigned char *page;
1340 unsigned char ib[4];
1341 int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
1342 int p_bit, u_bit, b_bit, w_bit, l_bit, regform, rm, c, t;
1343 int any_pc_reg;
1344 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
1345
1346 /* Figure out the address of the instruction: */
1347 low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
1348 / sizeof(struct arm_instr_call);
1349 addr = cpu->cd.arm.r[ARM_PC] & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
1350 ARM_INSTR_ALIGNMENT_SHIFT);
1351 addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1352 cpu->pc = cpu->cd.arm.r[ARM_PC] = addr;
1353 addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
1354
1355 /* Read the instruction word from memory: */
1356 page = cpu->cd.arm.host_load[addr >> 12];
1357 if (page != NULL) {
1358 /* fatal("TRANSLATION HIT!\n"); */
1359 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
1360 } else {
1361 /* fatal("TRANSLATION MISS!\n"); */
1362 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
1363 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
1364 fatal("to_be_translated(): "
1365 "read failed: TODO\n");
1366 goto bad;
1367 }
1368 }
1369
1370 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1371 iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
1372 else
1373 iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
1374
1375
1376 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
1377 #include "cpu_dyntrans.c"
1378 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
1379
1380
1381 /* The idea of taking bits 27..24 was found here:
1382 http://armphetamine.sourceforge.net/oldinfo.html */
1383 condition_code = iword >> 28;
1384 main_opcode = (iword >> 24) & 15;
1385 secondary_opcode = (iword >> 21) & 15;
1386 u_bit = (iword >> 23) & 1;
1387 b_bit = (iword >> 22) & 1;
1388 w_bit = (iword >> 21) & 1;
1389 s_bit = l_bit = (iword >> 20) & 1;
1390 rn = (iword >> 16) & 15;
1391 rd = (iword >> 12) & 15;
1392 r8 = (iword >> 8) & 15;
1393 c = (iword >> 7) & 31;
1394 t = (iword >> 4) & 7;
1395 rm = iword & 15;
1396
1397 if (condition_code == 0xf) {
1398 if ((iword & 0xfc70f000) == 0xf450f000) {
1399 /* Preload: TODO. Treat as NOP for now. */
1400 ic->f = instr(nop);
1401 goto okay;
1402 }
1403
1404 fatal("TODO: ARM condition code 0x%x\n",
1405 condition_code);
1406 goto bad;
1407 }
1408
1409
1410 /*
1411 * Translate the instruction:
1412 */
1413
1414 switch (main_opcode) {
1415
1416 case 0x0:
1417 case 0x1:
1418 case 0x2:
1419 case 0x3:
1420 /* Check special cases first: */
1421 if ((iword & 0x0fc000f0) == 0x00000090) {
1422 /*
1423 * Multiplication:
1424 * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])
1425 */
1426 if (iword & 0x00200000) {
1427 if (s_bit)
1428 ic->f = cond_instr(mlas);
1429 else
1430 ic->f = cond_instr(mla);
1431 ic->arg[0] = iword;
1432 } else {
1433 if (s_bit)
1434 ic->f = cond_instr(muls);
1435 else
1436 ic->f = cond_instr(mul);
1437 /* NOTE: rn means rd in this case: */
1438 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1439 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
1440 ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]);
1441 }
1442 break;
1443 }
1444 if ((iword & 0x0f8000f0) == 0x00800090) {
1445 /* Long multiplication: */
1446 if (s_bit) {
1447 fatal("TODO: sbit mull\n");
1448 goto bad;
1449 }
1450 ic->f = cond_instr(mull);
1451 ic->arg[0] = iword;
1452 break;
1453 }
1454 if ((iword & 0x0ff000d0) == 0x01200010) {
1455 /* bx or blx */
1456 if (iword & 0x20)
1457 ic->f = cond_instr(blx);
1458 else {
1459 if (cpu->machine->show_trace_tree &&
1460 rm == ARM_LR)
1461 ic->f = cond_instr(bx_trace);
1462 else
1463 ic->f = cond_instr(bx);
1464 }
1465 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
1466 break;
1467 }
1468 if ((iword & 0x0fb00ff0) == 0x1000090) {
1469 if (iword & 0x00400000)
1470 ic->f = cond_instr(swpb);
1471 else
1472 ic->f = cond_instr(swp);
1473 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
1474 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
1475 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
1476 break;
1477 }
1478 if ((iword & 0x0fb0fff0) == 0x0120f000 ||
1479 (iword & 0x0fb0f000) == 0x0320f000) {
1480 /* msr: move to [S|C]PSR from a register or
1481 immediate value */
1482 if (rm == ARM_PC) {
1483 fatal("msr PC?\n");
1484 goto bad;
1485 }
1486 if (iword & 0x02000000) {
1487 if (iword & 0x00400000)
1488 ic->f = cond_instr(msr_imm_spsr);
1489 else
1490 ic->f = cond_instr(msr_imm);
1491 } else {
1492 if (iword & 0x00400000)
1493 ic->f = cond_instr(msr_spsr);
1494 else
1495 ic->f = cond_instr(msr);
1496 }
1497 imm = iword & 0xff;
1498 while (r8-- > 0)
1499 imm = (imm >> 2) | ((imm & 3) << 30);
1500 ic->arg[0] = imm;
1501 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
1502 switch ((iword >> 16) & 15) {
1503 case 1: ic->arg[1] = 0x000000ff; break;
1504 case 8: ic->arg[1] = 0xff000000; break;
1505 case 9: ic->arg[1] = 0xff0000ff; break;
1506 default:fatal("unimpl a: msr regform\n");
1507 goto bad;
1508 }
1509 break;
1510 }
1511 if ((iword & 0x0fbf0fff) == 0x010f0000) {
1512 /* mrs: move from CPSR/SPSR to a register: */
1513 if (rd == ARM_PC) {
1514 fatal("mrs PC?\n");
1515 goto bad;
1516 }
1517 if (iword & 0x00400000)
1518 ic->f = cond_instr(mrs_spsr);
1519 else
1520 ic->f = cond_instr(mrs);
1521 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
1522 break;
1523 }
1524 if ((iword & 0x0e000090) == 0x00000090) {
1525 int imm = ((iword >> 4) & 0xf0) | (iword & 0xf);
1526 int regform = !(iword & 0x00400000);
1527 p_bit = main_opcode & 1;
1528 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1529 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
1530 if (rd == ARM_PC || rn == ARM_PC) {
1531 ic->f = arm_load_store_instr_3_pc[
1532 condition_code + (l_bit? 16 : 0)
1533 + (iword & 0x40? 32 : 0)
1534 + (w_bit? 64 : 0)
1535 + (iword & 0x20? 128 : 0)
1536 + (u_bit? 256 : 0) + (p_bit? 512 : 0)
1537 + (regform? 1024 : 0)];
1538 if (rn == ARM_PC)
1539 ic->arg[0] = (size_t)
1540 (&cpu->cd.arm.tmp_pc);
1541 if (!l_bit && rd == ARM_PC)
1542 ic->arg[2] = (size_t)
1543 (&cpu->cd.arm.tmp_pc);
1544 } else
1545 ic->f = arm_load_store_instr_3[
1546 condition_code + (l_bit? 16 : 0)
1547 + (iword & 0x40? 32 : 0)
1548 + (w_bit? 64 : 0)
1549 + (iword & 0x20? 128 : 0)
1550 + (u_bit? 256 : 0) + (p_bit? 512 : 0)
1551 + (regform? 1024 : 0)];
1552 if (regform)
1553 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
1554 else
1555 ic->arg[1] = imm;
1556 break;
1557 }
1558
1559 if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
1560 fatal("reg form blah blah\n");
1561 goto bad;
1562 }
1563
1564 /* "mov pc,lr" with trace enabled: */
1565 if ((iword & 0x0fffffff) == 0x01a0f00e &&
1566 cpu->machine->show_trace_tree) {
1567 ic->f = cond_instr(ret_trace);
1568 break;
1569 }
1570
1571 /* "mov reg,reg": */
1572 if ((iword & 0x0fff0ff0) == 0x01a00000 &&
1573 (iword&15) != ARM_PC && rd != ARM_PC) {
1574 ic->f = cond_instr(mov_reg_reg);
1575 ic->arg[0] = (size_t)(&cpu->cd.arm.r[iword & 15]);
1576 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
1577 break;
1578 }
1579
1580 /*
1581 * Generic Data Processing Instructions:
1582 */
1583 if ((main_opcode & 2) == 0)
1584 regform = 1;
1585 else
1586 regform = 0;
1587
1588 if (regform) {
1589 /* 0x1000 signifies Carry bit update on rotation,
1590 which is not necessary for add,adc,sub,sbc,
1591 rsb,rsc,cmp, or cmn, because they update the
1592 Carry bit manually anyway. */
1593 int q = 0x1000;
1594 if (s_bit == 0)
1595 q = 0;
1596 if ((secondary_opcode >= 2 && secondary_opcode <= 7)
1597 || secondary_opcode==0xa || secondary_opcode==0xb)
1598 q = 0;
1599 ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q];
1600 } else {
1601 imm = iword & 0xff;
1602 while (r8-- > 0)
1603 imm = (imm >> 2) | ((imm & 3) << 30);
1604 ic->arg[1] = imm;
1605 }
1606
1607 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1608 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
1609 any_pc_reg = 0;
1610 if (rn == ARM_PC || rd == ARM_PC)
1611 any_pc_reg = 1;
1612
1613 ic->f = arm_dpi_instr[condition_code +
1614 16 * secondary_opcode + (s_bit? 256 : 0) +
1615 (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
1616 break;
1617
1618 case 0x4: /* Load and store... */
1619 case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
1620 case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
1621 case 0x7:
1622 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1623 ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
1624 if (rd == ARM_PC || rn == ARM_PC) {
1625 ic->f = arm_load_store_instr_pc[((iword >> 16)
1626 & 0x3f0) + condition_code];
1627 if (rn == ARM_PC)
1628 ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc);
1629 if (!l_bit && rd == ARM_PC)
1630 ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc);
1631 } else {
1632 ic->f = arm_load_store_instr[((iword >> 16) &
1633 0x3f0) + condition_code];
1634 }
1635 imm = iword & 0xfff;
1636 if (main_opcode < 6)
1637 ic->arg[1] = imm;
1638 else
1639 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
1640 if ((iword & 0x0e000010) == 0x06000010) {
1641 fatal("Not a Load/store TODO\n");
1642 goto bad;
1643 }
1644 break;
1645
1646 case 0x8: /* Multiple load/store... (Block data transfer) */
1647 case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
1648 if (l_bit)
1649 ic->f = cond_instr(bdt_load);
1650 else
1651 ic->f = cond_instr(bdt_store);
1652 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
1653 ic->arg[1] = (size_t)iword;
1654 if (rn == ARM_PC) {
1655 fatal("TODO: bdt with PC as base\n");
1656 goto bad;
1657 }
1658 break;
1659
1660 case 0xa: /* B: branch */
1661 case 0xb: /* BL: branch+link */
1662 if (main_opcode == 0x0a) {
1663 ic->f = cond_instr(b);
1664 samepage_function = cond_instr(b_samepage);
1665 } else {
1666 if (cpu->machine->show_trace_tree) {
1667 ic->f = cond_instr(bl_trace);
1668 samepage_function =
1669 cond_instr(bl_samepage_trace);
1670 } else {
1671 ic->f = cond_instr(bl);
1672 samepage_function = cond_instr(bl_samepage);
1673 }
1674 }
1675
1676 ic->arg[0] = (iword & 0x00ffffff) << 2;
1677 /* Sign-extend: */
1678 if (ic->arg[0] & 0x02000000)
1679 ic->arg[0] |= 0xfc000000;
1680 /*
1681 * Branches are calculated as PC + 8 + offset.
1682 */
1683 ic->arg[0] = (int32_t)(ic->arg[0] + 8);
1684
1685 /* Special case: branch within the same page: */
1686 {
1687 uint32_t mask_within_page =
1688 ((ARM_IC_ENTRIES_PER_PAGE-1) <<
1689 ARM_INSTR_ALIGNMENT_SHIFT) |
1690 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
1691 uint32_t old_pc = addr;
1692 uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
1693 if ((old_pc & ~mask_within_page) ==
1694 (new_pc & ~mask_within_page)) {
1695 ic->f = samepage_function;
1696 ic->arg[0] = (size_t) (
1697 cpu->cd.arm.cur_ic_page +
1698 ((new_pc & mask_within_page) >>
1699 ARM_INSTR_ALIGNMENT_SHIFT));
1700 }
1701 }
1702 break;
1703
1704 case 0xe:
1705 if (iword & 0x10) {
1706 /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */
1707 ic->arg[0] = iword;
1708 ic->f = cond_instr(mcr_mrc);
1709 } else {
1710 /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */
1711 ic->arg[0] = iword;
1712 ic->f = cond_instr(cdp);
1713 }
1714 break;
1715
1716 case 0xf:
1717 /* SWI: */
1718 /* Default handler: */
1719 ic->f = cond_instr(swi);
1720 if (iword == 0xef8c64be) {
1721 /* Hack for openfirmware prom emulation: */
1722 ic->f = instr(openfirmware);
1723 } else if (cpu->machine->userland_emul != NULL) {
1724 if ((iword & 0x00f00000) == 0x00a00000) {
1725 ic->arg[0] = iword & 0x00ffffff;
1726 ic->f = cond_instr(swi_useremul);
1727 } else {
1728 fatal("Bad userland SWI?\n");
1729 goto bad;
1730 }
1731 }
1732 break;
1733
1734 default:goto bad;
1735 }
1736
1737 okay:
1738
1739 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
1740 #include "cpu_dyntrans.c"
1741 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
1742 }
1743

  ViewVC Help
Powered by ViewVC 1.1.26