1a1ba9ba4Schristos /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
2a1ba9ba4Schristos Copyright (C) 1994 Advanced RISC Machines Ltd.
3a1ba9ba4Schristos
4a1ba9ba4Schristos This program is free software; you can redistribute it and/or modify
5a1ba9ba4Schristos it under the terms of the GNU General Public License as published by
6a1ba9ba4Schristos the Free Software Foundation; either version 3 of the License, or
7a1ba9ba4Schristos (at your option) any later version.
8a1ba9ba4Schristos
9a1ba9ba4Schristos This program is distributed in the hope that it will be useful,
10a1ba9ba4Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
11a1ba9ba4Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12a1ba9ba4Schristos GNU General Public License for more details.
13a1ba9ba4Schristos
14a1ba9ba4Schristos You should have received a copy of the GNU General Public License
15a1ba9ba4Schristos along with this program; if not, see <http://www.gnu.org/licenses/>. */
16a1ba9ba4Schristos
17a1ba9ba4Schristos #include "armdefs.h"
18a1ba9ba4Schristos #include "armemu.h"
19a1ba9ba4Schristos #include "ansidecl.h"
20*15d8e94aSchristos #include "libiberty.h"
21a1ba9ba4Schristos #include <math.h>
22a1ba9ba4Schristos
23a1ba9ba4Schristos /* Definitions for the support routines. */
24a1ba9ba4Schristos
25a1ba9ba4Schristos static ARMword ModeToBank (ARMword);
26a1ba9ba4Schristos static void EnvokeList (ARMul_State *, unsigned long, unsigned long);
27a1ba9ba4Schristos
28a1ba9ba4Schristos struct EventNode
29a1ba9ba4Schristos { /* An event list node. */
30a1ba9ba4Schristos unsigned (*func) (ARMul_State *); /* The function to call. */
31a1ba9ba4Schristos struct EventNode *next;
32a1ba9ba4Schristos };
33a1ba9ba4Schristos
34a1ba9ba4Schristos /* This routine returns the value of a register from a mode. */
35a1ba9ba4Schristos
36a1ba9ba4Schristos ARMword
ARMul_GetReg(ARMul_State * state,unsigned mode,unsigned reg)37a1ba9ba4Schristos ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
38a1ba9ba4Schristos {
39a1ba9ba4Schristos mode &= MODEBITS;
40a1ba9ba4Schristos if (mode != state->Mode)
41a1ba9ba4Schristos return (state->RegBank[ModeToBank ((ARMword) mode)][reg]);
42a1ba9ba4Schristos else
43a1ba9ba4Schristos return (state->Reg[reg]);
44a1ba9ba4Schristos }
45a1ba9ba4Schristos
46a1ba9ba4Schristos /* This routine sets the value of a register for a mode. */
47a1ba9ba4Schristos
48a1ba9ba4Schristos void
ARMul_SetReg(ARMul_State * state,unsigned mode,unsigned reg,ARMword value)49a1ba9ba4Schristos ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
50a1ba9ba4Schristos {
51a1ba9ba4Schristos mode &= MODEBITS;
52a1ba9ba4Schristos if (mode != state->Mode)
53a1ba9ba4Schristos state->RegBank[ModeToBank ((ARMword) mode)][reg] = value;
54a1ba9ba4Schristos else
55a1ba9ba4Schristos state->Reg[reg] = value;
56a1ba9ba4Schristos }
57a1ba9ba4Schristos
58a1ba9ba4Schristos /* This routine returns the value of the PC, mode independently. */
59a1ba9ba4Schristos
60a1ba9ba4Schristos ARMword
ARMul_GetPC(ARMul_State * state)61a1ba9ba4Schristos ARMul_GetPC (ARMul_State * state)
62a1ba9ba4Schristos {
63a1ba9ba4Schristos if (state->Mode > SVC26MODE)
64a1ba9ba4Schristos return state->Reg[15];
65a1ba9ba4Schristos else
66a1ba9ba4Schristos return R15PC;
67a1ba9ba4Schristos }
68a1ba9ba4Schristos
69a1ba9ba4Schristos /* This routine returns the value of the PC, mode independently. */
70a1ba9ba4Schristos
71a1ba9ba4Schristos ARMword
ARMul_GetNextPC(ARMul_State * state)72a1ba9ba4Schristos ARMul_GetNextPC (ARMul_State * state)
73a1ba9ba4Schristos {
74a1ba9ba4Schristos if (state->Mode > SVC26MODE)
75a1ba9ba4Schristos return state->Reg[15] + isize;
76a1ba9ba4Schristos else
77a1ba9ba4Schristos return (state->Reg[15] + isize) & R15PCBITS;
78a1ba9ba4Schristos }
79a1ba9ba4Schristos
80a1ba9ba4Schristos /* This routine sets the value of the PC. */
81a1ba9ba4Schristos
82a1ba9ba4Schristos void
ARMul_SetPC(ARMul_State * state,ARMword value)83a1ba9ba4Schristos ARMul_SetPC (ARMul_State * state, ARMword value)
84a1ba9ba4Schristos {
85a1ba9ba4Schristos if (ARMul_MODE32BIT)
86a1ba9ba4Schristos state->Reg[15] = value & PCBITS;
87a1ba9ba4Schristos else
88a1ba9ba4Schristos state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
89a1ba9ba4Schristos FLUSHPIPE;
90a1ba9ba4Schristos }
91a1ba9ba4Schristos
92a1ba9ba4Schristos /* This routine returns the value of register 15, mode independently. */
93a1ba9ba4Schristos
94a1ba9ba4Schristos ARMword
ARMul_GetR15(ARMul_State * state)95a1ba9ba4Schristos ARMul_GetR15 (ARMul_State * state)
96a1ba9ba4Schristos {
97a1ba9ba4Schristos if (state->Mode > SVC26MODE)
98a1ba9ba4Schristos return (state->Reg[15]);
99a1ba9ba4Schristos else
100a1ba9ba4Schristos return (R15PC | ECC | ER15INT | EMODE);
101a1ba9ba4Schristos }
102a1ba9ba4Schristos
103a1ba9ba4Schristos /* This routine sets the value of Register 15. */
104a1ba9ba4Schristos
105a1ba9ba4Schristos void
ARMul_SetR15(ARMul_State * state,ARMword value)106a1ba9ba4Schristos ARMul_SetR15 (ARMul_State * state, ARMword value)
107a1ba9ba4Schristos {
108a1ba9ba4Schristos if (ARMul_MODE32BIT)
109a1ba9ba4Schristos state->Reg[15] = value & PCBITS;
110a1ba9ba4Schristos else
111a1ba9ba4Schristos {
112a1ba9ba4Schristos state->Reg[15] = value;
113a1ba9ba4Schristos ARMul_R15Altered (state);
114a1ba9ba4Schristos }
115a1ba9ba4Schristos FLUSHPIPE;
116a1ba9ba4Schristos }
117a1ba9ba4Schristos
118a1ba9ba4Schristos /* This routine returns the value of the CPSR. */
119a1ba9ba4Schristos
120a1ba9ba4Schristos ARMword
ARMul_GetCPSR(ARMul_State * state)121a1ba9ba4Schristos ARMul_GetCPSR (ARMul_State * state)
122a1ba9ba4Schristos {
123a1ba9ba4Schristos return (CPSR | state->Cpsr);
124a1ba9ba4Schristos }
125a1ba9ba4Schristos
126a1ba9ba4Schristos /* This routine sets the value of the CPSR. */
127a1ba9ba4Schristos
128a1ba9ba4Schristos void
ARMul_SetCPSR(ARMul_State * state,ARMword value)129a1ba9ba4Schristos ARMul_SetCPSR (ARMul_State * state, ARMword value)
130a1ba9ba4Schristos {
131a1ba9ba4Schristos state->Cpsr = value;
132a1ba9ba4Schristos ARMul_CPSRAltered (state);
133a1ba9ba4Schristos }
134a1ba9ba4Schristos
135a1ba9ba4Schristos /* This routine does all the nasty bits involved in a write to the CPSR,
136a1ba9ba4Schristos including updating the register bank, given a MSR instruction. */
137a1ba9ba4Schristos
138a1ba9ba4Schristos void
ARMul_FixCPSR(ARMul_State * state,ARMword instr,ARMword rhs)139a1ba9ba4Schristos ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
140a1ba9ba4Schristos {
141a1ba9ba4Schristos state->Cpsr = ARMul_GetCPSR (state);
142a1ba9ba4Schristos
143a1ba9ba4Schristos if (state->Mode != USER26MODE
144a1ba9ba4Schristos && state->Mode != USER32MODE)
145a1ba9ba4Schristos {
146a1ba9ba4Schristos /* In user mode, only write flags. */
147a1ba9ba4Schristos if (BIT (16))
148a1ba9ba4Schristos SETPSR_C (state->Cpsr, rhs);
149a1ba9ba4Schristos if (BIT (17))
150a1ba9ba4Schristos SETPSR_X (state->Cpsr, rhs);
151a1ba9ba4Schristos if (BIT (18))
152a1ba9ba4Schristos SETPSR_S (state->Cpsr, rhs);
153a1ba9ba4Schristos }
154a1ba9ba4Schristos if (BIT (19))
155a1ba9ba4Schristos SETPSR_F (state->Cpsr, rhs);
156a1ba9ba4Schristos ARMul_CPSRAltered (state);
157a1ba9ba4Schristos }
158a1ba9ba4Schristos
159a1ba9ba4Schristos /* Get an SPSR from the specified mode. */
160a1ba9ba4Schristos
161a1ba9ba4Schristos ARMword
ARMul_GetSPSR(ARMul_State * state,ARMword mode)162a1ba9ba4Schristos ARMul_GetSPSR (ARMul_State * state, ARMword mode)
163a1ba9ba4Schristos {
164a1ba9ba4Schristos ARMword bank = ModeToBank (mode & MODEBITS);
165a1ba9ba4Schristos
166a1ba9ba4Schristos if (! BANK_CAN_ACCESS_SPSR (bank))
167a1ba9ba4Schristos return ARMul_GetCPSR (state);
168a1ba9ba4Schristos
169a1ba9ba4Schristos return state->Spsr[bank];
170a1ba9ba4Schristos }
171a1ba9ba4Schristos
172a1ba9ba4Schristos /* This routine does a write to an SPSR. */
173a1ba9ba4Schristos
174a1ba9ba4Schristos void
ARMul_SetSPSR(ARMul_State * state,ARMword mode,ARMword value)175a1ba9ba4Schristos ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
176a1ba9ba4Schristos {
177a1ba9ba4Schristos ARMword bank = ModeToBank (mode & MODEBITS);
178a1ba9ba4Schristos
179a1ba9ba4Schristos if (BANK_CAN_ACCESS_SPSR (bank))
180a1ba9ba4Schristos state->Spsr[bank] = value;
181a1ba9ba4Schristos }
182a1ba9ba4Schristos
183a1ba9ba4Schristos /* This routine does a write to the current SPSR, given an MSR instruction. */
184a1ba9ba4Schristos
185a1ba9ba4Schristos void
ARMul_FixSPSR(ARMul_State * state,ARMword instr,ARMword rhs)186a1ba9ba4Schristos ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
187a1ba9ba4Schristos {
188a1ba9ba4Schristos if (BANK_CAN_ACCESS_SPSR (state->Bank))
189a1ba9ba4Schristos {
190a1ba9ba4Schristos if (BIT (16))
191a1ba9ba4Schristos SETPSR_C (state->Spsr[state->Bank], rhs);
192a1ba9ba4Schristos if (BIT (17))
193a1ba9ba4Schristos SETPSR_X (state->Spsr[state->Bank], rhs);
194a1ba9ba4Schristos if (BIT (18))
195a1ba9ba4Schristos SETPSR_S (state->Spsr[state->Bank], rhs);
196a1ba9ba4Schristos if (BIT (19))
197a1ba9ba4Schristos SETPSR_F (state->Spsr[state->Bank], rhs);
198a1ba9ba4Schristos }
199a1ba9ba4Schristos }
200a1ba9ba4Schristos
201a1ba9ba4Schristos /* This routine updates the state of the emulator after the Cpsr has been
202a1ba9ba4Schristos changed. Both the processor flags and register bank are updated. */
203a1ba9ba4Schristos
204a1ba9ba4Schristos void
ARMul_CPSRAltered(ARMul_State * state)205a1ba9ba4Schristos ARMul_CPSRAltered (ARMul_State * state)
206a1ba9ba4Schristos {
207a1ba9ba4Schristos ARMword oldmode;
208a1ba9ba4Schristos
209a1ba9ba4Schristos if (state->prog32Sig == LOW)
210a1ba9ba4Schristos state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
211a1ba9ba4Schristos
212a1ba9ba4Schristos oldmode = state->Mode;
213a1ba9ba4Schristos
214a1ba9ba4Schristos if (state->Mode != (state->Cpsr & MODEBITS))
215a1ba9ba4Schristos {
216a1ba9ba4Schristos state->Mode =
217a1ba9ba4Schristos ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
218a1ba9ba4Schristos
219a1ba9ba4Schristos state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
220a1ba9ba4Schristos }
221a1ba9ba4Schristos state->Cpsr &= ~MODEBITS;
222a1ba9ba4Schristos
223a1ba9ba4Schristos ASSIGNINT (state->Cpsr & INTBITS);
224a1ba9ba4Schristos state->Cpsr &= ~INTBITS;
225a1ba9ba4Schristos ASSIGNN ((state->Cpsr & NBIT) != 0);
226a1ba9ba4Schristos state->Cpsr &= ~NBIT;
227a1ba9ba4Schristos ASSIGNZ ((state->Cpsr & ZBIT) != 0);
228a1ba9ba4Schristos state->Cpsr &= ~ZBIT;
229a1ba9ba4Schristos ASSIGNC ((state->Cpsr & CBIT) != 0);
230a1ba9ba4Schristos state->Cpsr &= ~CBIT;
231a1ba9ba4Schristos ASSIGNV ((state->Cpsr & VBIT) != 0);
232a1ba9ba4Schristos state->Cpsr &= ~VBIT;
233a1ba9ba4Schristos ASSIGNS ((state->Cpsr & SBIT) != 0);
234a1ba9ba4Schristos state->Cpsr &= ~SBIT;
235a1ba9ba4Schristos #ifdef MODET
236a1ba9ba4Schristos ASSIGNT ((state->Cpsr & TBIT) != 0);
237a1ba9ba4Schristos state->Cpsr &= ~TBIT;
238a1ba9ba4Schristos #endif
239a1ba9ba4Schristos
240a1ba9ba4Schristos if (oldmode > SVC26MODE)
241a1ba9ba4Schristos {
242a1ba9ba4Schristos if (state->Mode <= SVC26MODE)
243a1ba9ba4Schristos {
244a1ba9ba4Schristos state->Emulate = CHANGEMODE;
245a1ba9ba4Schristos state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
246a1ba9ba4Schristos }
247a1ba9ba4Schristos }
248a1ba9ba4Schristos else
249a1ba9ba4Schristos {
250a1ba9ba4Schristos if (state->Mode > SVC26MODE)
251a1ba9ba4Schristos {
252a1ba9ba4Schristos state->Emulate = CHANGEMODE;
253a1ba9ba4Schristos state->Reg[15] = R15PC;
254a1ba9ba4Schristos }
255a1ba9ba4Schristos else
256a1ba9ba4Schristos state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
257a1ba9ba4Schristos }
258a1ba9ba4Schristos }
259a1ba9ba4Schristos
260a1ba9ba4Schristos /* This routine updates the state of the emulator after register 15 has
261a1ba9ba4Schristos been changed. Both the processor flags and register bank are updated.
262a1ba9ba4Schristos This routine should only be called from a 26 bit mode. */
263a1ba9ba4Schristos
264a1ba9ba4Schristos void
ARMul_R15Altered(ARMul_State * state)265a1ba9ba4Schristos ARMul_R15Altered (ARMul_State * state)
266a1ba9ba4Schristos {
267a1ba9ba4Schristos if (state->Mode != R15MODE)
268a1ba9ba4Schristos {
269a1ba9ba4Schristos state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
270a1ba9ba4Schristos state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
271a1ba9ba4Schristos }
272a1ba9ba4Schristos
273a1ba9ba4Schristos if (state->Mode > SVC26MODE)
274a1ba9ba4Schristos state->Emulate = CHANGEMODE;
275a1ba9ba4Schristos
276a1ba9ba4Schristos ASSIGNR15INT (R15INT);
277a1ba9ba4Schristos
278a1ba9ba4Schristos ASSIGNN ((state->Reg[15] & NBIT) != 0);
279a1ba9ba4Schristos ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
280a1ba9ba4Schristos ASSIGNC ((state->Reg[15] & CBIT) != 0);
281a1ba9ba4Schristos ASSIGNV ((state->Reg[15] & VBIT) != 0);
282a1ba9ba4Schristos }
283a1ba9ba4Schristos
284a1ba9ba4Schristos /* This routine controls the saving and restoring of registers across mode
285a1ba9ba4Schristos changes. The regbank matrix is largely unused, only rows 13 and 14 are
286a1ba9ba4Schristos used across all modes, 8 to 14 are used for FIQ, all others use the USER
287a1ba9ba4Schristos column. It's easier this way. old and new parameter are modes numbers.
288a1ba9ba4Schristos Notice the side effect of changing the Bank variable. */
289a1ba9ba4Schristos
290a1ba9ba4Schristos ARMword
ARMul_SwitchMode(ARMul_State * state,ARMword oldmode,ARMword newmode)291a1ba9ba4Schristos ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
292a1ba9ba4Schristos {
293a1ba9ba4Schristos unsigned i;
294a1ba9ba4Schristos ARMword oldbank;
295a1ba9ba4Schristos ARMword newbank;
296a1ba9ba4Schristos
297a1ba9ba4Schristos oldbank = ModeToBank (oldmode);
298a1ba9ba4Schristos newbank = state->Bank = ModeToBank (newmode);
299a1ba9ba4Schristos
300a1ba9ba4Schristos /* Do we really need to do it? */
301a1ba9ba4Schristos if (oldbank != newbank)
302a1ba9ba4Schristos {
303a1ba9ba4Schristos /* Save away the old registers. */
304a1ba9ba4Schristos switch (oldbank)
305a1ba9ba4Schristos {
306a1ba9ba4Schristos case USERBANK:
307a1ba9ba4Schristos case IRQBANK:
308a1ba9ba4Schristos case SVCBANK:
309a1ba9ba4Schristos case ABORTBANK:
310a1ba9ba4Schristos case UNDEFBANK:
311a1ba9ba4Schristos if (newbank == FIQBANK)
312a1ba9ba4Schristos for (i = 8; i < 13; i++)
313a1ba9ba4Schristos state->RegBank[USERBANK][i] = state->Reg[i];
314a1ba9ba4Schristos state->RegBank[oldbank][13] = state->Reg[13];
315a1ba9ba4Schristos state->RegBank[oldbank][14] = state->Reg[14];
316a1ba9ba4Schristos break;
317a1ba9ba4Schristos case FIQBANK:
318a1ba9ba4Schristos for (i = 8; i < 15; i++)
319a1ba9ba4Schristos state->RegBank[FIQBANK][i] = state->Reg[i];
320a1ba9ba4Schristos break;
321a1ba9ba4Schristos case DUMMYBANK:
322a1ba9ba4Schristos for (i = 8; i < 15; i++)
323a1ba9ba4Schristos state->RegBank[DUMMYBANK][i] = 0;
324a1ba9ba4Schristos break;
325a1ba9ba4Schristos default:
326a1ba9ba4Schristos abort ();
327a1ba9ba4Schristos }
328a1ba9ba4Schristos
329a1ba9ba4Schristos /* Restore the new registers. */
330a1ba9ba4Schristos switch (newbank)
331a1ba9ba4Schristos {
332a1ba9ba4Schristos case USERBANK:
333a1ba9ba4Schristos case IRQBANK:
334a1ba9ba4Schristos case SVCBANK:
335a1ba9ba4Schristos case ABORTBANK:
336a1ba9ba4Schristos case UNDEFBANK:
337a1ba9ba4Schristos if (oldbank == FIQBANK)
338a1ba9ba4Schristos for (i = 8; i < 13; i++)
339a1ba9ba4Schristos state->Reg[i] = state->RegBank[USERBANK][i];
340a1ba9ba4Schristos state->Reg[13] = state->RegBank[newbank][13];
341a1ba9ba4Schristos state->Reg[14] = state->RegBank[newbank][14];
342a1ba9ba4Schristos break;
343a1ba9ba4Schristos case FIQBANK:
344a1ba9ba4Schristos for (i = 8; i < 15; i++)
345a1ba9ba4Schristos state->Reg[i] = state->RegBank[FIQBANK][i];
346a1ba9ba4Schristos break;
347a1ba9ba4Schristos case DUMMYBANK:
348a1ba9ba4Schristos for (i = 8; i < 15; i++)
349a1ba9ba4Schristos state->Reg[i] = 0;
350a1ba9ba4Schristos break;
351a1ba9ba4Schristos default:
352a1ba9ba4Schristos abort ();
353a1ba9ba4Schristos }
354a1ba9ba4Schristos }
355a1ba9ba4Schristos
356a1ba9ba4Schristos return newmode;
357a1ba9ba4Schristos }
358a1ba9ba4Schristos
359a1ba9ba4Schristos /* Given a processor mode, this routine returns the
360a1ba9ba4Schristos register bank that will be accessed in that mode. */
361a1ba9ba4Schristos
362a1ba9ba4Schristos static ARMword
ModeToBank(ARMword mode)363a1ba9ba4Schristos ModeToBank (ARMword mode)
364a1ba9ba4Schristos {
365a1ba9ba4Schristos static ARMword bankofmode[] =
366a1ba9ba4Schristos {
367a1ba9ba4Schristos USERBANK, FIQBANK, IRQBANK, SVCBANK,
368a1ba9ba4Schristos DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
369a1ba9ba4Schristos DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
370a1ba9ba4Schristos DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
371a1ba9ba4Schristos USERBANK, FIQBANK, IRQBANK, SVCBANK,
372a1ba9ba4Schristos DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
373a1ba9ba4Schristos DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
374a1ba9ba4Schristos DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
375a1ba9ba4Schristos };
376a1ba9ba4Schristos
377*15d8e94aSchristos if (mode >= ARRAY_SIZE (bankofmode))
378a1ba9ba4Schristos return DUMMYBANK;
379a1ba9ba4Schristos
380a1ba9ba4Schristos return bankofmode[mode];
381a1ba9ba4Schristos }
382a1ba9ba4Schristos
383a1ba9ba4Schristos /* Returns the register number of the nth register in a reg list. */
384a1ba9ba4Schristos
385a1ba9ba4Schristos unsigned
ARMul_NthReg(ARMword instr,unsigned number)386a1ba9ba4Schristos ARMul_NthReg (ARMword instr, unsigned number)
387a1ba9ba4Schristos {
388a1ba9ba4Schristos unsigned bit, upto;
389a1ba9ba4Schristos
390a1ba9ba4Schristos for (bit = 0, upto = 0; upto <= number; bit ++)
391a1ba9ba4Schristos if (BIT (bit))
392a1ba9ba4Schristos upto ++;
393a1ba9ba4Schristos
394a1ba9ba4Schristos return (bit - 1);
395a1ba9ba4Schristos }
396a1ba9ba4Schristos
397a1ba9ba4Schristos /* Assigns the N and Z flags depending on the value of result. */
398a1ba9ba4Schristos
399a1ba9ba4Schristos void
ARMul_NegZero(ARMul_State * state,ARMword result)400a1ba9ba4Schristos ARMul_NegZero (ARMul_State * state, ARMword result)
401a1ba9ba4Schristos {
402a1ba9ba4Schristos if (NEG (result))
403a1ba9ba4Schristos {
404a1ba9ba4Schristos SETN;
405a1ba9ba4Schristos CLEARZ;
406a1ba9ba4Schristos }
407a1ba9ba4Schristos else if (result == 0)
408a1ba9ba4Schristos {
409a1ba9ba4Schristos CLEARN;
410a1ba9ba4Schristos SETZ;
411a1ba9ba4Schristos }
412a1ba9ba4Schristos else
413a1ba9ba4Schristos {
414a1ba9ba4Schristos CLEARN;
415a1ba9ba4Schristos CLEARZ;
416a1ba9ba4Schristos }
417a1ba9ba4Schristos }
418a1ba9ba4Schristos
419a1ba9ba4Schristos /* Compute whether an addition of A and B, giving RESULT, overflowed. */
420a1ba9ba4Schristos
421a1ba9ba4Schristos int
AddOverflow(ARMword a,ARMword b,ARMword result)422a1ba9ba4Schristos AddOverflow (ARMword a, ARMword b, ARMword result)
423a1ba9ba4Schristos {
424a1ba9ba4Schristos return ((NEG (a) && NEG (b) && POS (result))
425a1ba9ba4Schristos || (POS (a) && POS (b) && NEG (result)));
426a1ba9ba4Schristos }
427a1ba9ba4Schristos
428a1ba9ba4Schristos /* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
429a1ba9ba4Schristos
430a1ba9ba4Schristos int
SubOverflow(ARMword a,ARMword b,ARMword result)431a1ba9ba4Schristos SubOverflow (ARMword a, ARMword b, ARMword result)
432a1ba9ba4Schristos {
433a1ba9ba4Schristos return ((NEG (a) && POS (b) && POS (result))
434a1ba9ba4Schristos || (POS (a) && NEG (b) && NEG (result)));
435a1ba9ba4Schristos }
436a1ba9ba4Schristos
437a1ba9ba4Schristos /* Assigns the C flag after an addition of a and b to give result. */
438a1ba9ba4Schristos
439a1ba9ba4Schristos void
ARMul_AddCarry(ARMul_State * state,ARMword a,ARMword b,ARMword result)440a1ba9ba4Schristos ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
441a1ba9ba4Schristos {
442a1ba9ba4Schristos ASSIGNC ((NEG (a) && NEG (b)) ||
443a1ba9ba4Schristos (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
444a1ba9ba4Schristos }
445a1ba9ba4Schristos
446a1ba9ba4Schristos /* Assigns the V flag after an addition of a and b to give result. */
447a1ba9ba4Schristos
448a1ba9ba4Schristos void
ARMul_AddOverflow(ARMul_State * state,ARMword a,ARMword b,ARMword result)449a1ba9ba4Schristos ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
450a1ba9ba4Schristos {
451a1ba9ba4Schristos ASSIGNV (AddOverflow (a, b, result));
452a1ba9ba4Schristos }
453a1ba9ba4Schristos
454a1ba9ba4Schristos /* Assigns the C flag after an subtraction of a and b to give result. */
455a1ba9ba4Schristos
456a1ba9ba4Schristos void
ARMul_SubCarry(ARMul_State * state,ARMword a,ARMword b,ARMword result)457a1ba9ba4Schristos ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
458a1ba9ba4Schristos {
459a1ba9ba4Schristos ASSIGNC ((NEG (a) && POS (b)) ||
460a1ba9ba4Schristos (NEG (a) && POS (result)) || (POS (b) && POS (result)));
461a1ba9ba4Schristos }
462a1ba9ba4Schristos
463a1ba9ba4Schristos /* Assigns the V flag after an subtraction of a and b to give result. */
464a1ba9ba4Schristos
465a1ba9ba4Schristos void
ARMul_SubOverflow(ARMul_State * state,ARMword a,ARMword b,ARMword result)466a1ba9ba4Schristos ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
467a1ba9ba4Schristos {
468a1ba9ba4Schristos ASSIGNV (SubOverflow (a, b, result));
469a1ba9ba4Schristos }
470a1ba9ba4Schristos
471a1ba9ba4Schristos static void
handle_VFP_xfer(ARMul_State * state,ARMword instr)472a1ba9ba4Schristos handle_VFP_xfer (ARMul_State * state, ARMword instr)
473a1ba9ba4Schristos {
474a1ba9ba4Schristos if (TOPBITS (28) == NV)
475a1ba9ba4Schristos {
476a1ba9ba4Schristos fprintf (stderr, "SIM: UNDEFINED VFP instruction\n");
477a1ba9ba4Schristos return;
478a1ba9ba4Schristos }
479a1ba9ba4Schristos
480a1ba9ba4Schristos if (BITS (25, 27) != 0x6)
481a1ba9ba4Schristos {
482a1ba9ba4Schristos fprintf (stderr, "SIM: ISE: VFP handler called incorrectly\n");
483a1ba9ba4Schristos return;
484a1ba9ba4Schristos }
485a1ba9ba4Schristos
486a1ba9ba4Schristos switch (BITS (20, 24))
487a1ba9ba4Schristos {
488a1ba9ba4Schristos case 0x04:
489a1ba9ba4Schristos case 0x05:
490a1ba9ba4Schristos {
491a1ba9ba4Schristos /* VMOV double precision to/from two ARM registers. */
492a1ba9ba4Schristos int vm = BITS (0, 3);
493a1ba9ba4Schristos int rt1 = BITS (12, 15);
494a1ba9ba4Schristos int rt2 = BITS (16, 19);
495a1ba9ba4Schristos
496a1ba9ba4Schristos /* FIXME: UNPREDICTABLE if rt1 == 15 or rt2 == 15. */
497a1ba9ba4Schristos if (BIT (20))
498a1ba9ba4Schristos {
499a1ba9ba4Schristos /* Transfer to ARM. */
500a1ba9ba4Schristos /* FIXME: UPPREDICTABLE if rt1 == rt2. */
501a1ba9ba4Schristos state->Reg[rt1] = VFP_dword (vm) & 0xffffffff;
502a1ba9ba4Schristos state->Reg[rt2] = VFP_dword (vm) >> 32;
503a1ba9ba4Schristos }
504a1ba9ba4Schristos else
505a1ba9ba4Schristos {
506a1ba9ba4Schristos VFP_dword (vm) = state->Reg[rt2];
507a1ba9ba4Schristos VFP_dword (vm) <<= 32;
508a1ba9ba4Schristos VFP_dword (vm) |= (state->Reg[rt1] & 0xffffffff);
509a1ba9ba4Schristos }
510a1ba9ba4Schristos return;
511a1ba9ba4Schristos }
512a1ba9ba4Schristos
513a1ba9ba4Schristos case 0x08:
514a1ba9ba4Schristos case 0x0A:
515a1ba9ba4Schristos case 0x0C:
516a1ba9ba4Schristos case 0x0E:
517a1ba9ba4Schristos {
518a1ba9ba4Schristos /* VSTM with PUW=011 or PUW=010. */
519a1ba9ba4Schristos int n = BITS (16, 19);
520a1ba9ba4Schristos int imm8 = BITS (0, 7);
521a1ba9ba4Schristos
522a1ba9ba4Schristos ARMword address = state->Reg[n];
523a1ba9ba4Schristos if (BIT (21))
524a1ba9ba4Schristos state->Reg[n] = address + (imm8 << 2);
525a1ba9ba4Schristos
526a1ba9ba4Schristos if (BIT (8))
527a1ba9ba4Schristos {
528a1ba9ba4Schristos int src = (BIT (22) << 4) | BITS (12, 15);
529a1ba9ba4Schristos imm8 >>= 1;
530a1ba9ba4Schristos while (imm8--)
531a1ba9ba4Schristos {
532a1ba9ba4Schristos if (state->bigendSig)
533a1ba9ba4Schristos {
534a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (src) >> 32);
535a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (src));
536a1ba9ba4Schristos }
537a1ba9ba4Schristos else
538a1ba9ba4Schristos {
539a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (src));
540a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (src) >> 32);
541a1ba9ba4Schristos }
542a1ba9ba4Schristos address += 8;
543a1ba9ba4Schristos src += 1;
544a1ba9ba4Schristos }
545a1ba9ba4Schristos }
546a1ba9ba4Schristos else
547a1ba9ba4Schristos {
548a1ba9ba4Schristos int src = (BITS (12, 15) << 1) | BIT (22);
549a1ba9ba4Schristos while (imm8--)
550a1ba9ba4Schristos {
551a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_uword (src));
552a1ba9ba4Schristos address += 4;
553a1ba9ba4Schristos src += 1;
554a1ba9ba4Schristos }
555a1ba9ba4Schristos }
556a1ba9ba4Schristos }
557a1ba9ba4Schristos return;
558a1ba9ba4Schristos
559a1ba9ba4Schristos case 0x10:
560a1ba9ba4Schristos case 0x14:
561a1ba9ba4Schristos case 0x18:
562a1ba9ba4Schristos case 0x1C:
563a1ba9ba4Schristos {
564a1ba9ba4Schristos /* VSTR */
565a1ba9ba4Schristos ARMword imm32 = BITS (0, 7) << 2;
566a1ba9ba4Schristos int base = state->Reg[LHSReg];
567a1ba9ba4Schristos ARMword address;
568a1ba9ba4Schristos int dest;
569a1ba9ba4Schristos
570a1ba9ba4Schristos if (LHSReg == 15)
571a1ba9ba4Schristos base = (base + 3) & ~3;
572a1ba9ba4Schristos
573a1ba9ba4Schristos address = base + (BIT (23) ? imm32 : - imm32);
574a1ba9ba4Schristos
575a1ba9ba4Schristos if (CPNum == 10)
576a1ba9ba4Schristos {
577a1ba9ba4Schristos dest = (DESTReg << 1) + BIT (22);
578a1ba9ba4Schristos
579a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_uword (dest));
580a1ba9ba4Schristos }
581a1ba9ba4Schristos else
582a1ba9ba4Schristos {
583a1ba9ba4Schristos dest = (BIT (22) << 4) + DESTReg;
584a1ba9ba4Schristos
585a1ba9ba4Schristos if (state->bigendSig)
586a1ba9ba4Schristos {
587a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (dest) >> 32);
588a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (dest));
589a1ba9ba4Schristos }
590a1ba9ba4Schristos else
591a1ba9ba4Schristos {
592a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (dest));
593a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (dest) >> 32);
594a1ba9ba4Schristos }
595a1ba9ba4Schristos }
596a1ba9ba4Schristos }
597a1ba9ba4Schristos return;
598a1ba9ba4Schristos
599a1ba9ba4Schristos case 0x12:
600a1ba9ba4Schristos case 0x16:
601a1ba9ba4Schristos if (BITS (16, 19) == 13)
602a1ba9ba4Schristos {
603a1ba9ba4Schristos /* VPUSH */
604a1ba9ba4Schristos ARMword address = state->Reg[13] - (BITS (0, 7) << 2);
605a1ba9ba4Schristos state->Reg[13] = address;
606a1ba9ba4Schristos
607a1ba9ba4Schristos if (BIT (8))
608a1ba9ba4Schristos {
609a1ba9ba4Schristos int dreg = (BIT (22) << 4) | BITS (12, 15);
610a1ba9ba4Schristos int num = BITS (0, 7) >> 1;
611a1ba9ba4Schristos while (num--)
612a1ba9ba4Schristos {
613a1ba9ba4Schristos if (state->bigendSig)
614a1ba9ba4Schristos {
615a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (dreg) >> 32);
616a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (dreg));
617a1ba9ba4Schristos }
618a1ba9ba4Schristos else
619a1ba9ba4Schristos {
620a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (dreg));
621a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (dreg) >> 32);
622a1ba9ba4Schristos }
623a1ba9ba4Schristos address += 8;
624a1ba9ba4Schristos dreg += 1;
625a1ba9ba4Schristos }
626a1ba9ba4Schristos }
627a1ba9ba4Schristos else
628a1ba9ba4Schristos {
629a1ba9ba4Schristos int sreg = (BITS (12, 15) << 1) | BIT (22);
630a1ba9ba4Schristos int num = BITS (0, 7);
631a1ba9ba4Schristos while (num--)
632a1ba9ba4Schristos {
633a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_uword (sreg));
634a1ba9ba4Schristos address += 4;
635a1ba9ba4Schristos sreg += 1;
636a1ba9ba4Schristos }
637a1ba9ba4Schristos }
638a1ba9ba4Schristos }
639a1ba9ba4Schristos else if (BITS (9, 11) != 0x5)
640a1ba9ba4Schristos break;
641a1ba9ba4Schristos else
642a1ba9ba4Schristos {
643a1ba9ba4Schristos /* VSTM PUW=101 */
644a1ba9ba4Schristos int n = BITS (16, 19);
645a1ba9ba4Schristos int imm8 = BITS (0, 7);
646a1ba9ba4Schristos ARMword address = state->Reg[n] - (imm8 << 2);
647a1ba9ba4Schristos state->Reg[n] = address;
648a1ba9ba4Schristos
649a1ba9ba4Schristos if (BIT (8))
650a1ba9ba4Schristos {
651a1ba9ba4Schristos int src = (BIT (22) << 4) | BITS (12, 15);
652a1ba9ba4Schristos
653a1ba9ba4Schristos imm8 >>= 1;
654a1ba9ba4Schristos while (imm8--)
655a1ba9ba4Schristos {
656a1ba9ba4Schristos if (state->bigendSig)
657a1ba9ba4Schristos {
658a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (src) >> 32);
659a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (src));
660a1ba9ba4Schristos }
661a1ba9ba4Schristos else
662a1ba9ba4Schristos {
663a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_dword (src));
664a1ba9ba4Schristos ARMul_StoreWordN (state, address + 4, VFP_dword (src) >> 32);
665a1ba9ba4Schristos }
666a1ba9ba4Schristos address += 8;
667a1ba9ba4Schristos src += 1;
668a1ba9ba4Schristos }
669a1ba9ba4Schristos }
670a1ba9ba4Schristos else
671a1ba9ba4Schristos {
672a1ba9ba4Schristos int src = (BITS (12, 15) << 1) | BIT (22);
673a1ba9ba4Schristos
674a1ba9ba4Schristos while (imm8--)
675a1ba9ba4Schristos {
676a1ba9ba4Schristos ARMul_StoreWordN (state, address, VFP_uword (src));
677a1ba9ba4Schristos address += 4;
678a1ba9ba4Schristos src += 1;
679a1ba9ba4Schristos }
680a1ba9ba4Schristos }
681a1ba9ba4Schristos }
682a1ba9ba4Schristos return;
683a1ba9ba4Schristos
684a1ba9ba4Schristos case 0x13:
685a1ba9ba4Schristos case 0x17:
686a1ba9ba4Schristos /* VLDM PUW=101 */
687a1ba9ba4Schristos case 0x09:
688a1ba9ba4Schristos case 0x0D:
689a1ba9ba4Schristos /* VLDM PUW=010 */
690a1ba9ba4Schristos {
691a1ba9ba4Schristos int n = BITS (16, 19);
692a1ba9ba4Schristos int imm8 = BITS (0, 7);
693a1ba9ba4Schristos
694a1ba9ba4Schristos ARMword address = state->Reg[n];
695a1ba9ba4Schristos if (BIT (23) == 0)
696a1ba9ba4Schristos address -= imm8 << 2;
697a1ba9ba4Schristos if (BIT (21))
698a1ba9ba4Schristos state->Reg[n] = BIT (23) ? address + (imm8 << 2) : address;
699a1ba9ba4Schristos
700a1ba9ba4Schristos if (BIT (8))
701a1ba9ba4Schristos {
702a1ba9ba4Schristos int dest = (BIT (22) << 4) | BITS (12, 15);
703a1ba9ba4Schristos imm8 >>= 1;
704a1ba9ba4Schristos while (imm8--)
705a1ba9ba4Schristos {
706a1ba9ba4Schristos if (state->bigendSig)
707a1ba9ba4Schristos {
708a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address);
709a1ba9ba4Schristos VFP_dword (dest) <<= 32;
710a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address + 4);
711a1ba9ba4Schristos }
712a1ba9ba4Schristos else
713a1ba9ba4Schristos {
714a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address + 4);
715a1ba9ba4Schristos VFP_dword (dest) <<= 32;
716a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address);
717a1ba9ba4Schristos }
718a1ba9ba4Schristos
719a1ba9ba4Schristos if (trace)
720a1ba9ba4Schristos fprintf (stderr, " VFP: VLDM: D%d = %g\n", dest, VFP_dval (dest));
721a1ba9ba4Schristos
722a1ba9ba4Schristos address += 8;
723a1ba9ba4Schristos dest += 1;
724a1ba9ba4Schristos }
725a1ba9ba4Schristos }
726a1ba9ba4Schristos else
727a1ba9ba4Schristos {
728a1ba9ba4Schristos int dest = (BITS (12, 15) << 1) | BIT (22);
729a1ba9ba4Schristos
730a1ba9ba4Schristos while (imm8--)
731a1ba9ba4Schristos {
732a1ba9ba4Schristos VFP_uword (dest) = ARMul_LoadWordN (state, address);
733a1ba9ba4Schristos address += 4;
734a1ba9ba4Schristos dest += 1;
735a1ba9ba4Schristos }
736a1ba9ba4Schristos }
737a1ba9ba4Schristos }
738a1ba9ba4Schristos return;
739a1ba9ba4Schristos
740a1ba9ba4Schristos case 0x0B:
741a1ba9ba4Schristos case 0x0F:
742a1ba9ba4Schristos if (BITS (16, 19) == 13)
743a1ba9ba4Schristos {
744a1ba9ba4Schristos /* VPOP */
745a1ba9ba4Schristos ARMword address = state->Reg[13];
746a1ba9ba4Schristos state->Reg[13] = address + (BITS (0, 7) << 2);
747a1ba9ba4Schristos
748a1ba9ba4Schristos if (BIT (8))
749a1ba9ba4Schristos {
750a1ba9ba4Schristos int dest = (BIT (22) << 4) | BITS (12, 15);
751a1ba9ba4Schristos int num = BITS (0, 7) >> 1;
752a1ba9ba4Schristos
753a1ba9ba4Schristos while (num--)
754a1ba9ba4Schristos {
755a1ba9ba4Schristos if (state->bigendSig)
756a1ba9ba4Schristos {
757a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address);
758a1ba9ba4Schristos VFP_dword (dest) <<= 32;
759a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address + 4);
760a1ba9ba4Schristos }
761a1ba9ba4Schristos else
762a1ba9ba4Schristos {
763a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address + 4);
764a1ba9ba4Schristos VFP_dword (dest) <<= 32;
765a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address);
766a1ba9ba4Schristos }
767a1ba9ba4Schristos
768a1ba9ba4Schristos if (trace)
769a1ba9ba4Schristos fprintf (stderr, " VFP: VPOP: D%d = %g\n", dest, VFP_dval (dest));
770a1ba9ba4Schristos
771a1ba9ba4Schristos address += 8;
772a1ba9ba4Schristos dest += 1;
773a1ba9ba4Schristos }
774a1ba9ba4Schristos }
775a1ba9ba4Schristos else
776a1ba9ba4Schristos {
777a1ba9ba4Schristos int sreg = (BITS (12, 15) << 1) | BIT (22);
778a1ba9ba4Schristos int num = BITS (0, 7);
779a1ba9ba4Schristos
780a1ba9ba4Schristos while (num--)
781a1ba9ba4Schristos {
782a1ba9ba4Schristos VFP_uword (sreg) = ARMul_LoadWordN (state, address);
783a1ba9ba4Schristos address += 4;
784a1ba9ba4Schristos sreg += 1;
785a1ba9ba4Schristos }
786a1ba9ba4Schristos }
787a1ba9ba4Schristos }
788a1ba9ba4Schristos else if (BITS (9, 11) != 0x5)
789a1ba9ba4Schristos break;
790a1ba9ba4Schristos else
791a1ba9ba4Schristos {
792a1ba9ba4Schristos /* VLDM PUW=011 */
793a1ba9ba4Schristos int n = BITS (16, 19);
794a1ba9ba4Schristos int imm8 = BITS (0, 7);
795a1ba9ba4Schristos ARMword address = state->Reg[n];
796a1ba9ba4Schristos state->Reg[n] += imm8 << 2;
797a1ba9ba4Schristos
798a1ba9ba4Schristos if (BIT (8))
799a1ba9ba4Schristos {
800a1ba9ba4Schristos int dest = (BIT (22) << 4) | BITS (12, 15);
801a1ba9ba4Schristos
802a1ba9ba4Schristos imm8 >>= 1;
803a1ba9ba4Schristos while (imm8--)
804a1ba9ba4Schristos {
805a1ba9ba4Schristos if (state->bigendSig)
806a1ba9ba4Schristos {
807a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address);
808a1ba9ba4Schristos VFP_dword (dest) <<= 32;
809a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address + 4);
810a1ba9ba4Schristos }
811a1ba9ba4Schristos else
812a1ba9ba4Schristos {
813a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address + 4);
814a1ba9ba4Schristos VFP_dword (dest) <<= 32;
815a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address);
816a1ba9ba4Schristos }
817a1ba9ba4Schristos
818a1ba9ba4Schristos if (trace)
819a1ba9ba4Schristos fprintf (stderr, " VFP: VLDM: D%d = %g\n", dest, VFP_dval (dest));
820a1ba9ba4Schristos
821a1ba9ba4Schristos address += 8;
822a1ba9ba4Schristos dest += 1;
823a1ba9ba4Schristos }
824a1ba9ba4Schristos }
825a1ba9ba4Schristos else
826a1ba9ba4Schristos {
827a1ba9ba4Schristos int dest = (BITS (12, 15) << 1) | BIT (22);
828a1ba9ba4Schristos while (imm8--)
829a1ba9ba4Schristos {
830a1ba9ba4Schristos VFP_uword (dest) = ARMul_LoadWordN (state, address);
831a1ba9ba4Schristos address += 4;
832a1ba9ba4Schristos dest += 1;
833a1ba9ba4Schristos }
834a1ba9ba4Schristos }
835a1ba9ba4Schristos }
836a1ba9ba4Schristos return;
837a1ba9ba4Schristos
838a1ba9ba4Schristos case 0x11:
839a1ba9ba4Schristos case 0x15:
840a1ba9ba4Schristos case 0x19:
841a1ba9ba4Schristos case 0x1D:
842a1ba9ba4Schristos {
843a1ba9ba4Schristos /* VLDR */
844a1ba9ba4Schristos ARMword imm32 = BITS (0, 7) << 2;
845a1ba9ba4Schristos int base = state->Reg[LHSReg];
846a1ba9ba4Schristos ARMword address;
847a1ba9ba4Schristos int dest;
848a1ba9ba4Schristos
849a1ba9ba4Schristos if (LHSReg == 15)
850a1ba9ba4Schristos base = (base + 3) & ~3;
851a1ba9ba4Schristos
852a1ba9ba4Schristos address = base + (BIT (23) ? imm32 : - imm32);
853a1ba9ba4Schristos
854a1ba9ba4Schristos if (CPNum == 10)
855a1ba9ba4Schristos {
856a1ba9ba4Schristos dest = (DESTReg << 1) + BIT (22);
857a1ba9ba4Schristos
858a1ba9ba4Schristos VFP_uword (dest) = ARMul_LoadWordN (state, address);
859a1ba9ba4Schristos }
860a1ba9ba4Schristos else
861a1ba9ba4Schristos {
862a1ba9ba4Schristos dest = (BIT (22) << 4) + DESTReg;
863a1ba9ba4Schristos
864a1ba9ba4Schristos if (state->bigendSig)
865a1ba9ba4Schristos {
866a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address);
867a1ba9ba4Schristos VFP_dword (dest) <<= 32;
868a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address + 4);
869a1ba9ba4Schristos }
870a1ba9ba4Schristos else
871a1ba9ba4Schristos {
872a1ba9ba4Schristos VFP_dword (dest) = ARMul_LoadWordN (state, address + 4);
873a1ba9ba4Schristos VFP_dword (dest) <<= 32;
874a1ba9ba4Schristos VFP_dword (dest) |= ARMul_LoadWordN (state, address);
875a1ba9ba4Schristos }
876a1ba9ba4Schristos
877a1ba9ba4Schristos if (trace)
878a1ba9ba4Schristos fprintf (stderr, " VFP: VLDR: D%d = %g\n", dest, VFP_dval (dest));
879a1ba9ba4Schristos }
880a1ba9ba4Schristos }
881a1ba9ba4Schristos return;
882a1ba9ba4Schristos }
883a1ba9ba4Schristos
884a1ba9ba4Schristos fprintf (stderr, "SIM: VFP: Unimplemented: %0x\n", BITS (20, 24));
885a1ba9ba4Schristos }
886a1ba9ba4Schristos
887a1ba9ba4Schristos /* This function does the work of generating the addresses used in an
888a1ba9ba4Schristos LDC instruction. The code here is always post-indexed, it's up to the
889a1ba9ba4Schristos caller to get the input address correct and to handle base register
890a1ba9ba4Schristos modification. It also handles the Busy-Waiting. */
891a1ba9ba4Schristos
892a1ba9ba4Schristos void
ARMul_LDC(ARMul_State * state,ARMword instr,ARMword address)893a1ba9ba4Schristos ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
894a1ba9ba4Schristos {
895a1ba9ba4Schristos unsigned cpab;
896a1ba9ba4Schristos ARMword data;
897a1ba9ba4Schristos
898a1ba9ba4Schristos if (CPNum == 10 || CPNum == 11)
899a1ba9ba4Schristos {
900a1ba9ba4Schristos handle_VFP_xfer (state, instr);
901a1ba9ba4Schristos return;
902a1ba9ba4Schristos }
903a1ba9ba4Schristos
904a1ba9ba4Schristos UNDEF_LSCPCBaseWb;
905a1ba9ba4Schristos
906a1ba9ba4Schristos if (! CP_ACCESS_ALLOWED (state, CPNum))
907a1ba9ba4Schristos {
908a1ba9ba4Schristos ARMul_UndefInstr (state, instr);
909a1ba9ba4Schristos return;
910a1ba9ba4Schristos }
911a1ba9ba4Schristos
912a1ba9ba4Schristos if (ADDREXCEPT (address))
913a1ba9ba4Schristos INTERNALABORT (address);
914a1ba9ba4Schristos
915a1ba9ba4Schristos cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
916a1ba9ba4Schristos while (cpab == ARMul_BUSY)
917a1ba9ba4Schristos {
918a1ba9ba4Schristos ARMul_Icycles (state, 1, 0);
919a1ba9ba4Schristos
920a1ba9ba4Schristos if (IntPending (state))
921a1ba9ba4Schristos {
922a1ba9ba4Schristos cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
923a1ba9ba4Schristos return;
924a1ba9ba4Schristos }
925a1ba9ba4Schristos else
926a1ba9ba4Schristos cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
927a1ba9ba4Schristos }
928a1ba9ba4Schristos if (cpab == ARMul_CANT)
929a1ba9ba4Schristos {
930a1ba9ba4Schristos CPTAKEABORT;
931a1ba9ba4Schristos return;
932a1ba9ba4Schristos }
933a1ba9ba4Schristos
934a1ba9ba4Schristos cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
935a1ba9ba4Schristos data = ARMul_LoadWordN (state, address);
936a1ba9ba4Schristos BUSUSEDINCPCN;
937a1ba9ba4Schristos
938a1ba9ba4Schristos if (BIT (21))
939a1ba9ba4Schristos LSBase = state->Base;
940a1ba9ba4Schristos cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
941a1ba9ba4Schristos
942a1ba9ba4Schristos while (cpab == ARMul_INC)
943a1ba9ba4Schristos {
944a1ba9ba4Schristos address += 4;
945a1ba9ba4Schristos data = ARMul_LoadWordN (state, address);
946a1ba9ba4Schristos cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
947a1ba9ba4Schristos }
948a1ba9ba4Schristos
949a1ba9ba4Schristos if (state->abortSig || state->Aborted)
950a1ba9ba4Schristos TAKEABORT;
951a1ba9ba4Schristos }
952a1ba9ba4Schristos
953a1ba9ba4Schristos /* This function does the work of generating the addresses used in an
954a1ba9ba4Schristos STC instruction. The code here is always post-indexed, it's up to the
955a1ba9ba4Schristos caller to get the input address correct and to handle base register
956a1ba9ba4Schristos modification. It also handles the Busy-Waiting. */
957a1ba9ba4Schristos
958a1ba9ba4Schristos void
ARMul_STC(ARMul_State * state,ARMword instr,ARMword address)959a1ba9ba4Schristos ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
960a1ba9ba4Schristos {
961a1ba9ba4Schristos unsigned cpab;
962a1ba9ba4Schristos ARMword data;
963a1ba9ba4Schristos
964a1ba9ba4Schristos if (CPNum == 10 || CPNum == 11)
965a1ba9ba4Schristos {
966a1ba9ba4Schristos handle_VFP_xfer (state, instr);
967a1ba9ba4Schristos return;
968a1ba9ba4Schristos }
969a1ba9ba4Schristos
970a1ba9ba4Schristos UNDEF_LSCPCBaseWb;
971a1ba9ba4Schristos
972a1ba9ba4Schristos if (! CP_ACCESS_ALLOWED (state, CPNum))
973a1ba9ba4Schristos {
974a1ba9ba4Schristos ARMul_UndefInstr (state, instr);
975a1ba9ba4Schristos return;
976a1ba9ba4Schristos }
977a1ba9ba4Schristos
978a1ba9ba4Schristos if (ADDREXCEPT (address) || VECTORACCESS (address))
979a1ba9ba4Schristos INTERNALABORT (address);
980a1ba9ba4Schristos
981a1ba9ba4Schristos cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
982a1ba9ba4Schristos while (cpab == ARMul_BUSY)
983a1ba9ba4Schristos {
984a1ba9ba4Schristos ARMul_Icycles (state, 1, 0);
985a1ba9ba4Schristos if (IntPending (state))
986a1ba9ba4Schristos {
987a1ba9ba4Schristos cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
988a1ba9ba4Schristos return;
989a1ba9ba4Schristos }
990a1ba9ba4Schristos else
991a1ba9ba4Schristos cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
992a1ba9ba4Schristos }
993a1ba9ba4Schristos
994a1ba9ba4Schristos if (cpab == ARMul_CANT)
995a1ba9ba4Schristos {
996a1ba9ba4Schristos CPTAKEABORT;
997a1ba9ba4Schristos return;
998a1ba9ba4Schristos }
999a1ba9ba4Schristos #ifndef MODE32
1000a1ba9ba4Schristos if (ADDREXCEPT (address) || VECTORACCESS (address))
1001a1ba9ba4Schristos INTERNALABORT (address);
1002a1ba9ba4Schristos #endif
1003a1ba9ba4Schristos BUSUSEDINCPCN;
1004a1ba9ba4Schristos if (BIT (21))
1005a1ba9ba4Schristos LSBase = state->Base;
1006a1ba9ba4Schristos cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
1007a1ba9ba4Schristos ARMul_StoreWordN (state, address, data);
1008a1ba9ba4Schristos
1009a1ba9ba4Schristos while (cpab == ARMul_INC)
1010a1ba9ba4Schristos {
1011a1ba9ba4Schristos address += 4;
1012a1ba9ba4Schristos cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
1013a1ba9ba4Schristos ARMul_StoreWordN (state, address, data);
1014a1ba9ba4Schristos }
1015a1ba9ba4Schristos
1016a1ba9ba4Schristos if (state->abortSig || state->Aborted)
1017a1ba9ba4Schristos TAKEABORT;
1018a1ba9ba4Schristos }
1019a1ba9ba4Schristos
1020a1ba9ba4Schristos /* This function does the Busy-Waiting for an MCR instruction. */
1021a1ba9ba4Schristos
1022a1ba9ba4Schristos void
ARMul_MCR(ARMul_State * state,ARMword instr,ARMword source)1023a1ba9ba4Schristos ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
1024a1ba9ba4Schristos {
1025a1ba9ba4Schristos unsigned cpab;
1026a1ba9ba4Schristos
1027a1ba9ba4Schristos if (! CP_ACCESS_ALLOWED (state, CPNum))
1028a1ba9ba4Schristos {
1029a1ba9ba4Schristos ARMul_UndefInstr (state, instr);
1030a1ba9ba4Schristos return;
1031a1ba9ba4Schristos }
1032a1ba9ba4Schristos
1033a1ba9ba4Schristos cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
1034a1ba9ba4Schristos
1035a1ba9ba4Schristos while (cpab == ARMul_BUSY)
1036a1ba9ba4Schristos {
1037a1ba9ba4Schristos ARMul_Icycles (state, 1, 0);
1038a1ba9ba4Schristos
1039a1ba9ba4Schristos if (IntPending (state))
1040a1ba9ba4Schristos {
1041a1ba9ba4Schristos cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
1042a1ba9ba4Schristos return;
1043a1ba9ba4Schristos }
1044a1ba9ba4Schristos else
1045a1ba9ba4Schristos cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
1046a1ba9ba4Schristos }
1047a1ba9ba4Schristos
1048a1ba9ba4Schristos if (cpab == ARMul_CANT)
1049a1ba9ba4Schristos ARMul_Abort (state, ARMul_UndefinedInstrV);
1050a1ba9ba4Schristos else
1051a1ba9ba4Schristos {
1052a1ba9ba4Schristos BUSUSEDINCPCN;
1053a1ba9ba4Schristos ARMul_Ccycles (state, 1, 0);
1054a1ba9ba4Schristos }
1055a1ba9ba4Schristos }
1056a1ba9ba4Schristos
1057a1ba9ba4Schristos /* This function does the Busy-Waiting for an MRC instruction. */
1058a1ba9ba4Schristos
1059a1ba9ba4Schristos ARMword
ARMul_MRC(ARMul_State * state,ARMword instr)1060a1ba9ba4Schristos ARMul_MRC (ARMul_State * state, ARMword instr)
1061a1ba9ba4Schristos {
1062a1ba9ba4Schristos unsigned cpab;
1063a1ba9ba4Schristos ARMword result = 0;
1064a1ba9ba4Schristos
1065a1ba9ba4Schristos if (! CP_ACCESS_ALLOWED (state, CPNum))
1066a1ba9ba4Schristos {
1067a1ba9ba4Schristos ARMul_UndefInstr (state, instr);
1068a1ba9ba4Schristos return result;
1069a1ba9ba4Schristos }
1070a1ba9ba4Schristos
1071a1ba9ba4Schristos cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
1072a1ba9ba4Schristos while (cpab == ARMul_BUSY)
1073a1ba9ba4Schristos {
1074a1ba9ba4Schristos ARMul_Icycles (state, 1, 0);
1075a1ba9ba4Schristos if (IntPending (state))
1076a1ba9ba4Schristos {
1077a1ba9ba4Schristos cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
1078a1ba9ba4Schristos return (0);
1079a1ba9ba4Schristos }
1080a1ba9ba4Schristos else
1081a1ba9ba4Schristos cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
1082a1ba9ba4Schristos }
1083a1ba9ba4Schristos if (cpab == ARMul_CANT)
1084a1ba9ba4Schristos {
1085a1ba9ba4Schristos ARMul_Abort (state, ARMul_UndefinedInstrV);
1086a1ba9ba4Schristos /* Parent will destroy the flags otherwise. */
1087a1ba9ba4Schristos result = ECC;
1088a1ba9ba4Schristos }
1089a1ba9ba4Schristos else
1090a1ba9ba4Schristos {
1091a1ba9ba4Schristos BUSUSEDINCPCN;
1092a1ba9ba4Schristos ARMul_Ccycles (state, 1, 0);
1093a1ba9ba4Schristos ARMul_Icycles (state, 1, 0);
1094a1ba9ba4Schristos }
1095a1ba9ba4Schristos
1096a1ba9ba4Schristos return result;
1097a1ba9ba4Schristos }
1098a1ba9ba4Schristos
1099a1ba9ba4Schristos static void
handle_VFP_op(ARMul_State * state,ARMword instr)1100a1ba9ba4Schristos handle_VFP_op (ARMul_State * state, ARMword instr)
1101a1ba9ba4Schristos {
1102a1ba9ba4Schristos int dest;
1103a1ba9ba4Schristos int srcN;
1104a1ba9ba4Schristos int srcM;
1105a1ba9ba4Schristos
1106a1ba9ba4Schristos if (BITS (9, 11) != 0x5 || BIT (4) != 0)
1107a1ba9ba4Schristos {
1108a1ba9ba4Schristos fprintf (stderr, "SIM: VFP: Unimplemented: Float op: %08x\n", BITS (0,31));
1109a1ba9ba4Schristos return;
1110a1ba9ba4Schristos }
1111a1ba9ba4Schristos
1112a1ba9ba4Schristos if (BIT (8))
1113a1ba9ba4Schristos {
1114a1ba9ba4Schristos dest = BITS(12,15) + (BIT (22) << 4);
1115a1ba9ba4Schristos srcN = LHSReg + (BIT (7) << 4);
1116a1ba9ba4Schristos srcM = BITS (0,3) + (BIT (5) << 4);
1117a1ba9ba4Schristos }
1118a1ba9ba4Schristos else
1119a1ba9ba4Schristos {
1120a1ba9ba4Schristos dest = (BITS(12,15) << 1) + BIT (22);
1121a1ba9ba4Schristos srcN = (LHSReg << 1) + BIT (7);
1122a1ba9ba4Schristos srcM = (BITS (0,3) << 1) + BIT (5);
1123a1ba9ba4Schristos }
1124a1ba9ba4Schristos
1125a1ba9ba4Schristos switch (BITS (20, 27))
1126a1ba9ba4Schristos {
1127a1ba9ba4Schristos case 0xE0:
1128a1ba9ba4Schristos case 0xE4:
1129a1ba9ba4Schristos /* VMLA VMLS */
1130a1ba9ba4Schristos if (BIT (8))
1131a1ba9ba4Schristos {
1132a1ba9ba4Schristos ARMdval val = VFP_dval (srcN) * VFP_dval (srcM);
1133a1ba9ba4Schristos
1134a1ba9ba4Schristos if (BIT (6))
1135a1ba9ba4Schristos {
1136a1ba9ba4Schristos if (trace)
1137a1ba9ba4Schristos fprintf (stderr, " VFP: VMLS: %g = %g - %g * %g\n",
1138a1ba9ba4Schristos VFP_dval (dest) - val,
1139a1ba9ba4Schristos VFP_dval (dest), VFP_dval (srcN), VFP_dval (srcM));
1140a1ba9ba4Schristos VFP_dval (dest) -= val;
1141a1ba9ba4Schristos }
1142a1ba9ba4Schristos else
1143a1ba9ba4Schristos {
1144a1ba9ba4Schristos if (trace)
1145a1ba9ba4Schristos fprintf (stderr, " VFP: VMLA: %g = %g + %g * %g\n",
1146a1ba9ba4Schristos VFP_dval (dest) + val,
1147a1ba9ba4Schristos VFP_dval (dest), VFP_dval (srcN), VFP_dval (srcM));
1148a1ba9ba4Schristos VFP_dval (dest) += val;
1149a1ba9ba4Schristos }
1150a1ba9ba4Schristos }
1151a1ba9ba4Schristos else
1152a1ba9ba4Schristos {
1153a1ba9ba4Schristos ARMfval val = VFP_fval (srcN) * VFP_fval (srcM);
1154a1ba9ba4Schristos
1155a1ba9ba4Schristos if (BIT (6))
1156a1ba9ba4Schristos {
1157a1ba9ba4Schristos if (trace)
1158a1ba9ba4Schristos fprintf (stderr, " VFP: VMLS: %g = %g - %g * %g\n",
1159a1ba9ba4Schristos VFP_fval (dest) - val,
1160a1ba9ba4Schristos VFP_fval (dest), VFP_fval (srcN), VFP_fval (srcM));
1161a1ba9ba4Schristos VFP_fval (dest) -= val;
1162a1ba9ba4Schristos }
1163a1ba9ba4Schristos else
1164a1ba9ba4Schristos {
1165a1ba9ba4Schristos if (trace)
1166a1ba9ba4Schristos fprintf (stderr, " VFP: VMLA: %g = %g + %g * %g\n",
1167a1ba9ba4Schristos VFP_fval (dest) + val,
1168a1ba9ba4Schristos VFP_fval (dest), VFP_fval (srcN), VFP_fval (srcM));
1169a1ba9ba4Schristos VFP_fval (dest) += val;
1170a1ba9ba4Schristos }
1171a1ba9ba4Schristos }
1172a1ba9ba4Schristos return;
1173a1ba9ba4Schristos
1174a1ba9ba4Schristos case 0xE1:
1175a1ba9ba4Schristos case 0xE5:
1176a1ba9ba4Schristos if (BIT (8))
1177a1ba9ba4Schristos {
1178a1ba9ba4Schristos ARMdval product = VFP_dval (srcN) * VFP_dval (srcM);
1179a1ba9ba4Schristos
1180a1ba9ba4Schristos if (BIT (6))
1181a1ba9ba4Schristos {
1182a1ba9ba4Schristos /* VNMLA */
1183a1ba9ba4Schristos if (trace)
1184a1ba9ba4Schristos fprintf (stderr, " VFP: VNMLA: %g = -(%g + (%g * %g))\n",
1185a1ba9ba4Schristos -(VFP_dval (dest) + product),
1186a1ba9ba4Schristos VFP_dval (dest), VFP_dval (srcN), VFP_dval (srcM));
1187a1ba9ba4Schristos VFP_dval (dest) = -(product + VFP_dval (dest));
1188a1ba9ba4Schristos }
1189a1ba9ba4Schristos else
1190a1ba9ba4Schristos {
1191a1ba9ba4Schristos /* VNMLS */
1192a1ba9ba4Schristos if (trace)
1193a1ba9ba4Schristos fprintf (stderr, " VFP: VNMLS: %g = -(%g + (%g * %g))\n",
1194a1ba9ba4Schristos -(VFP_dval (dest) + product),
1195a1ba9ba4Schristos VFP_dval (dest), VFP_dval (srcN), VFP_dval (srcM));
1196a1ba9ba4Schristos VFP_dval (dest) = product - VFP_dval (dest);
1197a1ba9ba4Schristos }
1198a1ba9ba4Schristos }
1199a1ba9ba4Schristos else
1200a1ba9ba4Schristos {
1201a1ba9ba4Schristos ARMfval product = VFP_fval (srcN) * VFP_fval (srcM);
1202a1ba9ba4Schristos
1203a1ba9ba4Schristos if (BIT (6))
1204a1ba9ba4Schristos /* VNMLA */
1205a1ba9ba4Schristos VFP_fval (dest) = -(product + VFP_fval (dest));
1206a1ba9ba4Schristos else
1207a1ba9ba4Schristos /* VNMLS */
1208a1ba9ba4Schristos VFP_fval (dest) = product - VFP_fval (dest);
1209a1ba9ba4Schristos }
1210a1ba9ba4Schristos return;
1211a1ba9ba4Schristos
1212a1ba9ba4Schristos case 0xE2:
1213a1ba9ba4Schristos case 0xE6:
1214a1ba9ba4Schristos if (BIT (8))
1215a1ba9ba4Schristos {
1216a1ba9ba4Schristos ARMdval product = VFP_dval (srcN) * VFP_dval (srcM);
1217a1ba9ba4Schristos
1218a1ba9ba4Schristos if (BIT (6))
1219a1ba9ba4Schristos {
1220a1ba9ba4Schristos if (trace)
1221a1ba9ba4Schristos fprintf (stderr, " VFP: VMUL: %g = %g * %g\n",
1222a1ba9ba4Schristos - product, VFP_dval (srcN), VFP_dval (srcM));
1223a1ba9ba4Schristos /* VNMUL */
1224a1ba9ba4Schristos VFP_dval (dest) = - product;
1225a1ba9ba4Schristos }
1226a1ba9ba4Schristos else
1227a1ba9ba4Schristos {
1228a1ba9ba4Schristos if (trace)
1229a1ba9ba4Schristos fprintf (stderr, " VFP: VMUL: %g = %g * %g\n",
1230a1ba9ba4Schristos product, VFP_dval (srcN), VFP_dval (srcM));
1231a1ba9ba4Schristos /* VMUL */
1232a1ba9ba4Schristos VFP_dval (dest) = product;
1233a1ba9ba4Schristos }
1234a1ba9ba4Schristos }
1235a1ba9ba4Schristos else
1236a1ba9ba4Schristos {
1237a1ba9ba4Schristos ARMfval product = VFP_fval (srcN) * VFP_fval (srcM);
1238a1ba9ba4Schristos
1239a1ba9ba4Schristos if (BIT (6))
1240a1ba9ba4Schristos {
1241a1ba9ba4Schristos if (trace)
1242a1ba9ba4Schristos fprintf (stderr, " VFP: VNMUL: %g = %g * %g\n",
1243a1ba9ba4Schristos - product, VFP_fval (srcN), VFP_fval (srcM));
1244a1ba9ba4Schristos
1245a1ba9ba4Schristos VFP_fval (dest) = - product;
1246a1ba9ba4Schristos }
1247a1ba9ba4Schristos else
1248a1ba9ba4Schristos {
1249a1ba9ba4Schristos if (trace)
1250a1ba9ba4Schristos fprintf (stderr, " VFP: VMUL: %g = %g * %g\n",
1251a1ba9ba4Schristos product, VFP_fval (srcN), VFP_fval (srcM));
1252a1ba9ba4Schristos
1253a1ba9ba4Schristos VFP_fval (dest) = product;
1254a1ba9ba4Schristos }
1255a1ba9ba4Schristos }
1256a1ba9ba4Schristos return;
1257a1ba9ba4Schristos
1258a1ba9ba4Schristos case 0xE3:
1259a1ba9ba4Schristos case 0xE7:
1260a1ba9ba4Schristos if (BIT (6) == 0)
1261a1ba9ba4Schristos {
1262a1ba9ba4Schristos /* VADD */
1263a1ba9ba4Schristos if (BIT(8))
1264a1ba9ba4Schristos {
1265a1ba9ba4Schristos if (trace)
1266a1ba9ba4Schristos fprintf (stderr, " VFP: VADD %g = %g + %g\n",
1267a1ba9ba4Schristos VFP_dval (srcN) + VFP_dval (srcM),
1268a1ba9ba4Schristos VFP_dval (srcN),
1269a1ba9ba4Schristos VFP_dval (srcM));
1270a1ba9ba4Schristos VFP_dval (dest) = VFP_dval (srcN) + VFP_dval (srcM);
1271a1ba9ba4Schristos }
1272a1ba9ba4Schristos else
1273a1ba9ba4Schristos VFP_fval (dest) = VFP_fval (srcN) + VFP_fval (srcM);
1274a1ba9ba4Schristos
1275a1ba9ba4Schristos }
1276a1ba9ba4Schristos else
1277a1ba9ba4Schristos {
1278a1ba9ba4Schristos /* VSUB */
1279a1ba9ba4Schristos if (BIT(8))
1280a1ba9ba4Schristos {
1281a1ba9ba4Schristos if (trace)
1282a1ba9ba4Schristos fprintf (stderr, " VFP: VSUB %g = %g - %g\n",
1283a1ba9ba4Schristos VFP_dval (srcN) - VFP_dval (srcM),
1284a1ba9ba4Schristos VFP_dval (srcN),
1285a1ba9ba4Schristos VFP_dval (srcM));
1286a1ba9ba4Schristos VFP_dval (dest) = VFP_dval (srcN) - VFP_dval (srcM);
1287a1ba9ba4Schristos }
1288a1ba9ba4Schristos else
1289a1ba9ba4Schristos VFP_fval (dest) = VFP_fval (srcN) - VFP_fval (srcM);
1290a1ba9ba4Schristos }
1291a1ba9ba4Schristos return;
1292a1ba9ba4Schristos
1293a1ba9ba4Schristos case 0xE8:
1294a1ba9ba4Schristos case 0xEC:
1295a1ba9ba4Schristos if (BIT (6) == 1)
1296a1ba9ba4Schristos break;
1297a1ba9ba4Schristos
1298a1ba9ba4Schristos /* VDIV */
1299a1ba9ba4Schristos if (BIT (8))
1300a1ba9ba4Schristos {
1301a1ba9ba4Schristos ARMdval res = VFP_dval (srcN) / VFP_dval (srcM);
1302a1ba9ba4Schristos if (trace)
1303a1ba9ba4Schristos fprintf (stderr, " VFP: VDIV (64bit): %g = %g / %g\n",
1304a1ba9ba4Schristos res, VFP_dval (srcN), VFP_dval (srcM));
1305a1ba9ba4Schristos VFP_dval (dest) = res;
1306a1ba9ba4Schristos }
1307a1ba9ba4Schristos else
1308a1ba9ba4Schristos {
1309a1ba9ba4Schristos if (trace)
1310a1ba9ba4Schristos fprintf (stderr, " VFP: VDIV: %g = %g / %g\n",
1311a1ba9ba4Schristos VFP_fval (srcN) / VFP_fval (srcM),
1312a1ba9ba4Schristos VFP_fval (srcN), VFP_fval (srcM));
1313a1ba9ba4Schristos
1314a1ba9ba4Schristos VFP_fval (dest) = VFP_fval (srcN) / VFP_fval (srcM);
1315a1ba9ba4Schristos }
1316a1ba9ba4Schristos return;
1317a1ba9ba4Schristos
1318a1ba9ba4Schristos case 0xEB:
1319a1ba9ba4Schristos case 0xEF:
1320a1ba9ba4Schristos if (BIT (6) != 1)
1321a1ba9ba4Schristos break;
1322a1ba9ba4Schristos
1323a1ba9ba4Schristos switch (BITS (16, 19))
1324a1ba9ba4Schristos {
1325a1ba9ba4Schristos case 0x0:
1326a1ba9ba4Schristos if (BIT (7) == 0)
1327a1ba9ba4Schristos {
1328a1ba9ba4Schristos if (BIT (8))
1329a1ba9ba4Schristos {
1330a1ba9ba4Schristos /* VMOV.F64 <Dd>, <Dm>. */
1331a1ba9ba4Schristos VFP_dval (dest) = VFP_dval (srcM);
1332a1ba9ba4Schristos if (trace)
1333a1ba9ba4Schristos fprintf (stderr, " VFP: VMOV d%d, d%d: %g\n", dest, srcM, VFP_dval (srcM));
1334a1ba9ba4Schristos }
1335a1ba9ba4Schristos else
1336a1ba9ba4Schristos {
1337a1ba9ba4Schristos /* VMOV.F32 <Sd>, <Sm>. */
1338a1ba9ba4Schristos VFP_fval (dest) = VFP_fval (srcM);
1339a1ba9ba4Schristos if (trace)
1340a1ba9ba4Schristos fprintf (stderr, " VFP: VMOV s%d, s%d: %g\n", dest, srcM, VFP_fval (srcM));
1341a1ba9ba4Schristos }
1342a1ba9ba4Schristos }
1343a1ba9ba4Schristos else
1344a1ba9ba4Schristos {
1345a1ba9ba4Schristos /* VABS */
1346a1ba9ba4Schristos if (BIT (8))
1347a1ba9ba4Schristos {
1348a1ba9ba4Schristos ARMdval src = VFP_dval (srcM);
1349a1ba9ba4Schristos
1350a1ba9ba4Schristos VFP_dval (dest) = fabs (src);
1351a1ba9ba4Schristos if (trace)
1352a1ba9ba4Schristos fprintf (stderr, " VFP: VABS (%g) = %g\n", src, VFP_dval (dest));
1353a1ba9ba4Schristos }
1354a1ba9ba4Schristos else
1355a1ba9ba4Schristos {
1356a1ba9ba4Schristos ARMfval src = VFP_fval (srcM);
1357a1ba9ba4Schristos
1358a1ba9ba4Schristos VFP_fval (dest) = fabsf (src);
1359a1ba9ba4Schristos if (trace)
1360a1ba9ba4Schristos fprintf (stderr, " VFP: VABS (%g) = %g\n", src, VFP_fval (dest));
1361a1ba9ba4Schristos }
1362a1ba9ba4Schristos }
1363a1ba9ba4Schristos return;
1364a1ba9ba4Schristos
1365a1ba9ba4Schristos case 0x1:
1366a1ba9ba4Schristos if (BIT (7) == 0)
1367a1ba9ba4Schristos {
1368a1ba9ba4Schristos /* VNEG */
1369a1ba9ba4Schristos if (BIT (8))
1370a1ba9ba4Schristos VFP_dval (dest) = - VFP_dval (srcM);
1371a1ba9ba4Schristos else
1372a1ba9ba4Schristos VFP_fval (dest) = - VFP_fval (srcM);
1373a1ba9ba4Schristos }
1374a1ba9ba4Schristos else
1375a1ba9ba4Schristos {
1376a1ba9ba4Schristos /* VSQRT */
1377a1ba9ba4Schristos if (BIT (8))
1378a1ba9ba4Schristos {
1379a1ba9ba4Schristos if (trace)
1380a1ba9ba4Schristos fprintf (stderr, " VFP: %g = root(%g)\n",
1381a1ba9ba4Schristos sqrt (VFP_dval (srcM)), VFP_dval (srcM));
1382a1ba9ba4Schristos
1383a1ba9ba4Schristos VFP_dval (dest) = sqrt (VFP_dval (srcM));
1384a1ba9ba4Schristos }
1385a1ba9ba4Schristos else
1386a1ba9ba4Schristos {
1387a1ba9ba4Schristos if (trace)
1388a1ba9ba4Schristos fprintf (stderr, " VFP: %g = root(%g)\n",
1389a1ba9ba4Schristos sqrtf (VFP_fval (srcM)), VFP_fval (srcM));
1390a1ba9ba4Schristos
1391a1ba9ba4Schristos VFP_fval (dest) = sqrtf (VFP_fval (srcM));
1392a1ba9ba4Schristos }
1393a1ba9ba4Schristos }
1394a1ba9ba4Schristos return;
1395a1ba9ba4Schristos
1396a1ba9ba4Schristos case 0x4:
1397a1ba9ba4Schristos case 0x5:
1398a1ba9ba4Schristos /* VCMP, VCMPE */
1399a1ba9ba4Schristos if (BIT(8))
1400a1ba9ba4Schristos {
1401a1ba9ba4Schristos ARMdval res = VFP_dval (dest);
1402a1ba9ba4Schristos
1403a1ba9ba4Schristos if (BIT (16) == 0)
1404a1ba9ba4Schristos {
1405a1ba9ba4Schristos ARMdval src = VFP_dval (srcM);
1406a1ba9ba4Schristos
1407a1ba9ba4Schristos if (isinf (res) && isinf (src))
1408a1ba9ba4Schristos {
1409a1ba9ba4Schristos if (res > 0.0 && src > 0.0)
1410a1ba9ba4Schristos res = 0.0;
1411a1ba9ba4Schristos else if (res < 0.0 && src < 0.0)
1412a1ba9ba4Schristos res = 0.0;
1413a1ba9ba4Schristos /* else leave res alone. */
1414a1ba9ba4Schristos }
1415a1ba9ba4Schristos else
1416a1ba9ba4Schristos res -= src;
1417a1ba9ba4Schristos }
1418a1ba9ba4Schristos
1419a1ba9ba4Schristos /* FIXME: Add handling of signalling NaNs and the E bit. */
1420a1ba9ba4Schristos
1421a1ba9ba4Schristos state->FPSCR &= 0x0FFFFFFF;
1422a1ba9ba4Schristos if (res < 0.0)
1423a1ba9ba4Schristos state->FPSCR |= NBIT;
1424a1ba9ba4Schristos else
1425a1ba9ba4Schristos state->FPSCR |= CBIT;
1426a1ba9ba4Schristos if (res == 0.0)
1427a1ba9ba4Schristos state->FPSCR |= ZBIT;
1428a1ba9ba4Schristos if (isnan (res))
1429a1ba9ba4Schristos state->FPSCR |= VBIT;
1430a1ba9ba4Schristos
1431a1ba9ba4Schristos if (trace)
1432a1ba9ba4Schristos fprintf (stderr, " VFP: VCMP (64bit) %g vs %g res %g, flags: %c%c%c%c\n",
1433a1ba9ba4Schristos VFP_dval (dest), BIT (16) ? 0.0 : VFP_dval (srcM), res,
1434a1ba9ba4Schristos state->FPSCR & NBIT ? 'N' : '-',
1435a1ba9ba4Schristos state->FPSCR & ZBIT ? 'Z' : '-',
1436a1ba9ba4Schristos state->FPSCR & CBIT ? 'C' : '-',
1437a1ba9ba4Schristos state->FPSCR & VBIT ? 'V' : '-');
1438a1ba9ba4Schristos }
1439a1ba9ba4Schristos else
1440a1ba9ba4Schristos {
1441a1ba9ba4Schristos ARMfval res = VFP_fval (dest);
1442a1ba9ba4Schristos
1443a1ba9ba4Schristos if (BIT (16) == 0)
1444a1ba9ba4Schristos {
1445a1ba9ba4Schristos ARMfval src = VFP_fval (srcM);
1446a1ba9ba4Schristos
1447a1ba9ba4Schristos if (isinf (res) && isinf (src))
1448a1ba9ba4Schristos {
1449a1ba9ba4Schristos if (res > 0.0 && src > 0.0)
1450a1ba9ba4Schristos res = 0.0;
1451a1ba9ba4Schristos else if (res < 0.0 && src < 0.0)
1452a1ba9ba4Schristos res = 0.0;
1453a1ba9ba4Schristos /* else leave res alone. */
1454a1ba9ba4Schristos }
1455a1ba9ba4Schristos else
1456a1ba9ba4Schristos res -= src;
1457a1ba9ba4Schristos }
1458a1ba9ba4Schristos
1459a1ba9ba4Schristos /* FIXME: Add handling of signalling NaNs and the E bit. */
1460a1ba9ba4Schristos
1461a1ba9ba4Schristos state->FPSCR &= 0x0FFFFFFF;
1462a1ba9ba4Schristos if (res < 0.0)
1463a1ba9ba4Schristos state->FPSCR |= NBIT;
1464a1ba9ba4Schristos else
1465a1ba9ba4Schristos state->FPSCR |= CBIT;
1466a1ba9ba4Schristos if (res == 0.0)
1467a1ba9ba4Schristos state->FPSCR |= ZBIT;
1468a1ba9ba4Schristos if (isnan (res))
1469a1ba9ba4Schristos state->FPSCR |= VBIT;
1470a1ba9ba4Schristos
1471a1ba9ba4Schristos if (trace)
1472a1ba9ba4Schristos fprintf (stderr, " VFP: VCMP (32bit) %g vs %g res %g, flags: %c%c%c%c\n",
1473a1ba9ba4Schristos VFP_fval (dest), BIT (16) ? 0.0 : VFP_fval (srcM), res,
1474a1ba9ba4Schristos state->FPSCR & NBIT ? 'N' : '-',
1475a1ba9ba4Schristos state->FPSCR & ZBIT ? 'Z' : '-',
1476a1ba9ba4Schristos state->FPSCR & CBIT ? 'C' : '-',
1477a1ba9ba4Schristos state->FPSCR & VBIT ? 'V' : '-');
1478a1ba9ba4Schristos }
1479a1ba9ba4Schristos return;
1480a1ba9ba4Schristos
1481a1ba9ba4Schristos case 0x7:
1482a1ba9ba4Schristos if (BIT (8))
1483a1ba9ba4Schristos {
1484a1ba9ba4Schristos dest = (DESTReg << 1) + BIT (22);
1485a1ba9ba4Schristos VFP_fval (dest) = VFP_dval (srcM);
1486a1ba9ba4Schristos }
1487a1ba9ba4Schristos else
1488a1ba9ba4Schristos {
1489a1ba9ba4Schristos dest = DESTReg + (BIT (22) << 4);
1490a1ba9ba4Schristos VFP_dval (dest) = VFP_fval (srcM);
1491a1ba9ba4Schristos }
1492a1ba9ba4Schristos return;
1493a1ba9ba4Schristos
1494a1ba9ba4Schristos case 0x8:
1495a1ba9ba4Schristos case 0xC:
1496a1ba9ba4Schristos case 0xD:
1497a1ba9ba4Schristos /* VCVT integer <-> FP */
1498a1ba9ba4Schristos if (BIT (18))
1499a1ba9ba4Schristos {
1500a1ba9ba4Schristos /* To integer. */
1501a1ba9ba4Schristos if (BIT (8))
1502a1ba9ba4Schristos {
1503a1ba9ba4Schristos dest = (BITS(12,15) << 1) + BIT (22);
1504a1ba9ba4Schristos if (BIT (16))
1505a1ba9ba4Schristos VFP_sword (dest) = VFP_dval (srcM);
1506a1ba9ba4Schristos else
1507a1ba9ba4Schristos VFP_uword (dest) = VFP_dval (srcM);
1508a1ba9ba4Schristos }
1509a1ba9ba4Schristos else
1510a1ba9ba4Schristos {
1511a1ba9ba4Schristos if (BIT (16))
1512a1ba9ba4Schristos VFP_sword (dest) = VFP_fval (srcM);
1513a1ba9ba4Schristos else
1514a1ba9ba4Schristos VFP_uword (dest) = VFP_fval (srcM);
1515a1ba9ba4Schristos }
1516a1ba9ba4Schristos }
1517a1ba9ba4Schristos else
1518a1ba9ba4Schristos {
1519a1ba9ba4Schristos /* From integer. */
1520a1ba9ba4Schristos if (BIT (8))
1521a1ba9ba4Schristos {
1522a1ba9ba4Schristos srcM = (BITS (0,3) << 1) + BIT (5);
1523a1ba9ba4Schristos if (BIT (7))
1524a1ba9ba4Schristos VFP_dval (dest) = VFP_sword (srcM);
1525a1ba9ba4Schristos else
1526a1ba9ba4Schristos VFP_dval (dest) = VFP_uword (srcM);
1527a1ba9ba4Schristos }
1528a1ba9ba4Schristos else
1529a1ba9ba4Schristos {
1530a1ba9ba4Schristos if (BIT (7))
1531a1ba9ba4Schristos VFP_fval (dest) = VFP_sword (srcM);
1532a1ba9ba4Schristos else
1533a1ba9ba4Schristos VFP_fval (dest) = VFP_uword (srcM);
1534a1ba9ba4Schristos }
1535a1ba9ba4Schristos }
1536a1ba9ba4Schristos return;
1537a1ba9ba4Schristos }
1538a1ba9ba4Schristos
1539a1ba9ba4Schristos fprintf (stderr, "SIM: VFP: Unimplemented: Float op3: %03x\n", BITS (16,27));
1540a1ba9ba4Schristos return;
1541a1ba9ba4Schristos }
1542a1ba9ba4Schristos
1543a1ba9ba4Schristos fprintf (stderr, "SIM: VFP: Unimplemented: Float op2: %02x\n", BITS (20, 27));
1544a1ba9ba4Schristos return;
1545a1ba9ba4Schristos }
1546a1ba9ba4Schristos
1547a1ba9ba4Schristos /* This function does the Busy-Waiting for an CDP instruction. */
1548a1ba9ba4Schristos
1549a1ba9ba4Schristos void
ARMul_CDP(ARMul_State * state,ARMword instr)1550a1ba9ba4Schristos ARMul_CDP (ARMul_State * state, ARMword instr)
1551a1ba9ba4Schristos {
1552a1ba9ba4Schristos unsigned cpab;
1553a1ba9ba4Schristos
1554a1ba9ba4Schristos if (CPNum == 10 || CPNum == 11)
1555a1ba9ba4Schristos {
1556a1ba9ba4Schristos handle_VFP_op (state, instr);
1557a1ba9ba4Schristos return;
1558a1ba9ba4Schristos }
1559a1ba9ba4Schristos
1560a1ba9ba4Schristos if (! CP_ACCESS_ALLOWED (state, CPNum))
1561a1ba9ba4Schristos {
1562a1ba9ba4Schristos ARMul_UndefInstr (state, instr);
1563a1ba9ba4Schristos return;
1564a1ba9ba4Schristos }
1565a1ba9ba4Schristos
1566a1ba9ba4Schristos cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
1567a1ba9ba4Schristos while (cpab == ARMul_BUSY)
1568a1ba9ba4Schristos {
1569a1ba9ba4Schristos ARMul_Icycles (state, 1, 0);
1570a1ba9ba4Schristos if (IntPending (state))
1571a1ba9ba4Schristos {
1572a1ba9ba4Schristos cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
1573a1ba9ba4Schristos return;
1574a1ba9ba4Schristos }
1575a1ba9ba4Schristos else
1576a1ba9ba4Schristos cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
1577a1ba9ba4Schristos }
1578a1ba9ba4Schristos if (cpab == ARMul_CANT)
1579a1ba9ba4Schristos ARMul_Abort (state, ARMul_UndefinedInstrV);
1580a1ba9ba4Schristos else
1581a1ba9ba4Schristos BUSUSEDN;
1582a1ba9ba4Schristos }
1583a1ba9ba4Schristos
1584a1ba9ba4Schristos /* This function handles Undefined instructions, as CP isntruction. */
1585a1ba9ba4Schristos
1586a1ba9ba4Schristos void
ARMul_UndefInstr(ARMul_State * state,ARMword instr ATTRIBUTE_UNUSED)1587a1ba9ba4Schristos ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
1588a1ba9ba4Schristos {
1589a1ba9ba4Schristos ARMul_Abort (state, ARMul_UndefinedInstrV);
1590a1ba9ba4Schristos }
1591a1ba9ba4Schristos
1592a1ba9ba4Schristos /* Return TRUE if an interrupt is pending, FALSE otherwise. */
1593a1ba9ba4Schristos
1594a1ba9ba4Schristos unsigned
IntPending(ARMul_State * state)1595a1ba9ba4Schristos IntPending (ARMul_State * state)
1596a1ba9ba4Schristos {
1597a1ba9ba4Schristos if (state->Exception)
1598a1ba9ba4Schristos {
1599a1ba9ba4Schristos /* Any exceptions. */
1600a1ba9ba4Schristos if (state->NresetSig == LOW)
1601a1ba9ba4Schristos {
1602a1ba9ba4Schristos ARMul_Abort (state, ARMul_ResetV);
1603a1ba9ba4Schristos return TRUE;
1604a1ba9ba4Schristos }
1605a1ba9ba4Schristos else if (!state->NfiqSig && !FFLAG)
1606a1ba9ba4Schristos {
1607a1ba9ba4Schristos ARMul_Abort (state, ARMul_FIQV);
1608a1ba9ba4Schristos return TRUE;
1609a1ba9ba4Schristos }
1610a1ba9ba4Schristos else if (!state->NirqSig && !IFLAG)
1611a1ba9ba4Schristos {
1612a1ba9ba4Schristos ARMul_Abort (state, ARMul_IRQV);
1613a1ba9ba4Schristos return TRUE;
1614a1ba9ba4Schristos }
1615a1ba9ba4Schristos }
1616a1ba9ba4Schristos
1617a1ba9ba4Schristos return FALSE;
1618a1ba9ba4Schristos }
1619a1ba9ba4Schristos
1620a1ba9ba4Schristos /* Align a word access to a non word boundary. */
1621a1ba9ba4Schristos
1622a1ba9ba4Schristos ARMword
ARMul_Align(ARMul_State * state ATTRIBUTE_UNUSED,ARMword address,ARMword data)1623a1ba9ba4Schristos ARMul_Align (ARMul_State *state ATTRIBUTE_UNUSED, ARMword address, ARMword data)
1624a1ba9ba4Schristos {
1625a1ba9ba4Schristos /* This code assumes the address is really unaligned,
1626a1ba9ba4Schristos as a shift by 32 is undefined in C. */
1627a1ba9ba4Schristos
1628a1ba9ba4Schristos address = (address & 3) << 3; /* Get the word address. */
1629a1ba9ba4Schristos return ((data >> address) | (data << (32 - address))); /* rot right */
1630a1ba9ba4Schristos }
1631a1ba9ba4Schristos
1632a1ba9ba4Schristos /* This routine is used to call another routine after a certain number of
1633a1ba9ba4Schristos cycles have been executed. The first parameter is the number of cycles
1634a1ba9ba4Schristos delay before the function is called, the second argument is a pointer
1635a1ba9ba4Schristos to the function. A delay of zero doesn't work, just call the function. */
1636a1ba9ba4Schristos
1637a1ba9ba4Schristos void
ARMul_ScheduleEvent(ARMul_State * state,unsigned long delay,unsigned (* what)(ARMul_State *))1638a1ba9ba4Schristos ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
1639a1ba9ba4Schristos unsigned (*what) (ARMul_State *))
1640a1ba9ba4Schristos {
1641a1ba9ba4Schristos unsigned long when;
1642a1ba9ba4Schristos struct EventNode *event;
1643a1ba9ba4Schristos
1644a1ba9ba4Schristos if (state->EventSet++ == 0)
1645a1ba9ba4Schristos state->Now = ARMul_Time (state);
1646a1ba9ba4Schristos when = (state->Now + delay) % EVENTLISTSIZE;
1647a1ba9ba4Schristos event = (struct EventNode *) malloc (sizeof (struct EventNode));
1648a1ba9ba4Schristos event->func = what;
1649a1ba9ba4Schristos event->next = *(state->EventPtr + when);
1650a1ba9ba4Schristos *(state->EventPtr + when) = event;
1651a1ba9ba4Schristos }
1652a1ba9ba4Schristos
1653a1ba9ba4Schristos /* This routine is called at the beginning of
1654a1ba9ba4Schristos every cycle, to envoke scheduled events. */
1655a1ba9ba4Schristos
1656a1ba9ba4Schristos void
ARMul_EnvokeEvent(ARMul_State * state)1657a1ba9ba4Schristos ARMul_EnvokeEvent (ARMul_State * state)
1658a1ba9ba4Schristos {
1659a1ba9ba4Schristos static unsigned long then;
1660a1ba9ba4Schristos
1661a1ba9ba4Schristos then = state->Now;
1662a1ba9ba4Schristos state->Now = ARMul_Time (state) % EVENTLISTSIZE;
1663a1ba9ba4Schristos if (then < state->Now)
1664a1ba9ba4Schristos /* Schedule events. */
1665a1ba9ba4Schristos EnvokeList (state, then, state->Now);
1666a1ba9ba4Schristos else if (then > state->Now)
1667a1ba9ba4Schristos {
1668a1ba9ba4Schristos /* Need to wrap around the list. */
1669a1ba9ba4Schristos EnvokeList (state, then, EVENTLISTSIZE - 1L);
1670a1ba9ba4Schristos EnvokeList (state, 0L, state->Now);
1671a1ba9ba4Schristos }
1672a1ba9ba4Schristos }
1673a1ba9ba4Schristos
1674a1ba9ba4Schristos /* Envokes all the entries in a range. */
1675a1ba9ba4Schristos
1676a1ba9ba4Schristos static void
EnvokeList(ARMul_State * state,unsigned long from,unsigned long to)1677a1ba9ba4Schristos EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
1678a1ba9ba4Schristos {
1679a1ba9ba4Schristos for (; from <= to; from++)
1680a1ba9ba4Schristos {
1681a1ba9ba4Schristos struct EventNode *anevent;
1682a1ba9ba4Schristos
1683a1ba9ba4Schristos anevent = *(state->EventPtr + from);
1684a1ba9ba4Schristos while (anevent)
1685a1ba9ba4Schristos {
1686a1ba9ba4Schristos (anevent->func) (state);
1687a1ba9ba4Schristos state->EventSet--;
1688a1ba9ba4Schristos anevent = anevent->next;
1689a1ba9ba4Schristos }
1690a1ba9ba4Schristos *(state->EventPtr + from) = NULL;
1691a1ba9ba4Schristos }
1692a1ba9ba4Schristos }
1693a1ba9ba4Schristos
1694a1ba9ba4Schristos /* This routine is returns the number of clock ticks since the last reset. */
1695a1ba9ba4Schristos
1696a1ba9ba4Schristos unsigned long
ARMul_Time(ARMul_State * state)1697a1ba9ba4Schristos ARMul_Time (ARMul_State * state)
1698a1ba9ba4Schristos {
1699a1ba9ba4Schristos return (state->NumScycles + state->NumNcycles +
1700a1ba9ba4Schristos state->NumIcycles + state->NumCcycles + state->NumFcycles);
1701a1ba9ba4Schristos }
1702