/[gxemul]/upstream/0.3.6/src/cpus/cpu_arm_instr_dpi.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 /upstream/0.3.6/src/cpus/cpu_arm_instr_dpi.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 10215 byte(s)
0.3.6
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_dpi.c,v 1.9 2005/10/04 04:44:16 debug Exp $
29 *
30 *
31 * ARM Data Processing Instructions
32 * --------------------------------
33 *
34 * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form
35 * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form
36 *
37 * 4 bits to select which instruction, one of the following:
38 *
39 * 0000 and 1000 tst
40 * 0001 eor 1001 teq
41 * 0010 sub 1010 cmp
42 * 0011 rsb 1011 cmn
43 * 0100 add 1100 orr
44 * 0101 adc 1101 mov
45 * 0110 sbc 1110 bic
46 * 0111 rsc 1111 mvn
47 *
48 * 1 bit to select Status flag update.
49 *
50 * 1 bit to select Register form or Immediate form.
51 *
52 * 1 bit to select if the PC register is used.
53 *
54 * Each function must also (as always) be repeated for each possible ARM
55 * condition code (15 in total). Total: 1920 functions.
56 *
57 * NOTE: This does not include any special common cases, which might be
58 * nice to have. Examples: comparing against zero, moving common
59 * constants.
60 *
61 * See src/tools/generate_arm_dpi.c for more details.
62 */
63
64
65 /*
66 * arg[0] = pointer to rn
67 * arg[1] = int32_t immediate value OR copy of the instruction word (regform)
68 * arg[2] = pointer to rd
69 */
70 void A__NAME(struct cpu *cpu, struct arm_instr_call *ic)
71 {
72 #ifdef A__S
73 uint32_t c32;
74 #endif
75 #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \
76 || defined(A__RSC) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB)
77 #ifdef A__S
78 uint64_t
79 #else
80 uint32_t
81 #endif
82 #else
83 uint32_t
84 #endif
85 c64,
86 #if !defined(A__MOV) && !defined(A__MVN)
87 a = reg(ic->arg[0]),
88 #endif
89 b =
90 #ifdef A__REG
91 R(cpu, ic, ic->arg[1],
92 #ifdef A__S
93 1
94 #else
95 0
96 #endif
97 );
98 #else
99 ic->arg[1];
100 #endif
101
102
103 #if defined(A__MOV) || defined(A__MVN) || defined(A__TST) || defined(A__TEQ) \
104 || defined(A__AND) || defined(A__BIC) || defined(A__EOR) || defined(A__ORR)
105 #if !defined(A__REG) && defined(A__S)
106 /*
107 * TODO: This is not 100% correct, but should work with "recommended"
108 * ARM code: Immediate values larger than 255 are encoded with
109 * rotation. If the S-bit is set, then the carry bit is set to the
110 * highest bit of the operand.
111 *
112 * TODO 2: Perhaps this check should be moved out from here, and into
113 * cpu_arm_instr.c. (More correct, and higher performance.)
114 */
115 if (b > 255) {
116 cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
117 if (b & 0x80000000)
118 cpu->cd.arm.cpsr |= ARM_FLAG_C;
119 }
120 #endif
121 #endif
122
123
124 #if !defined(A__MOV) && !defined(A__MVN)
125 #ifdef A__PC
126 if (ic->arg[0] == (size_t)&cpu->cd.arm.r[ARM_PC]) {
127 uint32_t low_pc;
128 low_pc = ((size_t)ic - (size_t)
129 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
130 a = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1)
131 << ARM_INSTR_ALIGNMENT_SHIFT);
132 a += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT) + 8;
133 }
134 #endif
135 #endif
136
137
138 #if defined(A__RSB) || defined(A__RSC)
139 { uint32_t tmp = a; a = b; b = tmp; }
140 #endif
141
142 /*
143 * Perform the operation:
144 */
145 #if defined(A__AND) || defined(A__TST)
146 c64 = a & b;
147 #endif
148 #if defined(A__EOR) || defined(A__TEQ)
149 c64 = a ^ b;
150 #endif
151 #if defined(A__SUB) || defined(A__CMP) || defined(A__RSB)
152 c64 = a - b;
153 #endif
154 #if defined(A__ADD) || defined(A__CMN)
155 c64 = a + b;
156 #endif
157 #if defined(A__ADC)
158 c64 = a + b + (cpu->cd.arm.cpsr & ARM_FLAG_C? 1 : 0);
159 #endif
160 #if defined(A__SBC) || defined(A__RSC)
161 c64 = a - b - (1 - (cpu->cd.arm.cpsr & ARM_FLAG_C? 1 : 0));
162 #endif
163 #if defined(A__ORR)
164 c64 = a | b;
165 #endif
166 #if defined(A__MOV)
167 c64 = b;
168 #endif
169 #if defined(A__BIC)
170 c64 = a & ~b;
171 #endif
172 #if defined(A__MVN)
173 c64 = ~b;
174 #endif
175
176
177 #if defined(A__CMP) || defined(A__CMN) || defined(A__TST) || defined(A__TEQ)
178 /* No write to rd for compare/test. */
179 #else
180 #ifdef A__PC
181 if (ic->arg[2] == (size_t)&cpu->cd.arm.r[ARM_PC]) {
182 #ifndef A__S
183 uint32_t old_pc = cpu->cd.arm.r[ARM_PC];
184 uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
185 << ARM_INSTR_ALIGNMENT_SHIFT) |
186 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
187 #endif
188 cpu->pc = reg(ic->arg[2]) = c64;
189 #ifdef A__S
190 /* Copy the right SPSR into CPSR: */
191 arm_save_register_bank(cpu);
192 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
193 case ARM_MODE_FIQ32:
194 cpu->cd.arm.cpsr = cpu->cd.arm.spsr_fiq; break;
195 case ARM_MODE_IRQ32:
196 cpu->cd.arm.cpsr = cpu->cd.arm.spsr_irq; break;
197 case ARM_MODE_SVC32:
198 cpu->cd.arm.cpsr = cpu->cd.arm.spsr_svc; break;
199 case ARM_MODE_ABT32:
200 cpu->cd.arm.cpsr = cpu->cd.arm.spsr_abt; break;
201 case ARM_MODE_UND32:
202 cpu->cd.arm.cpsr = cpu->cd.arm.spsr_und; break;
203 default:fatal("huh? weird mode in dpi s with pc\n");
204 exit(1);
205 }
206 arm_load_register_bank(cpu);
207 #else
208 if ((old_pc & ~mask_within_page) ==
209 (cpu->pc & ~mask_within_page)) {
210 cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
211 ((cpu->pc & mask_within_page) >>
212 ARM_INSTR_ALIGNMENT_SHIFT);
213 } else
214 #endif
215 arm_pc_to_pointers(cpu);
216 return;
217 } else
218 reg(ic->arg[2]) = c64;
219 #else
220 reg(ic->arg[2]) = c64;
221 #endif
222 #endif
223
224
225 /*
226 * Status flag update (if the S-bit is set):
227 */
228 #ifdef A__S
229 c32 = c64;
230 cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N
231 #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \
232 || defined(A__RSB) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB)
233 | ARM_FLAG_V | ARM_FLAG_C
234 #endif
235 );
236
237 #if defined(A__CMP) || defined(A__RSB) || defined(A__SUB)
238 if ((uint32_t)a >= (uint32_t)b)
239 cpu->cd.arm.cpsr |= ARM_FLAG_C;
240 #else
241 #if defined(A__ADC) || defined(A__ADD) || defined(A__CMN)
242 if (c32 != c64)
243 cpu->cd.arm.cpsr |= ARM_FLAG_C;
244 #else
245 #if defined(A__RSC) || defined(A__SBC)
246 {
247 uint32_t low_pc;
248 low_pc = ((size_t)ic - (size_t)
249 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
250 a = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1)
251 << ARM_INSTR_ALIGNMENT_SHIFT);
252 a += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT) + 8;
253 fatal("TODO: C flag: pc = 0x%08x\n", a);
254 exit(1);
255 }
256 #endif
257 #endif
258 #endif
259
260 if (c32 == 0)
261 cpu->cd.arm.cpsr |= ARM_FLAG_Z;
262
263 if ((int32_t)c32 < 0)
264 cpu->cd.arm.cpsr |= ARM_FLAG_N;
265
266 /* Calculate the Overflow bit: */
267 #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \
268 || defined(A__RSB) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB)
269 {
270 int v = 0;
271 #if defined(A__ADD) || defined(A__CMN)
272 if (((int32_t)a >= 0 && (int32_t)b >= 0 &&
273 (int32_t)c32 < 0) ||
274 ((int32_t)a < 0 && (int32_t)b < 0 &&
275 (int32_t)c32 >= 0))
276 v = 1;
277 #else
278 #if defined(A__SUB) || defined(A__RSB) || defined(A__CMP)
279 if (((int32_t)a >= 0 && (int32_t)b < 0 &&
280 (int32_t)c32 < 0) ||
281 ((int32_t)a < 0 && (int32_t)b >= 0 &&
282 (int32_t)c32 >= 0))
283 v = 1;
284 #else
285 fatal("NO\n");
286 exit(1);
287 #endif
288 #endif
289 if (v)
290 cpu->cd.arm.cpsr |= ARM_FLAG_V;
291 }
292 #endif
293 #endif /* A__S */
294 }
295
296
297 void A__NAME__eq(struct cpu *cpu, struct arm_instr_call *ic)
298 { if (cpu->cd.arm.cpsr & ARM_FLAG_Z) A__NAME(cpu, ic); }
299 void A__NAME__ne(struct cpu *cpu, struct arm_instr_call *ic)
300 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); }
301 void A__NAME__cs(struct cpu *cpu, struct arm_instr_call *ic)
302 { if (cpu->cd.arm.cpsr & ARM_FLAG_C) A__NAME(cpu, ic); }
303 void A__NAME__cc(struct cpu *cpu, struct arm_instr_call *ic)
304 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_C)) A__NAME(cpu, ic); }
305 void A__NAME__mi(struct cpu *cpu, struct arm_instr_call *ic)
306 { if (cpu->cd.arm.cpsr & ARM_FLAG_N) A__NAME(cpu, ic); }
307 void A__NAME__pl(struct cpu *cpu, struct arm_instr_call *ic)
308 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_N)) A__NAME(cpu, ic); }
309 void A__NAME__vs(struct cpu *cpu, struct arm_instr_call *ic)
310 { if (cpu->cd.arm.cpsr & ARM_FLAG_V) A__NAME(cpu, ic); }
311 void A__NAME__vc(struct cpu *cpu, struct arm_instr_call *ic)
312 { if (!(cpu->cd.arm.cpsr & ARM_FLAG_V)) A__NAME(cpu, ic); }
313
314 void A__NAME__hi(struct cpu *cpu, struct arm_instr_call *ic)
315 { if (cpu->cd.arm.cpsr & ARM_FLAG_C &&
316 !(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); }
317 void A__NAME__ls(struct cpu *cpu, struct arm_instr_call *ic)
318 { if (cpu->cd.arm.cpsr & ARM_FLAG_Z ||
319 !(cpu->cd.arm.cpsr & ARM_FLAG_C)) A__NAME(cpu, ic); }
320 void A__NAME__ge(struct cpu *cpu, struct arm_instr_call *ic)
321 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) ==
322 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) A__NAME(cpu, ic); }
323 void A__NAME__lt(struct cpu *cpu, struct arm_instr_call *ic)
324 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) !=
325 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) A__NAME(cpu, ic); }
326 void A__NAME__gt(struct cpu *cpu, struct arm_instr_call *ic)
327 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) ==
328 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) &&
329 !(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); }
330 void A__NAME__le(struct cpu *cpu, struct arm_instr_call *ic)
331 { if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) !=
332 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) ||
333 (cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); }
334

  ViewVC Help
Powered by ViewVC 1.1.26