1 |
/* |
2 |
* Copyright (C) 2007 Anders Gavare. All rights reserved. |
3 |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
6 |
* |
7 |
* 1. Redistributions of source code must retain the above copyright |
8 |
* notice, this list of conditions and the following disclaimer. |
9 |
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
* notice, this list of conditions and the following disclaimer in the |
11 |
* documentation and/or other materials provided with the distribution. |
12 |
* 3. The name of the author may not be used to endorse or promote products |
13 |
* derived from this software without specific prior written permission. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* SUCH DAMAGE. |
26 |
* |
27 |
* |
28 |
* $Id: cpu_m32r_instr.c,v 1.1 2007/07/20 09:03:33 debug Exp $ |
29 |
* |
30 |
* M32R 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 |
#define SYNCH_PC { \ |
40 |
int low_pc = ((size_t)ic - (size_t)cpu->cd.m32r.cur_ic_page) \ |
41 |
/ sizeof(struct m32r_instr_call); \ |
42 |
cpu->pc &= ~((M32R_IC_ENTRIES_PER_PAGE-1) \ |
43 |
<< M32R_INSTR_ALIGNMENT_SHIFT); \ |
44 |
cpu->pc += (low_pc << M32R_INSTR_ALIGNMENT_SHIFT); \ |
45 |
} |
46 |
|
47 |
|
48 |
/* |
49 |
* nop: Do nothing. |
50 |
*/ |
51 |
X(nop) |
52 |
{ |
53 |
} |
54 |
|
55 |
|
56 |
/*****************************************************************************/ |
57 |
|
58 |
|
59 |
X(end_of_page) |
60 |
{ |
61 |
/* Update the PC: (offset 0, but on the next page) */ |
62 |
cpu->pc &= ~((M32R_IC_ENTRIES_PER_PAGE-1) << |
63 |
M32R_INSTR_ALIGNMENT_SHIFT); |
64 |
cpu->pc += (M32R_IC_ENTRIES_PER_PAGE << M32R_INSTR_ALIGNMENT_SHIFT); |
65 |
|
66 |
/* end_of_page doesn't count as an executed instruction: */ |
67 |
cpu->n_translated_instrs --; |
68 |
|
69 |
/* |
70 |
* Find the new physpage and update translation pointers. |
71 |
* |
72 |
* Note: This may cause an exception, if e.g. the new page is |
73 |
* not accessible. |
74 |
*/ |
75 |
quick_pc_to_pointers(cpu); |
76 |
|
77 |
/* Simple jump to the next page (if we are lucky): */ |
78 |
if (cpu->delay_slot == NOT_DELAYED) |
79 |
return; |
80 |
|
81 |
/* |
82 |
* If we were in a delay slot, and we got an exception while doing |
83 |
* quick_pc_to_pointers, then return. The function which called |
84 |
* end_of_page should handle this case. |
85 |
*/ |
86 |
if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT) |
87 |
return; |
88 |
|
89 |
/* |
90 |
* Tricky situation; the delay slot is on the next virtual page. |
91 |
* Calling to_be_translated will translate one instruction manually, |
92 |
* execute it, and then discard it. |
93 |
*/ |
94 |
/* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */ |
95 |
|
96 |
instr(to_be_translated)(cpu, cpu->cd.m32r.next_ic); |
97 |
|
98 |
/* The instruction in the delay slot has now executed. */ |
99 |
/* fatal("[ end_of_page: back from executing the delay slot, %i ]\n", |
100 |
cpu->delay_slot); */ |
101 |
|
102 |
/* Find the physpage etc of the instruction in the delay slot |
103 |
(or, if there was an exception, the exception handler): */ |
104 |
quick_pc_to_pointers(cpu); |
105 |
} |
106 |
|
107 |
|
108 |
/*****************************************************************************/ |
109 |
|
110 |
|
111 |
/* |
112 |
* m32r_instr_to_be_translated(): |
113 |
* |
114 |
* Translate an instruction word into a m32r_instr_call. ic is filled in with |
115 |
* valid data for the translated instruction, or a "nothing" instruction if |
116 |
* there was a translation failure. The newly translated instruction is then |
117 |
* executed. |
118 |
*/ |
119 |
X(to_be_translated) |
120 |
{ |
121 |
uint32_t addr, low_pc, iword; |
122 |
unsigned char *page; |
123 |
unsigned char ib[4]; |
124 |
int in_crosspage_delayslot = 0; |
125 |
/* void (*samepage_function)(struct cpu *, struct m32r_instr_call *) = |
126 |
NULL; */ |
127 |
|
128 |
/* Figure out the (virtual) address of the instruction: */ |
129 |
low_pc = ((size_t)ic - (size_t)cpu->cd.m32r.cur_ic_page) |
130 |
/ sizeof(struct m32r_instr_call); |
131 |
|
132 |
/* Special case for branch with delayslot on the next page: */ |
133 |
if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) { |
134 |
/* fatal("[ delay-slot translation across page " |
135 |
"boundary ]\n"); */ |
136 |
in_crosspage_delayslot = 1; |
137 |
} |
138 |
|
139 |
addr = cpu->pc & ~((M32R_IC_ENTRIES_PER_PAGE-1) |
140 |
<< M32R_INSTR_ALIGNMENT_SHIFT); |
141 |
addr += (low_pc << M32R_INSTR_ALIGNMENT_SHIFT); |
142 |
cpu->pc = (MODE_int_t)addr; |
143 |
addr &= ~((1 << M32R_INSTR_ALIGNMENT_SHIFT) - 1); |
144 |
|
145 |
/* Read the instruction word from memory: */ |
146 |
page = cpu->cd.m32r.host_load[(uint32_t)addr >> 12]; |
147 |
|
148 |
if (page != NULL) { |
149 |
/* fatal("TRANSLATION HIT!\n"); */ |
150 |
memcpy(ib, page + (addr & 0xffc), sizeof(ib)); |
151 |
} else { |
152 |
/* fatal("TRANSLATION MISS!\n"); */ |
153 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, |
154 |
sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { |
155 |
fatal("to_be_translated(): read failed: TODO\n"); |
156 |
goto bad; |
157 |
} |
158 |
} |
159 |
|
160 |
iword = *((uint32_t *)&ib[0]); |
161 |
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) |
162 |
iword = LE32_TO_HOST(iword); |
163 |
else |
164 |
iword = BE32_TO_HOST(iword); |
165 |
|
166 |
|
167 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
168 |
#include "cpu_dyntrans.c" |
169 |
#undef DYNTRANS_TO_BE_TRANSLATED_HEAD |
170 |
|
171 |
|
172 |
/* |
173 |
* Translate the instruction: |
174 |
*/ |
175 |
|
176 |
switch (iword) { |
177 |
|
178 |
default:goto bad; |
179 |
} |
180 |
|
181 |
|
182 |
#define DYNTRANS_TO_BE_TRANSLATED_TAIL |
183 |
#include "cpu_dyntrans.c" |
184 |
#undef DYNTRANS_TO_BE_TRANSLATED_TAIL |
185 |
} |
186 |
|