armsupp.c revision 1.1 1 1.1 christos /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
2 1.1 christos Copyright (C) 1994 Advanced RISC Machines Ltd.
3 1.1 christos
4 1.1 christos This program is free software; you can redistribute it and/or modify
5 1.1 christos it under the terms of the GNU General Public License as published by
6 1.1 christos the Free Software Foundation; either version 3 of the License, or
7 1.1 christos (at your option) any later version.
8 1.1 christos
9 1.1 christos This program is distributed in the hope that it will be useful,
10 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
11 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 1.1 christos GNU General Public License for more details.
13 1.1 christos
14 1.1 christos You should have received a copy of the GNU General Public License
15 1.1 christos along with this program; if not, see <http://www.gnu.org/licenses/>. */
16 1.1 christos
17 1.1 christos #include "armdefs.h"
18 1.1 christos #include "armemu.h"
19 1.1 christos #include "ansidecl.h"
20 1.1 christos
21 1.1 christos /* Definitions for the support routines. */
22 1.1 christos
23 1.1 christos static ARMword ModeToBank (ARMword);
24 1.1 christos static void EnvokeList (ARMul_State *, unsigned long, unsigned long);
25 1.1 christos
26 1.1 christos struct EventNode
27 1.1 christos { /* An event list node. */
28 1.1 christos unsigned (*func) (ARMul_State *); /* The function to call. */
29 1.1 christos struct EventNode *next;
30 1.1 christos };
31 1.1 christos
32 1.1 christos /* This routine returns the value of a register from a mode. */
33 1.1 christos
34 1.1 christos ARMword
35 1.1 christos ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
36 1.1 christos {
37 1.1 christos mode &= MODEBITS;
38 1.1 christos if (mode != state->Mode)
39 1.1 christos return (state->RegBank[ModeToBank ((ARMword) mode)][reg]);
40 1.1 christos else
41 1.1 christos return (state->Reg[reg]);
42 1.1 christos }
43 1.1 christos
44 1.1 christos /* This routine sets the value of a register for a mode. */
45 1.1 christos
46 1.1 christos void
47 1.1 christos ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
48 1.1 christos {
49 1.1 christos mode &= MODEBITS;
50 1.1 christos if (mode != state->Mode)
51 1.1 christos state->RegBank[ModeToBank ((ARMword) mode)][reg] = value;
52 1.1 christos else
53 1.1 christos state->Reg[reg] = value;
54 1.1 christos }
55 1.1 christos
56 1.1 christos /* This routine returns the value of the PC, mode independently. */
57 1.1 christos
58 1.1 christos ARMword
59 1.1 christos ARMul_GetPC (ARMul_State * state)
60 1.1 christos {
61 1.1 christos if (state->Mode > SVC26MODE)
62 1.1 christos return state->Reg[15];
63 1.1 christos else
64 1.1 christos return R15PC;
65 1.1 christos }
66 1.1 christos
67 1.1 christos /* This routine returns the value of the PC, mode independently. */
68 1.1 christos
69 1.1 christos ARMword
70 1.1 christos ARMul_GetNextPC (ARMul_State * state)
71 1.1 christos {
72 1.1 christos if (state->Mode > SVC26MODE)
73 1.1 christos return state->Reg[15] + isize;
74 1.1 christos else
75 1.1 christos return (state->Reg[15] + isize) & R15PCBITS;
76 1.1 christos }
77 1.1 christos
78 1.1 christos /* This routine sets the value of the PC. */
79 1.1 christos
80 1.1 christos void
81 1.1 christos ARMul_SetPC (ARMul_State * state, ARMword value)
82 1.1 christos {
83 1.1 christos if (ARMul_MODE32BIT)
84 1.1 christos state->Reg[15] = value & PCBITS;
85 1.1 christos else
86 1.1 christos state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
87 1.1 christos FLUSHPIPE;
88 1.1 christos }
89 1.1 christos
90 1.1 christos /* This routine returns the value of register 15, mode independently. */
91 1.1 christos
92 1.1 christos ARMword
93 1.1 christos ARMul_GetR15 (ARMul_State * state)
94 1.1 christos {
95 1.1 christos if (state->Mode > SVC26MODE)
96 1.1 christos return (state->Reg[15]);
97 1.1 christos else
98 1.1 christos return (R15PC | ECC | ER15INT | EMODE);
99 1.1 christos }
100 1.1 christos
101 1.1 christos /* This routine sets the value of Register 15. */
102 1.1 christos
103 1.1 christos void
104 1.1 christos ARMul_SetR15 (ARMul_State * state, ARMword value)
105 1.1 christos {
106 1.1 christos if (ARMul_MODE32BIT)
107 1.1 christos state->Reg[15] = value & PCBITS;
108 1.1 christos else
109 1.1 christos {
110 1.1 christos state->Reg[15] = value;
111 1.1 christos ARMul_R15Altered (state);
112 1.1 christos }
113 1.1 christos FLUSHPIPE;
114 1.1 christos }
115 1.1 christos
116 1.1 christos /* This routine returns the value of the CPSR. */
117 1.1 christos
118 1.1 christos ARMword
119 1.1 christos ARMul_GetCPSR (ARMul_State * state)
120 1.1 christos {
121 1.1 christos return (CPSR | state->Cpsr);
122 1.1 christos }
123 1.1 christos
124 1.1 christos /* This routine sets the value of the CPSR. */
125 1.1 christos
126 1.1 christos void
127 1.1 christos ARMul_SetCPSR (ARMul_State * state, ARMword value)
128 1.1 christos {
129 1.1 christos state->Cpsr = value;
130 1.1 christos ARMul_CPSRAltered (state);
131 1.1 christos }
132 1.1 christos
133 1.1 christos /* This routine does all the nasty bits involved in a write to the CPSR,
134 1.1 christos including updating the register bank, given a MSR instruction. */
135 1.1 christos
136 1.1 christos void
137 1.1 christos ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
138 1.1 christos {
139 1.1 christos state->Cpsr = ARMul_GetCPSR (state);
140 1.1 christos
141 1.1 christos if (state->Mode != USER26MODE
142 1.1 christos && state->Mode != USER32MODE)
143 1.1 christos {
144 1.1 christos /* In user mode, only write flags. */
145 1.1 christos if (BIT (16))
146 1.1 christos SETPSR_C (state->Cpsr, rhs);
147 1.1 christos if (BIT (17))
148 1.1 christos SETPSR_X (state->Cpsr, rhs);
149 1.1 christos if (BIT (18))
150 1.1 christos SETPSR_S (state->Cpsr, rhs);
151 1.1 christos }
152 1.1 christos if (BIT (19))
153 1.1 christos SETPSR_F (state->Cpsr, rhs);
154 1.1 christos ARMul_CPSRAltered (state);
155 1.1 christos }
156 1.1 christos
157 1.1 christos /* Get an SPSR from the specified mode. */
158 1.1 christos
159 1.1 christos ARMword
160 1.1 christos ARMul_GetSPSR (ARMul_State * state, ARMword mode)
161 1.1 christos {
162 1.1 christos ARMword bank = ModeToBank (mode & MODEBITS);
163 1.1 christos
164 1.1 christos if (! BANK_CAN_ACCESS_SPSR (bank))
165 1.1 christos return ARMul_GetCPSR (state);
166 1.1 christos
167 1.1 christos return state->Spsr[bank];
168 1.1 christos }
169 1.1 christos
170 1.1 christos /* This routine does a write to an SPSR. */
171 1.1 christos
172 1.1 christos void
173 1.1 christos ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
174 1.1 christos {
175 1.1 christos ARMword bank = ModeToBank (mode & MODEBITS);
176 1.1 christos
177 1.1 christos if (BANK_CAN_ACCESS_SPSR (bank))
178 1.1 christos state->Spsr[bank] = value;
179 1.1 christos }
180 1.1 christos
181 1.1 christos /* This routine does a write to the current SPSR, given an MSR instruction. */
182 1.1 christos
183 1.1 christos void
184 1.1 christos ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
185 1.1 christos {
186 1.1 christos if (BANK_CAN_ACCESS_SPSR (state->Bank))
187 1.1 christos {
188 1.1 christos if (BIT (16))
189 1.1 christos SETPSR_C (state->Spsr[state->Bank], rhs);
190 1.1 christos if (BIT (17))
191 1.1 christos SETPSR_X (state->Spsr[state->Bank], rhs);
192 1.1 christos if (BIT (18))
193 1.1 christos SETPSR_S (state->Spsr[state->Bank], rhs);
194 1.1 christos if (BIT (19))
195 1.1 christos SETPSR_F (state->Spsr[state->Bank], rhs);
196 1.1 christos }
197 1.1 christos }
198 1.1 christos
199 1.1 christos /* This routine updates the state of the emulator after the Cpsr has been
200 1.1 christos changed. Both the processor flags and register bank are updated. */
201 1.1 christos
202 1.1 christos void
203 1.1 christos ARMul_CPSRAltered (ARMul_State * state)
204 1.1 christos {
205 1.1 christos ARMword oldmode;
206 1.1 christos
207 1.1 christos if (state->prog32Sig == LOW)
208 1.1 christos state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
209 1.1 christos
210 1.1 christos oldmode = state->Mode;
211 1.1 christos
212 1.1 christos if (state->Mode != (state->Cpsr & MODEBITS))
213 1.1 christos {
214 1.1 christos state->Mode =
215 1.1 christos ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
216 1.1 christos
217 1.1 christos state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
218 1.1 christos }
219 1.1 christos state->Cpsr &= ~MODEBITS;
220 1.1 christos
221 1.1 christos ASSIGNINT (state->Cpsr & INTBITS);
222 1.1 christos state->Cpsr &= ~INTBITS;
223 1.1 christos ASSIGNN ((state->Cpsr & NBIT) != 0);
224 1.1 christos state->Cpsr &= ~NBIT;
225 1.1 christos ASSIGNZ ((state->Cpsr & ZBIT) != 0);
226 1.1 christos state->Cpsr &= ~ZBIT;
227 1.1 christos ASSIGNC ((state->Cpsr & CBIT) != 0);
228 1.1 christos state->Cpsr &= ~CBIT;
229 1.1 christos ASSIGNV ((state->Cpsr & VBIT) != 0);
230 1.1 christos state->Cpsr &= ~VBIT;
231 1.1 christos ASSIGNS ((state->Cpsr & SBIT) != 0);
232 1.1 christos state->Cpsr &= ~SBIT;
233 1.1 christos #ifdef MODET
234 1.1 christos ASSIGNT ((state->Cpsr & TBIT) != 0);
235 1.1 christos state->Cpsr &= ~TBIT;
236 1.1 christos #endif
237 1.1 christos
238 1.1 christos if (oldmode > SVC26MODE)
239 1.1 christos {
240 1.1 christos if (state->Mode <= SVC26MODE)
241 1.1 christos {
242 1.1 christos state->Emulate = CHANGEMODE;
243 1.1 christos state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
244 1.1 christos }
245 1.1 christos }
246 1.1 christos else
247 1.1 christos {
248 1.1 christos if (state->Mode > SVC26MODE)
249 1.1 christos {
250 1.1 christos state->Emulate = CHANGEMODE;
251 1.1 christos state->Reg[15] = R15PC;
252 1.1 christos }
253 1.1 christos else
254 1.1 christos state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
255 1.1 christos }
256 1.1 christos }
257 1.1 christos
258 1.1 christos /* This routine updates the state of the emulator after register 15 has
259 1.1 christos been changed. Both the processor flags and register bank are updated.
260 1.1 christos This routine should only be called from a 26 bit mode. */
261 1.1 christos
262 1.1 christos void
263 1.1 christos ARMul_R15Altered (ARMul_State * state)
264 1.1 christos {
265 1.1 christos if (state->Mode != R15MODE)
266 1.1 christos {
267 1.1 christos state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
268 1.1 christos state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
269 1.1 christos }
270 1.1 christos
271 1.1 christos if (state->Mode > SVC26MODE)
272 1.1 christos state->Emulate = CHANGEMODE;
273 1.1 christos
274 1.1 christos ASSIGNR15INT (R15INT);
275 1.1 christos
276 1.1 christos ASSIGNN ((state->Reg[15] & NBIT) != 0);
277 1.1 christos ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
278 1.1 christos ASSIGNC ((state->Reg[15] & CBIT) != 0);
279 1.1 christos ASSIGNV ((state->Reg[15] & VBIT) != 0);
280 1.1 christos }
281 1.1 christos
282 1.1 christos /* This routine controls the saving and restoring of registers across mode
283 1.1 christos changes. The regbank matrix is largely unused, only rows 13 and 14 are
284 1.1 christos used across all modes, 8 to 14 are used for FIQ, all others use the USER
285 1.1 christos column. It's easier this way. old and new parameter are modes numbers.
286 1.1 christos Notice the side effect of changing the Bank variable. */
287 1.1 christos
288 1.1 christos ARMword
289 1.1 christos ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
290 1.1 christos {
291 1.1 christos unsigned i;
292 1.1 christos ARMword oldbank;
293 1.1 christos ARMword newbank;
294 1.1 christos
295 1.1 christos oldbank = ModeToBank (oldmode);
296 1.1 christos newbank = state->Bank = ModeToBank (newmode);
297 1.1 christos
298 1.1 christos /* Do we really need to do it? */
299 1.1 christos if (oldbank != newbank)
300 1.1 christos {
301 1.1 christos /* Save away the old registers. */
302 1.1 christos switch (oldbank)
303 1.1 christos {
304 1.1 christos case USERBANK:
305 1.1 christos case IRQBANK:
306 1.1 christos case SVCBANK:
307 1.1 christos case ABORTBANK:
308 1.1 christos case UNDEFBANK:
309 1.1 christos if (newbank == FIQBANK)
310 1.1 christos for (i = 8; i < 13; i++)
311 1.1 christos state->RegBank[USERBANK][i] = state->Reg[i];
312 1.1 christos state->RegBank[oldbank][13] = state->Reg[13];
313 1.1 christos state->RegBank[oldbank][14] = state->Reg[14];
314 1.1 christos break;
315 1.1 christos case FIQBANK:
316 1.1 christos for (i = 8; i < 15; i++)
317 1.1 christos state->RegBank[FIQBANK][i] = state->Reg[i];
318 1.1 christos break;
319 1.1 christos case DUMMYBANK:
320 1.1 christos for (i = 8; i < 15; i++)
321 1.1 christos state->RegBank[DUMMYBANK][i] = 0;
322 1.1 christos break;
323 1.1 christos default:
324 1.1 christos abort ();
325 1.1 christos }
326 1.1 christos
327 1.1 christos /* Restore the new registers. */
328 1.1 christos switch (newbank)
329 1.1 christos {
330 1.1 christos case USERBANK:
331 1.1 christos case IRQBANK:
332 1.1 christos case SVCBANK:
333 1.1 christos case ABORTBANK:
334 1.1 christos case UNDEFBANK:
335 1.1 christos if (oldbank == FIQBANK)
336 1.1 christos for (i = 8; i < 13; i++)
337 1.1 christos state->Reg[i] = state->RegBank[USERBANK][i];
338 1.1 christos state->Reg[13] = state->RegBank[newbank][13];
339 1.1 christos state->Reg[14] = state->RegBank[newbank][14];
340 1.1 christos break;
341 1.1 christos case FIQBANK:
342 1.1 christos for (i = 8; i < 15; i++)
343 1.1 christos state->Reg[i] = state->RegBank[FIQBANK][i];
344 1.1 christos break;
345 1.1 christos case DUMMYBANK:
346 1.1 christos for (i = 8; i < 15; i++)
347 1.1 christos state->Reg[i] = 0;
348 1.1 christos break;
349 1.1 christos default:
350 1.1 christos abort ();
351 1.1 christos }
352 1.1 christos }
353 1.1 christos
354 1.1 christos return newmode;
355 1.1 christos }
356 1.1 christos
357 1.1 christos /* Given a processor mode, this routine returns the
358 1.1 christos register bank that will be accessed in that mode. */
359 1.1 christos
360 1.1 christos static ARMword
361 1.1 christos ModeToBank (ARMword mode)
362 1.1 christos {
363 1.1 christos static ARMword bankofmode[] =
364 1.1 christos {
365 1.1 christos USERBANK, FIQBANK, IRQBANK, SVCBANK,
366 1.1 christos DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
367 1.1 christos DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
368 1.1 christos DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
369 1.1 christos USERBANK, FIQBANK, IRQBANK, SVCBANK,
370 1.1 christos DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
371 1.1 christos DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
372 1.1 christos DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
373 1.1 christos };
374 1.1 christos
375 1.1 christos if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
376 1.1 christos return DUMMYBANK;
377 1.1 christos
378 1.1 christos return bankofmode[mode];
379 1.1 christos }
380 1.1 christos
381 1.1 christos /* Returns the register number of the nth register in a reg list. */
382 1.1 christos
383 1.1 christos unsigned
384 1.1 christos ARMul_NthReg (ARMword instr, unsigned number)
385 1.1 christos {
386 1.1 christos unsigned bit, upto;
387 1.1 christos
388 1.1 christos for (bit = 0, upto = 0; upto <= number; bit ++)
389 1.1 christos if (BIT (bit))
390 1.1 christos upto ++;
391 1.1 christos
392 1.1 christos return (bit - 1);
393 1.1 christos }
394 1.1 christos
395 1.1 christos /* Assigns the N and Z flags depending on the value of result. */
396 1.1 christos
397 1.1 christos void
398 1.1 christos ARMul_NegZero (ARMul_State * state, ARMword result)
399 1.1 christos {
400 1.1 christos if (NEG (result))
401 1.1 christos {
402 1.1 christos SETN;
403 1.1 christos CLEARZ;
404 1.1 christos }
405 1.1 christos else if (result == 0)
406 1.1 christos {
407 1.1 christos CLEARN;
408 1.1 christos SETZ;
409 1.1 christos }
410 1.1 christos else
411 1.1 christos {
412 1.1 christos CLEARN;
413 1.1 christos CLEARZ;
414 1.1 christos }
415 1.1 christos }
416 1.1 christos
417 1.1 christos /* Compute whether an addition of A and B, giving RESULT, overflowed. */
418 1.1 christos
419 1.1 christos int
420 1.1 christos AddOverflow (ARMword a, ARMword b, ARMword result)
421 1.1 christos {
422 1.1 christos return ((NEG (a) && NEG (b) && POS (result))
423 1.1 christos || (POS (a) && POS (b) && NEG (result)));
424 1.1 christos }
425 1.1 christos
426 1.1 christos /* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
427 1.1 christos
428 1.1 christos int
429 1.1 christos SubOverflow (ARMword a, ARMword b, ARMword result)
430 1.1 christos {
431 1.1 christos return ((NEG (a) && POS (b) && POS (result))
432 1.1 christos || (POS (a) && NEG (b) && NEG (result)));
433 1.1 christos }
434 1.1 christos
435 1.1 christos /* Assigns the C flag after an addition of a and b to give result. */
436 1.1 christos
437 1.1 christos void
438 1.1 christos ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
439 1.1 christos {
440 1.1 christos ASSIGNC ((NEG (a) && NEG (b)) ||
441 1.1 christos (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
442 1.1 christos }
443 1.1 christos
444 1.1 christos /* Assigns the V flag after an addition of a and b to give result. */
445 1.1 christos
446 1.1 christos void
447 1.1 christos ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
448 1.1 christos {
449 1.1 christos ASSIGNV (AddOverflow (a, b, result));
450 1.1 christos }
451 1.1 christos
452 1.1 christos /* Assigns the C flag after an subtraction of a and b to give result. */
453 1.1 christos
454 1.1 christos void
455 1.1 christos ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
456 1.1 christos {
457 1.1 christos ASSIGNC ((NEG (a) && POS (b)) ||
458 1.1 christos (NEG (a) && POS (result)) || (POS (b) && POS (result)));
459 1.1 christos }
460 1.1 christos
461 1.1 christos /* Assigns the V flag after an subtraction of a and b to give result. */
462 1.1 christos
463 1.1 christos void
464 1.1 christos ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
465 1.1 christos {
466 1.1 christos ASSIGNV (SubOverflow (a, b, result));
467 1.1 christos }
468 1.1 christos
469 1.1 christos /* This function does the work of generating the addresses used in an
470 1.1 christos LDC instruction. The code here is always post-indexed, it's up to the
471 1.1 christos caller to get the input address correct and to handle base register
472 1.1 christos modification. It also handles the Busy-Waiting. */
473 1.1 christos
474 1.1 christos void
475 1.1 christos ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
476 1.1 christos {
477 1.1 christos unsigned cpab;
478 1.1 christos ARMword data;
479 1.1 christos
480 1.1 christos UNDEF_LSCPCBaseWb;
481 1.1 christos
482 1.1 christos if (! CP_ACCESS_ALLOWED (state, CPNum))
483 1.1 christos {
484 1.1 christos ARMul_UndefInstr (state, instr);
485 1.1 christos return;
486 1.1 christos }
487 1.1 christos
488 1.1 christos if (ADDREXCEPT (address))
489 1.1 christos INTERNALABORT (address);
490 1.1 christos
491 1.1 christos cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
492 1.1 christos while (cpab == ARMul_BUSY)
493 1.1 christos {
494 1.1 christos ARMul_Icycles (state, 1, 0);
495 1.1 christos
496 1.1 christos if (IntPending (state))
497 1.1 christos {
498 1.1 christos cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
499 1.1 christos return;
500 1.1 christos }
501 1.1 christos else
502 1.1 christos cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
503 1.1 christos }
504 1.1 christos if (cpab == ARMul_CANT)
505 1.1 christos {
506 1.1 christos CPTAKEABORT;
507 1.1 christos return;
508 1.1 christos }
509 1.1 christos
510 1.1 christos cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
511 1.1 christos data = ARMul_LoadWordN (state, address);
512 1.1 christos BUSUSEDINCPCN;
513 1.1 christos
514 1.1 christos if (BIT (21))
515 1.1 christos LSBase = state->Base;
516 1.1 christos cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
517 1.1 christos
518 1.1 christos while (cpab == ARMul_INC)
519 1.1 christos {
520 1.1 christos address += 4;
521 1.1 christos data = ARMul_LoadWordN (state, address);
522 1.1 christos cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
523 1.1 christos }
524 1.1 christos
525 1.1 christos if (state->abortSig || state->Aborted)
526 1.1 christos TAKEABORT;
527 1.1 christos }
528 1.1 christos
529 1.1 christos /* This function does the work of generating the addresses used in an
530 1.1 christos STC instruction. The code here is always post-indexed, it's up to the
531 1.1 christos caller to get the input address correct and to handle base register
532 1.1 christos modification. It also handles the Busy-Waiting. */
533 1.1 christos
534 1.1 christos void
535 1.1 christos ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
536 1.1 christos {
537 1.1 christos unsigned cpab;
538 1.1 christos ARMword data;
539 1.1 christos
540 1.1 christos UNDEF_LSCPCBaseWb;
541 1.1 christos
542 1.1 christos if (! CP_ACCESS_ALLOWED (state, CPNum))
543 1.1 christos {
544 1.1 christos ARMul_UndefInstr (state, instr);
545 1.1 christos return;
546 1.1 christos }
547 1.1 christos
548 1.1 christos if (ADDREXCEPT (address) || VECTORACCESS (address))
549 1.1 christos INTERNALABORT (address);
550 1.1 christos
551 1.1 christos cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
552 1.1 christos while (cpab == ARMul_BUSY)
553 1.1 christos {
554 1.1 christos ARMul_Icycles (state, 1, 0);
555 1.1 christos if (IntPending (state))
556 1.1 christos {
557 1.1 christos cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
558 1.1 christos return;
559 1.1 christos }
560 1.1 christos else
561 1.1 christos cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
562 1.1 christos }
563 1.1 christos
564 1.1 christos if (cpab == ARMul_CANT)
565 1.1 christos {
566 1.1 christos CPTAKEABORT;
567 1.1 christos return;
568 1.1 christos }
569 1.1 christos #ifndef MODE32
570 1.1 christos if (ADDREXCEPT (address) || VECTORACCESS (address))
571 1.1 christos INTERNALABORT (address);
572 1.1 christos #endif
573 1.1 christos BUSUSEDINCPCN;
574 1.1 christos if (BIT (21))
575 1.1 christos LSBase = state->Base;
576 1.1 christos cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
577 1.1 christos ARMul_StoreWordN (state, address, data);
578 1.1 christos
579 1.1 christos while (cpab == ARMul_INC)
580 1.1 christos {
581 1.1 christos address += 4;
582 1.1 christos cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
583 1.1 christos ARMul_StoreWordN (state, address, data);
584 1.1 christos }
585 1.1 christos
586 1.1 christos if (state->abortSig || state->Aborted)
587 1.1 christos TAKEABORT;
588 1.1 christos }
589 1.1 christos
590 1.1 christos /* This function does the Busy-Waiting for an MCR instruction. */
591 1.1 christos
592 1.1 christos void
593 1.1 christos ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
594 1.1 christos {
595 1.1 christos unsigned cpab;
596 1.1 christos
597 1.1 christos if (! CP_ACCESS_ALLOWED (state, CPNum))
598 1.1 christos {
599 1.1 christos ARMul_UndefInstr (state, instr);
600 1.1 christos return;
601 1.1 christos }
602 1.1 christos
603 1.1 christos cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
604 1.1 christos
605 1.1 christos while (cpab == ARMul_BUSY)
606 1.1 christos {
607 1.1 christos ARMul_Icycles (state, 1, 0);
608 1.1 christos
609 1.1 christos if (IntPending (state))
610 1.1 christos {
611 1.1 christos cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
612 1.1 christos return;
613 1.1 christos }
614 1.1 christos else
615 1.1 christos cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
616 1.1 christos }
617 1.1 christos
618 1.1 christos if (cpab == ARMul_CANT)
619 1.1 christos ARMul_Abort (state, ARMul_UndefinedInstrV);
620 1.1 christos else
621 1.1 christos {
622 1.1 christos BUSUSEDINCPCN;
623 1.1 christos ARMul_Ccycles (state, 1, 0);
624 1.1 christos }
625 1.1 christos }
626 1.1 christos
627 1.1 christos /* This function does the Busy-Waiting for an MRC instruction. */
628 1.1 christos
629 1.1 christos ARMword
630 1.1 christos ARMul_MRC (ARMul_State * state, ARMword instr)
631 1.1 christos {
632 1.1 christos unsigned cpab;
633 1.1 christos ARMword result = 0;
634 1.1 christos
635 1.1 christos if (! CP_ACCESS_ALLOWED (state, CPNum))
636 1.1 christos {
637 1.1 christos ARMul_UndefInstr (state, instr);
638 1.1 christos return result;
639 1.1 christos }
640 1.1 christos
641 1.1 christos cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
642 1.1 christos while (cpab == ARMul_BUSY)
643 1.1 christos {
644 1.1 christos ARMul_Icycles (state, 1, 0);
645 1.1 christos if (IntPending (state))
646 1.1 christos {
647 1.1 christos cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
648 1.1 christos return (0);
649 1.1 christos }
650 1.1 christos else
651 1.1 christos cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
652 1.1 christos }
653 1.1 christos if (cpab == ARMul_CANT)
654 1.1 christos {
655 1.1 christos ARMul_Abort (state, ARMul_UndefinedInstrV);
656 1.1 christos /* Parent will destroy the flags otherwise. */
657 1.1 christos result = ECC;
658 1.1 christos }
659 1.1 christos else
660 1.1 christos {
661 1.1 christos BUSUSEDINCPCN;
662 1.1 christos ARMul_Ccycles (state, 1, 0);
663 1.1 christos ARMul_Icycles (state, 1, 0);
664 1.1 christos }
665 1.1 christos
666 1.1 christos return result;
667 1.1 christos }
668 1.1 christos
669 1.1 christos /* This function does the Busy-Waiting for an CDP instruction. */
670 1.1 christos
671 1.1 christos void
672 1.1 christos ARMul_CDP (ARMul_State * state, ARMword instr)
673 1.1 christos {
674 1.1 christos unsigned cpab;
675 1.1 christos
676 1.1 christos if (! CP_ACCESS_ALLOWED (state, CPNum))
677 1.1 christos {
678 1.1 christos ARMul_UndefInstr (state, instr);
679 1.1 christos return;
680 1.1 christos }
681 1.1 christos
682 1.1 christos cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
683 1.1 christos while (cpab == ARMul_BUSY)
684 1.1 christos {
685 1.1 christos ARMul_Icycles (state, 1, 0);
686 1.1 christos if (IntPending (state))
687 1.1 christos {
688 1.1 christos cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
689 1.1 christos return;
690 1.1 christos }
691 1.1 christos else
692 1.1 christos cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
693 1.1 christos }
694 1.1 christos if (cpab == ARMul_CANT)
695 1.1 christos ARMul_Abort (state, ARMul_UndefinedInstrV);
696 1.1 christos else
697 1.1 christos BUSUSEDN;
698 1.1 christos }
699 1.1 christos
700 1.1 christos /* This function handles Undefined instructions, as CP isntruction. */
701 1.1 christos
702 1.1 christos void
703 1.1 christos ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
704 1.1 christos {
705 1.1 christos ARMul_Abort (state, ARMul_UndefinedInstrV);
706 1.1 christos }
707 1.1 christos
708 1.1 christos /* Return TRUE if an interrupt is pending, FALSE otherwise. */
709 1.1 christos
710 1.1 christos unsigned
711 1.1 christos IntPending (ARMul_State * state)
712 1.1 christos {
713 1.1 christos if (state->Exception)
714 1.1 christos {
715 1.1 christos /* Any exceptions. */
716 1.1 christos if (state->NresetSig == LOW)
717 1.1 christos {
718 1.1 christos ARMul_Abort (state, ARMul_ResetV);
719 1.1 christos return TRUE;
720 1.1 christos }
721 1.1 christos else if (!state->NfiqSig && !FFLAG)
722 1.1 christos {
723 1.1 christos ARMul_Abort (state, ARMul_FIQV);
724 1.1 christos return TRUE;
725 1.1 christos }
726 1.1 christos else if (!state->NirqSig && !IFLAG)
727 1.1 christos {
728 1.1 christos ARMul_Abort (state, ARMul_IRQV);
729 1.1 christos return TRUE;
730 1.1 christos }
731 1.1 christos }
732 1.1 christos
733 1.1 christos return FALSE;
734 1.1 christos }
735 1.1 christos
736 1.1 christos /* Align a word access to a non word boundary. */
737 1.1 christos
738 1.1 christos ARMword
739 1.1 christos ARMul_Align (state, address, data)
740 1.1 christos ARMul_State * state ATTRIBUTE_UNUSED;
741 1.1 christos ARMword address;
742 1.1 christos ARMword data;
743 1.1 christos {
744 1.1 christos /* This code assumes the address is really unaligned,
745 1.1 christos as a shift by 32 is undefined in C. */
746 1.1 christos
747 1.1 christos address = (address & 3) << 3; /* Get the word address. */
748 1.1 christos return ((data >> address) | (data << (32 - address))); /* rot right */
749 1.1 christos }
750 1.1 christos
751 1.1 christos /* This routine is used to call another routine after a certain number of
752 1.1 christos cycles have been executed. The first parameter is the number of cycles
753 1.1 christos delay before the function is called, the second argument is a pointer
754 1.1 christos to the function. A delay of zero doesn't work, just call the function. */
755 1.1 christos
756 1.1 christos void
757 1.1 christos ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
758 1.1 christos unsigned (*what) (ARMul_State *))
759 1.1 christos {
760 1.1 christos unsigned long when;
761 1.1 christos struct EventNode *event;
762 1.1 christos
763 1.1 christos if (state->EventSet++ == 0)
764 1.1 christos state->Now = ARMul_Time (state);
765 1.1 christos when = (state->Now + delay) % EVENTLISTSIZE;
766 1.1 christos event = (struct EventNode *) malloc (sizeof (struct EventNode));
767 1.1 christos event->func = what;
768 1.1 christos event->next = *(state->EventPtr + when);
769 1.1 christos *(state->EventPtr + when) = event;
770 1.1 christos }
771 1.1 christos
772 1.1 christos /* This routine is called at the beginning of
773 1.1 christos every cycle, to envoke scheduled events. */
774 1.1 christos
775 1.1 christos void
776 1.1 christos ARMul_EnvokeEvent (ARMul_State * state)
777 1.1 christos {
778 1.1 christos static unsigned long then;
779 1.1 christos
780 1.1 christos then = state->Now;
781 1.1 christos state->Now = ARMul_Time (state) % EVENTLISTSIZE;
782 1.1 christos if (then < state->Now)
783 1.1 christos /* Schedule events. */
784 1.1 christos EnvokeList (state, then, state->Now);
785 1.1 christos else if (then > state->Now)
786 1.1 christos {
787 1.1 christos /* Need to wrap around the list. */
788 1.1 christos EnvokeList (state, then, EVENTLISTSIZE - 1L);
789 1.1 christos EnvokeList (state, 0L, state->Now);
790 1.1 christos }
791 1.1 christos }
792 1.1 christos
793 1.1 christos /* Envokes all the entries in a range. */
794 1.1 christos
795 1.1 christos static void
796 1.1 christos EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
797 1.1 christos {
798 1.1 christos for (; from <= to; from++)
799 1.1 christos {
800 1.1 christos struct EventNode *anevent;
801 1.1 christos
802 1.1 christos anevent = *(state->EventPtr + from);
803 1.1 christos while (anevent)
804 1.1 christos {
805 1.1 christos (anevent->func) (state);
806 1.1 christos state->EventSet--;
807 1.1 christos anevent = anevent->next;
808 1.1 christos }
809 1.1 christos *(state->EventPtr + from) = NULL;
810 1.1 christos }
811 1.1 christos }
812 1.1 christos
813 1.1 christos /* This routine is returns the number of clock ticks since the last reset. */
814 1.1 christos
815 1.1 christos unsigned long
816 1.1 christos ARMul_Time (ARMul_State * state)
817 1.1 christos {
818 1.1 christos return (state->NumScycles + state->NumNcycles +
819 1.1 christos state->NumIcycles + state->NumCcycles + state->NumFcycles);
820 1.1 christos }
821