/[gxemul]/trunk/src/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/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 25914 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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.20 2005/06/27 09:20:19 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->cd.arm.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 X(n) void arm_instr_ ## n(struct cpu *cpu, \
57 struct arm_instr_call *ic)
58
59 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
60 struct arm_instr_call *ic) \
61 { if (cpu->cd.arm.flags & ARM_FLAG_Z) \
62 arm_instr_ ## n (cpu, ic); } \
63 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
64 struct arm_instr_call *ic) \
65 { if (!(cpu->cd.arm.flags & ARM_FLAG_Z)) \
66 arm_instr_ ## n (cpu, ic); } \
67 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
68 struct arm_instr_call *ic) \
69 { if (cpu->cd.arm.flags & ARM_FLAG_C) \
70 arm_instr_ ## n (cpu, ic); } \
71 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
72 struct arm_instr_call *ic) \
73 { if (!(cpu->cd.arm.flags & ARM_FLAG_C)) \
74 arm_instr_ ## n (cpu, ic); } \
75 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
76 struct arm_instr_call *ic) \
77 { if (cpu->cd.arm.flags & ARM_FLAG_N) \
78 arm_instr_ ## n (cpu, ic); } \
79 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
80 struct arm_instr_call *ic) \
81 { if (!(cpu->cd.arm.flags & ARM_FLAG_N)) \
82 arm_instr_ ## n (cpu, ic); } \
83 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
84 struct arm_instr_call *ic) \
85 { if (cpu->cd.arm.flags & ARM_FLAG_V) \
86 arm_instr_ ## n (cpu, ic); } \
87 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
88 struct arm_instr_call *ic) \
89 { if (!(cpu->cd.arm.flags & ARM_FLAG_V)) \
90 arm_instr_ ## n (cpu, ic); } \
91 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
92 struct arm_instr_call *ic) \
93 { if (cpu->cd.arm.flags & ARM_FLAG_C && \
94 !(cpu->cd.arm.flags & ARM_FLAG_Z)) \
95 arm_instr_ ## n (cpu, ic); } \
96 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
97 struct arm_instr_call *ic) \
98 { if (cpu->cd.arm.flags & ARM_FLAG_Z && \
99 !(cpu->cd.arm.flags & ARM_FLAG_C)) \
100 arm_instr_ ## n (cpu, ic); } \
101 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
102 struct arm_instr_call *ic) \
103 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) == \
104 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0)) \
105 arm_instr_ ## n (cpu, ic); } \
106 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
107 struct arm_instr_call *ic) \
108 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) != \
109 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0)) \
110 arm_instr_ ## n (cpu, ic); } \
111 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
112 struct arm_instr_call *ic) \
113 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) == \
114 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0) && \
115 !(cpu->cd.arm.flags & ARM_FLAG_Z)) \
116 arm_instr_ ## n (cpu, ic); } \
117 void arm_instr_ ## n ## __le(struct cpu *cpu, \
118 struct arm_instr_call *ic) \
119 { if (((cpu->cd.arm.flags & ARM_FLAG_N)?1:0) != \
120 ((cpu->cd.arm.flags & ARM_FLAG_V)?1:0) || \
121 (cpu->cd.arm.flags & ARM_FLAG_Z)) \
122 arm_instr_ ## n (cpu, ic); } \
123 void (*arm_cond_instr_ ## n [16])(struct cpu *, \
124 struct arm_instr_call *) = { \
125 arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
126 arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
127 arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
128 arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
129 arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
130 arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
131 arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
132 arm_instr_ ## n , arm_instr_nop };
133
134 #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
135
136
137 /* This is for marking a physical page as containing combined instructions: */
138 #define combined (cpu->cd.arm.cur_physpage->flags |= ARM_COMBINATIONS)
139
140
141 void arm_translate_instruction(struct cpu *cpu, struct arm_instr_call *ic);
142
143
144 /*
145 * nothing: Do nothing.
146 *
147 * The difference between this function and the "nop" instruction is that
148 * this function does not increase the program counter or the number of
149 * translated instructions. It is used to "get out" of running in translated
150 * mode.
151 */
152 X(nothing)
153 {
154 cpu->cd.arm.running_translated = 0;
155 cpu->cd.arm.n_translated_instrs --;
156 cpu->cd.arm.next_ic --;
157 }
158
159
160 static struct arm_instr_call nothing_call = { instr(nothing), {0,0,0} };
161
162
163 /*****************************************************************************/
164
165
166 /*
167 * nop: Do nothing.
168 */
169 X(nop)
170 {
171 }
172
173
174 /*
175 * b: Branch (to a different translated page)
176 *
177 * arg[0] = relative offset
178 */
179 X(b)
180 {
181 int low_pc;
182 uint32_t old_pc;
183
184 /* fatal("b: arg[0] = 0x%08x, pc=0x%08x\n", ic->arg[0], cpu->pc); */
185
186 /* Calculate new PC from this instruction + arg[0] */
187 low_pc = ((size_t)ic - (size_t)
188 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
189 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
190 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
191 old_pc = cpu->cd.arm.r[ARM_PC];
192 /* fatal("b: 3: old_pc=0x%08x\n", old_pc); */
193 cpu->cd.arm.r[ARM_PC] += (int32_t)ic->arg[0];
194 cpu->pc = cpu->cd.arm.r[ARM_PC];
195 /* fatal("b: 2: pc=0x%08x\n", cpu->pc); */
196
197 fatal("b: different page! TODO\n");
198 exit(1);
199 }
200 Y(b)
201
202
203 /*
204 * b_samepage: Branch (to within the same translated page)
205 *
206 * arg[0] = pointer to new arm_instr_call
207 */
208 X(b_samepage)
209 {
210 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
211 }
212 Y(b_samepage)
213
214
215 /*
216 * bl: Branch and Link (to a different translated page)
217 *
218 * arg[0] = relative address
219 *
220 * TODO: Implement this.
221 * TODO: How about function call trace?
222 */
223 X(bl)
224 {
225 fatal("bl different page: TODO\n");
226 exit(1);
227 }
228 Y(bl)
229
230
231 /*
232 * bl_samepage: A branch + link within the same page
233 *
234 * arg[0] = pointer to new arm_instr_call
235 *
236 * TODO: How about function call trace?
237 */
238 X(bl_samepage)
239 {
240 uint32_t lr, low_pc;
241
242 /* Figure out what the return (link) address will be: */
243 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
244 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
245 lr = cpu->cd.arm.r[ARM_PC];
246 lr &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
247 lr += (low_pc << 2);
248
249 /* Link: */
250 cpu->cd.arm.r[ARM_LR] = lr;
251
252 /* Branch: */
253 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
254 }
255 Y(bl_samepage)
256
257
258 /*
259 * mov: Set a 32-bit register to a 32-bit value.
260 *
261 * arg[0] = pointer to uint32_t in host memory
262 * arg[1] = 32-bit value
263 */
264 X(mov)
265 {
266 *((uint32_t *)ic->arg[0]) = ic->arg[1];
267 }
268 Y(mov)
269
270
271 /*
272 * clear: Set a 32-bit register to 0. (A "mov" to fixed value zero.)
273 *
274 * arg[0] = pointer to uint32_t in host memory
275 */
276 X(clear)
277 {
278 *((uint32_t *)ic->arg[0]) = 0;
279 }
280 Y(clear)
281
282
283 /*
284 * load_byte_imm: Load an 8-bit byte from emulated memory and store it in
285 * a 32-bit word in host memory.
286 *
287 * arg[0] = pointer to uint32_t in host memory of base address
288 * arg[1] = 32-bit offset
289 * arg[2] = pointer to uint32_t in host memory where to store the value
290 */
291 X(load_byte_imm)
292 {
293 unsigned char data[1];
294 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
295 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
296 MEM_READ, CACHE_DATA)) {
297 fatal("load failed: TODO\n");
298 exit(1);
299 }
300 *((uint32_t *)ic->arg[2]) = data[0];
301 }
302 Y(load_byte_imm)
303
304
305 /*
306 * load_byte_w_imm:
307 * Load an 8-bit byte from emulated memory and store it in
308 * a 32-bit word in host memory, with address writeback.
309 *
310 * arg[0] = pointer to uint32_t in host memory of base address
311 * arg[1] = 32-bit offset
312 * arg[2] = pointer to uint32_t in host memory where to store the value
313 */
314 X(load_byte_w_imm)
315 {
316 unsigned char data[1];
317 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
318 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
319 MEM_READ, CACHE_DATA)) {
320 fatal("load failed: TODO\n");
321 exit(1);
322 }
323 *((uint32_t *)ic->arg[2]) = data[0];
324 *((uint32_t *)ic->arg[0]) = addr;
325 }
326 Y(load_byte_w_imm)
327
328
329 /*
330 * load_byte_wpost_imm:
331 * Load an 8-bit byte from emulated memory and store it in
332 * a 32-bit word in host memory, with address writeback AFTER the load.
333 *
334 * arg[0] = pointer to uint32_t in host memory of base address
335 * arg[1] = 32-bit offset
336 * arg[2] = pointer to uint32_t in host memory where to store the value
337 */
338 X(load_byte_wpost_imm)
339 {
340 unsigned char data[1];
341 uint32_t addr = *((uint32_t *)ic->arg[0]);
342 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
343 MEM_READ, CACHE_DATA)) {
344 fatal("load failed: TODO\n");
345 exit(1);
346 }
347 *((uint32_t *)ic->arg[2]) = data[0];
348 *((uint32_t *)ic->arg[0]) = addr + ic->arg[1];
349 }
350 Y(load_byte_wpost_imm)
351
352
353 /*
354 * store_byte_imm: Load a word from a 32-bit word in host memory, and store
355 * the lowest 8 bits of that word at an emulated memory
356 * address.
357 *
358 * arg[0] = pointer to uint32_t in host memory of base address
359 * arg[1] = 32-bit offset
360 * arg[2] = pointer to uint32_t in host memory where to load the value from
361 */
362 X(store_byte_imm)
363 {
364 unsigned char data[1];
365 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
366 data[0] = *((uint32_t *)ic->arg[2]);
367 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
368 MEM_WRITE, CACHE_DATA)) {
369 fatal("store failed: TODO\n");
370 exit(1);
371 }
372 }
373 Y(store_byte_imm)
374
375
376 /*
377 * store_byte_wpost_imm:
378 * Load a word from a 32-bit word in host memory, and store
379 * the lowest 8 bits of that word at an emulated memory address.
380 * Then add the immediate offset to the address, and write back
381 * to the first word.
382 *
383 * arg[0] = pointer to uint32_t in host memory of base address
384 * arg[1] = 32-bit offset
385 * arg[2] = pointer to uint32_t in host memory where to load the value from
386 */
387 X(store_byte_wpost_imm)
388 {
389 unsigned char data[1];
390 uint32_t addr = *((uint32_t *)ic->arg[0]);
391 data[0] = *((uint32_t *)ic->arg[2]);
392 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
393 MEM_WRITE, CACHE_DATA)) {
394 fatal("store failed: TODO\n");
395 exit(1);
396 }
397 *((uint32_t *)ic->arg[0]) = addr + ic->arg[1];
398 }
399 Y(store_byte_wpost_imm)
400
401
402 /*
403 * load_word_imm:
404 * Load a 32-bit word from emulated memory and store it in
405 * a 32-bit word in host memory.
406 *
407 * arg[0] = pointer to uint32_t in host memory of base address
408 * arg[1] = 32-bit offset
409 * arg[2] = pointer to uint32_t in host memory where to store the value
410 */
411 X(load_word_imm)
412 {
413 unsigned char data[sizeof(uint32_t)];
414 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
415 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
416 MEM_READ, CACHE_DATA)) {
417 fatal("load word failed: TODO\n");
418 exit(1);
419 }
420 /* TODO: Big endian */
421 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
422 (data[2] << 16) + (data[3] << 24);
423 }
424 Y(load_word_imm)
425
426
427 /*
428 * load_word_w_imm:
429 * Load a 32-bit word from emulated memory and store it in
430 * a 32-bit word in host memory, with address writeback.
431 *
432 * arg[0] = pointer to uint32_t in host memory of base address
433 * arg[1] = 32-bit offset
434 * arg[2] = pointer to uint32_t in host memory where to store the value
435 */
436 X(load_word_w_imm)
437 {
438 unsigned char data[sizeof(uint32_t)];
439 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
440 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
441 MEM_READ, CACHE_DATA)) {
442 fatal("load word failed: TODO\n");
443 exit(1);
444 }
445 /* TODO: Big endian */
446 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
447 (data[2] << 16) + (data[3] << 24);
448 *((uint32_t *)ic->arg[0]) = addr;
449 }
450 Y(load_word_w_imm)
451
452
453 /*
454 * store_word_imm: Load a 32-bit word from host memory and store it
455 * in emulated memory.
456 *
457 * arg[0] = pointer to uint32_t in host memory of base address
458 * arg[1] = 32-bit offset
459 * arg[2] = pointer to uint32_t in host memory where to load the value from.
460 */
461 X(store_word_imm)
462 {
463 unsigned char data[sizeof(uint32_t)];
464 uint32_t addr = *((uint32_t *)ic->arg[0]) + ic->arg[1];
465 uint32_t x = *((uint32_t *)ic->arg[2]);
466 /* TODO: Big endian */
467 data[0] = x; data[1] = x >> 8; data[2] = x >> 16; data[3] = x >> 24;
468 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
469 MEM_WRITE, CACHE_DATA)) {
470 fatal("store word failed: TODO\n");
471 exit(1);
472 }
473 }
474 Y(store_word_imm)
475
476
477 /*
478 * load_byte_imm_pcrel:
479 * Like load_byte_imm, but the source address is the PC register.
480 * Before loading, we have to synchronize the PC register and add 8.
481 *
482 * arg[0] = pointer to ARM_PC (not used here)
483 * arg[1] = 32-bit offset
484 * arg[2] = pointer to uint32_t in host memory where to store the value
485 */
486 X(load_byte_imm_pcrel)
487 {
488 uint32_t low_pc, addr;
489 unsigned char data[1];
490
491 low_pc = ((size_t)ic - (size_t)
492 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
493 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
494 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
495
496 addr = cpu->cd.arm.r[ARM_PC] + 8 + ic->arg[1];
497 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
498 MEM_READ, CACHE_DATA)) {
499 fatal("load failed: TODO\n");
500 exit(1);
501 }
502 *((uint32_t *)ic->arg[2]) = data[0];
503 }
504 Y(load_byte_imm_pcrel)
505
506
507 /*
508 * load_word_imm_pcrel:
509 * Like load_word_imm, but the source address is the PC register.
510 * Before loading, we have to synchronize the PC register and add 8.
511 *
512 * arg[0] = pointer to ARM_PC (not used here)
513 * arg[1] = 32-bit offset
514 * arg[2] = pointer to uint32_t in host memory where to store the value
515 */
516 X(load_word_imm_pcrel)
517 {
518 uint32_t low_pc, addr;
519 unsigned char data[sizeof(uint32_t)];
520
521 low_pc = ((size_t)ic - (size_t)
522 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
523 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
524 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
525
526 addr = cpu->cd.arm.r[ARM_PC] + 8 + ic->arg[1];
527 if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data),
528 MEM_READ, CACHE_DATA)) {
529 fatal("load failed: TODO\n");
530 exit(1);
531 }
532 /* TODO: Big endian */
533 *((uint32_t *)ic->arg[2]) = data[0] + (data[1] << 8) +
534 (data[2] << 16) + (data[3] << 24);
535 }
536 Y(load_word_imm_pcrel)
537
538
539 /*
540 * cmps: Compare a 32-bit register to a 32-bit value. (Subtraction.)
541 *
542 * arg[0] = pointer to uint32_t in host memory
543 * arg[1] = 32-bit value
544 */
545 X(cmps)
546 {
547 uint32_t a, b, c;
548 int v, n;
549 a = *((uint32_t *)ic->arg[0]);
550 b = ic->arg[1];
551
552 c = a - b;
553 cpu->cd.arm.flags &=
554 ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);
555 if (c == 0)
556 cpu->cd.arm.flags |= ARM_FLAG_Z;
557 if ((int32_t)c < 0) {
558 cpu->cd.arm.flags |= ARM_FLAG_N;
559 n = 1;
560 } else
561 n = 0;
562 v = !n;
563 if ((int32_t)a >= (int32_t)b)
564 v = n;
565 if (v)
566 cpu->cd.arm.flags |= ARM_FLAG_V;
567 if (a > b)
568 cpu->cd.arm.flags |= ARM_FLAG_C;
569 }
570 Y(cmps)
571
572
573 /*
574 * sub: Subtract an immediate value from a 32-bit word, and store the
575 * result in a 32-bit word.
576 *
577 * arg[0] = pointer to destination uint32_t in host memory
578 * arg[1] = pointer to source uint32_t in host memory
579 * arg[2] = 32-bit value
580 */
581 X(sub)
582 {
583 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]) - ic->arg[2];
584 }
585 Y(sub)
586 X(sub_self)
587 {
588 *((uint32_t *)ic->arg[0]) -= ic->arg[2];
589 }
590 Y(sub_self)
591
592
593 /*
594 * add: Add an immediate value to a 32-bit word, and store the
595 * result in a 32-bit word.
596 *
597 * arg[0] = pointer to destination uint32_t in host memory
598 * arg[1] = pointer to source uint32_t in host memory
599 * arg[2] = 32-bit value
600 */
601 X(add)
602 {
603 *((uint32_t *)ic->arg[0]) = *((uint32_t *)ic->arg[1]) + ic->arg[2];
604 }
605 Y(add)
606 X(add_self)
607 {
608 *((uint32_t *)ic->arg[0]) += ic->arg[2];
609 }
610 Y(add_self)
611
612
613 /*****************************************************************************/
614
615
616 /*
617 * mov_2: Double "mov".
618 *
619 * The current and the next arm_instr_call are treated as "mov"s.
620 */
621 X(mov_2)
622 {
623 *((uint32_t *)ic[0].arg[0]) = ic[0].arg[1];
624 *((uint32_t *)ic[1].arg[0]) = ic[1].arg[1];
625 cpu->cd.arm.next_ic ++;
626 cpu->cd.arm.n_translated_instrs ++;
627 }
628
629
630 /*****************************************************************************/
631
632
633 X(to_be_translated)
634 {
635 /* Translate the instruction... */
636 arm_translate_instruction(cpu, ic);
637
638 /* ... and execute it: */
639 ic->f(cpu, ic);
640 }
641
642
643 X(end_of_page)
644 {
645 printf("end_of_page()! pc=0x%08x\n", cpu->cd.arm.r[ARM_PC]);
646
647 /* Update the PC: Offset 0, but then go to next page: */
648 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
649 cpu->cd.arm.r[ARM_PC] += (IC_ENTRIES_PER_PAGE << 2);
650 cpu->pc = cpu->cd.arm.r[ARM_PC];
651
652 /* Find the new (physical) page: */
653 /* TODO */
654
655 printf("TODO: end_of_page()! new pc=0x%08x\n", cpu->cd.arm.r[ARM_PC]);
656 exit(1);
657 }
658
659
660 /*****************************************************************************/
661
662
663 /*
664 * arm_combine_instructions():
665 *
666 * Combine two or more instructions, if possible, into a single function call.
667 */
668 void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic)
669 {
670 int n_back;
671 n_back = (cpu->pc >> 2) & (IC_ENTRIES_PER_PAGE-1);
672
673 if (n_back >= 1) {
674 /* Double "mov": */
675 if (ic[-1].f == instr(mov) || ic[-1].f == instr(clear)) {
676 if (ic[-1].f == instr(mov) && ic[0].f == instr(mov)) {
677 ic[-1].f = instr(mov_2);
678 combined;
679 }
680 if (ic[-1].f == instr(clear) && ic[0].f == instr(mov)) {
681 ic[-1].f = instr(mov_2);
682 ic[-1].arg[1] = 0;
683 combined;
684 }
685 if (ic[-1].f == instr(mov) && ic[0].f == instr(clear)) {
686 ic[-1].f = instr(mov_2);
687 ic[0].arg[1] = 0;
688 combined;
689 }
690 if (ic[-1].f == instr(clear) && ic[0].f==instr(clear)) {
691 ic[-1].f = instr(mov_2);
692 ic[-1].arg[1] = 0;
693 ic[0].arg[1] = 0;
694 combined;
695 }
696 }
697 }
698 }
699
700
701 /*
702 * arm_translate_instruction():
703 *
704 * Translate an instruction word into an arm_instr_call.
705 */
706 void arm_translate_instruction(struct cpu *cpu, struct arm_instr_call *ic)
707 {
708 uint32_t addr, low_pc, iword, imm;
709 unsigned char ib[4];
710 int condition_code, main_opcode, secondary_opcode, s_bit, r16, r12, r8;
711 int p_bit, u_bit, b_bit, w_bit, l_bit;
712 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
713
714 /* Make sure that PC is in synch: */
715 low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
716 / sizeof(struct arm_instr_call);
717 cpu->cd.arm.r[ARM_PC] &= ~((IC_ENTRIES_PER_PAGE-1) << 2);
718 cpu->cd.arm.r[ARM_PC] += (low_pc << 2);
719 cpu->pc = cpu->cd.arm.r[ARM_PC];
720
721 /* Read the instruction word from memory: */
722 addr = cpu->pc & ~0x3;
723
724 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
725 sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
726 fatal("arm_translate_instruction(): read failed: TODO\n");
727 goto bad;
728 }
729
730 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
731 iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
732 else
733 iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
734
735 /* fatal("{ ARM translating pc=0x%08x iword=0x%08x }\n",
736 addr, iword); */
737
738 /* The idea of taking bits 27..24 was found here:
739 http://armphetamine.sourceforge.net/oldinfo.html */
740 condition_code = iword >> 28;
741 main_opcode = (iword >> 24) & 15;
742 secondary_opcode = (iword >> 21) & 15;
743 u_bit = (iword >> 23) & 1;
744 b_bit = (iword >> 22) & 1;
745 w_bit = (iword >> 21) & 1;
746 s_bit = l_bit = (iword >> 20) & 1;
747 r16 = (iword >> 16) & 15;
748 r12 = (iword >> 12) & 15;
749 r8 = (iword >> 8) & 15;
750
751 if (condition_code == 0xf) {
752 fatal("TODO: ARM condition code 0x%x\n",
753 condition_code);
754 goto bad;
755 }
756
757
758 /*
759 * Translate the instruction:
760 */
761
762 switch (main_opcode) {
763
764 case 0x0:
765 case 0x1:
766 case 0x2:
767 case 0x3:
768 if ((main_opcode & 2) == 0) {
769 fatal("REGISTER FORM! TODO\n");
770 goto bad;
771 }
772 imm = iword & 0xff;
773 r8 <<= 1;
774 while (r8-- > 0)
775 imm = (imm >> 1) | ((imm & 1) << 31);
776 switch (secondary_opcode) {
777 case 0x2: /* SUB */
778 case 0x4: /* ADD */
779 if (s_bit) {
780 fatal("sub s_bit: TODO\n");
781 goto bad;
782 }
783 switch (secondary_opcode) {
784 case 0x2:
785 if (r12 == r16)
786 ic->f = cond_instr(sub_self);
787 else
788 ic->f = cond_instr(sub);
789 break;
790 case 0x4:
791 if (r12 == r16)
792 ic->f = cond_instr(add_self);
793 else
794 ic->f = cond_instr(add);
795 break;
796 }
797 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r12]);
798 ic->arg[1] = (size_t)(&cpu->cd.arm.r[r16]);
799 ic->arg[2] = imm;
800 break;
801 case 0xa: /* CMP */
802 if (!s_bit) {
803 fatal("cmp !s_bit: TODO\n");
804 goto bad;
805 }
806 ic->f = cond_instr(cmps);
807 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
808 ic->arg[1] = imm;
809 break;
810 case 0xd: /* MOV */
811 if (s_bit) {
812 fatal("mov s_bit: TODO\n");
813 goto bad;
814 }
815 if (r12 == ARM_PC) {
816 fatal("TODO: mov used as branch\n");
817 goto bad;
818 } else {
819 ic->f = cond_instr(mov);
820 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r12]);
821 ic->arg[1] = imm;
822 if (imm == 0)
823 ic->f = cond_instr(clear);
824 }
825 break;
826 default:goto bad;
827 }
828 break;
829
830 case 0x4: /* Load and store... */
831 case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
832 case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
833 case 0x7:
834 p_bit = main_opcode & 1;
835 if (main_opcode < 6) {
836 /* Immediate: */
837 imm = iword & 0xfff;
838 if (!u_bit)
839 imm = (int32_t)0-imm;
840 ic->arg[0] = (size_t)(&cpu->cd.arm.r[r16]);
841 ic->arg[1] = (size_t)(imm);
842 ic->arg[2] = (size_t)(&cpu->cd.arm.r[r12]);
843 }
844 if (main_opcode == 4 && b_bit) {
845 /* Post-index, immediate: */
846 if (w_bit) {
847 fatal("load/store: T-bit\n");
848 goto bad;
849 }
850 if (r16 == ARM_PC) {
851 fatal("load/store writeback PC: error\n");
852 goto bad;
853 }
854 if (l_bit)
855 ic->f = cond_instr(load_byte_wpost_imm);
856 else
857 ic->f = cond_instr(store_byte_wpost_imm);
858 } else if (main_opcode == 5) {
859 /* Pre-index, immediate: */
860 /* ldr(b) Rd,[Rn,#imm] */
861 if (l_bit) {
862 if (r12 == ARM_PC)
863 fatal("WARNING: ldr to pc register?\n");
864 if (w_bit) {
865 ic->f = b_bit?
866 cond_instr(load_byte_w_imm) :
867 cond_instr(load_word_w_imm);
868 } else {
869 ic->f = b_bit?
870 cond_instr(load_byte_imm) :
871 cond_instr(load_word_imm);
872 }
873 if (r16 == ARM_PC) {
874 if (w_bit) {
875 fatal("w bit load etc\n");
876 goto bad;
877 }
878 ic->f = b_bit?
879 cond_instr(load_byte_imm_pcrel) :
880 cond_instr(load_word_imm_pcrel);
881 }
882 } else {
883 if (w_bit) {
884 fatal("w bit store etc\n");
885 goto bad;
886 }
887 if (r12 == ARM_PC) {
888 fatal("TODO: store pc\n");
889 goto bad;
890 }
891 ic->f = b_bit?
892 cond_instr(store_byte_imm) :
893 cond_instr(store_word_imm);
894 if (r16 == ARM_PC) {
895 fatal("TODO: store pc rel\n");
896 goto bad;
897 }
898 }
899 } else {
900 fatal("Specific Load/store TODO\n");
901 goto bad;
902 }
903 break;
904
905 case 0xa: /* B: branch */
906 case 0xb: /* BL: branch+link */
907 if (main_opcode == 0x0a) {
908 ic->f = cond_instr(b);
909 samepage_function = cond_instr(b_samepage);
910 } else {
911 ic->f = cond_instr(bl);
912 samepage_function = cond_instr(bl_samepage);
913 }
914
915 ic->arg[0] = (iword & 0x00ffffff) << 2;
916 /* Sign-extend: */
917 if (ic->arg[0] & 0x02000000)
918 ic->arg[0] |= 0xfc000000;
919 /* Branches are calculated as PC + 8 + offset: */
920 ic->arg[0] = (int32_t)(ic->arg[0] + 8);
921
922 /* Special case: branch within the same page: */
923 {
924 uint32_t mask_within_page =
925 ((IC_ENTRIES_PER_PAGE-1) << 2) | 3;
926 uint32_t old_pc = addr;
927 uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
928 if ((old_pc & ~mask_within_page) ==
929 (new_pc & ~mask_within_page)) {
930 ic->f = samepage_function;
931 ic->arg[0] = (size_t) (
932 cpu->cd.arm.cur_ic_page +
933 ((new_pc & mask_within_page) >> 2));
934 }
935 }
936 break;
937
938 default:goto bad;
939 }
940
941
942 /*
943 * If we end up here, then an instruction was translated. Now it is
944 * time to check for combinations of instructions that can be
945 * converted into a single function call.
946 */
947
948 /* Single-stepping doesn't work with combinations: */
949 if (single_step || cpu->machine->instruction_trace)
950 return;
951
952 arm_combine_instructions(cpu, ic);
953
954 return;
955
956
957 bad: /*
958 * Nothing was translated. (Unimplemented or illegal instruction.)
959 */
960 quiet_mode = 0;
961 fatal("arm_translate_instruction(): TODO: "
962 "unimplemented ARM instruction:\n");
963 arm_cpu_disassemble_instr(cpu, ib, 1, 0, 0);
964 cpu->running = 0;
965 cpu->dead = 1;
966 cpu->cd.arm.running_translated = 0;
967 *ic = nothing_call;
968 }
969

  ViewVC Help
Powered by ViewVC 1.1.26