/[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

Annotation of /trunk/src/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (12 years, 11 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 dpavlin 10 /*
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