Commit | Line | Data |
---|---|---|
c906108c | 1 | /* armcopro.c -- co-processor interface: ARM6 Instruction Emulator. |
6d358e86 | 2 | Copyright (C) 1994, 2000 Advanced RISC Machines Ltd. |
c906108c SS |
3 | |
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 2 of the License, or | |
7 | (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
17 | ||
18 | #include "armdefs.h" | |
6d358e86 | 19 | #include "ansidecl.h" |
c906108c | 20 | |
dfcd3bfb JM |
21 | extern unsigned ARMul_CoProInit (ARMul_State * state); |
22 | extern void ARMul_CoProExit (ARMul_State * state); | |
23 | extern void ARMul_CoProAttach (ARMul_State * state, unsigned number, | |
24 | ARMul_CPInits * init, ARMul_CPExits * exit, | |
25 | ARMul_LDCs * ldc, ARMul_STCs * stc, | |
26 | ARMul_MRCs * mrc, ARMul_MCRs * mcr, | |
27 | ARMul_CDPs * cdp, | |
28 | ARMul_CPReads * read, ARMul_CPWrites * write); | |
29 | extern void ARMul_CoProDetach (ARMul_State * state, unsigned number); | |
c906108c SS |
30 | |
31 | ||
32 | /***************************************************************************\ | |
33 | * Dummy Co-processors * | |
34 | \***************************************************************************/ | |
35 | ||
dfcd3bfb JM |
36 | static unsigned NoCoPro3R (ARMul_State * state, unsigned, ARMword); |
37 | static unsigned NoCoPro4R (ARMul_State * state, unsigned, ARMword, ARMword); | |
38 | static unsigned NoCoPro4W (ARMul_State * state, unsigned, ARMword, ARMword *); | |
c906108c SS |
39 | |
40 | /***************************************************************************\ | |
41 | * Define Co-Processor instruction handlers here * | |
42 | \***************************************************************************/ | |
43 | ||
44 | /* Here's ARMulator's MMU definition. A few things to note: | |
45 | 1) it has eight registers, but only two are defined. | |
46 | 2) you can only access its registers with MCR and MRC. | |
47 | 3) MMU Register 0 (ID) returns 0x41440110 | |
48 | 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4 | |
49 | controls 32/26 bit program space, bit 5 controls 32/26 bit data space, | |
50 | bit 6 controls late abort timimg and bit 7 controls big/little endian. | |
51 | */ | |
52 | ||
dfcd3bfb | 53 | static ARMword MMUReg[8]; |
c906108c | 54 | |
dfcd3bfb JM |
55 | static unsigned |
56 | MMUInit (ARMul_State * state) | |
57 | { | |
58 | MMUReg[1] = state->prog32Sig << 4 | | |
59 | state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7; | |
60 | ARMul_ConsolePrint (state, ", MMU present"); | |
61 | return (TRUE); | |
62 | } | |
63 | ||
64 | static unsigned | |
6d358e86 | 65 | MMUMRC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value) |
dfcd3bfb JM |
66 | { |
67 | int reg = BITS (16, 19) & 7; | |
68 | ||
69 | if (reg == 0) | |
70 | *value = 0x41440110; | |
71 | else | |
72 | *value = MMUReg[reg]; | |
73 | return (ARMul_DONE); | |
c906108c SS |
74 | } |
75 | ||
dfcd3bfb | 76 | static unsigned |
6d358e86 | 77 | MMUMCR (ARMul_State * state, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value) |
dfcd3bfb JM |
78 | { |
79 | int reg = BITS (16, 19) & 7; | |
80 | ||
81 | MMUReg[reg] = value; | |
82 | if (reg == 1) | |
83 | { | |
84 | state->prog32Sig = value >> 4 & 1; | |
85 | state->data32Sig = value >> 5 & 1; | |
86 | state->lateabtSig = value >> 6 & 1; | |
87 | state->bigendSig = value >> 7 & 1; | |
88 | state->Emulate = TRUE; /* force ARMulator to notice these now ! */ | |
c906108c | 89 | } |
dfcd3bfb JM |
90 | return (ARMul_DONE); |
91 | } | |
92 | ||
93 | ||
94 | static unsigned | |
6d358e86 | 95 | MMURead (ARMul_State * state ATTRIBUTE_UNUSED, unsigned reg, ARMword * value) |
dfcd3bfb JM |
96 | { |
97 | if (reg == 0) | |
98 | *value = 0x41440110; | |
99 | else if (reg < 8) | |
100 | *value = MMUReg[reg]; | |
101 | return (TRUE); | |
102 | } | |
103 | ||
104 | static unsigned | |
105 | MMUWrite (ARMul_State * state, unsigned reg, ARMword value) | |
106 | { | |
107 | if (reg < 8) | |
108 | MMUReg[reg] = value; | |
109 | if (reg == 1) | |
110 | { | |
111 | state->prog32Sig = value >> 4 & 1; | |
112 | state->data32Sig = value >> 5 & 1; | |
113 | state->lateabtSig = value >> 6 & 1; | |
114 | state->bigendSig = value >> 7 & 1; | |
115 | state->Emulate = TRUE; /* force ARMulator to notice these now ! */ | |
c906108c | 116 | } |
dfcd3bfb JM |
117 | return (TRUE); |
118 | } | |
c906108c SS |
119 | |
120 | ||
121 | /* What follows is the Validation Suite Coprocessor. It uses two | |
122 | co-processor numbers (4 and 5) and has the follwing functionality. | |
123 | Sixteen registers. Both co-processor nuimbers can be used in an MCR and | |
124 | MRC to access these registers. CP 4 can LDC and STC to and from the | |
125 | registers. CP 4 and CP 5 CDP 0 will busy wait for the number of cycles | |
126 | specified by a CP register. CP 5 CDP 1 issues a FIQ after a number of | |
127 | cycles (specified in a CP register), CDP 2 issues an IRQW in the same | |
128 | way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5 stores a 32 | |
129 | bit time value in a CP register (actually it's the total number of N, S, | |
130 | I, C and F cyles) */ | |
131 | ||
dfcd3bfb | 132 | static ARMword ValReg[16]; |
c906108c | 133 | |
dfcd3bfb | 134 | static unsigned |
6d358e86 | 135 | ValLDC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type, ARMword instr, ARMword data) |
dfcd3bfb JM |
136 | { |
137 | static unsigned words; | |
c906108c | 138 | |
dfcd3bfb JM |
139 | if (type != ARMul_DATA) |
140 | { | |
141 | words = 0; | |
142 | return (ARMul_DONE); | |
c906108c | 143 | } |
dfcd3bfb JM |
144 | if (BIT (22)) |
145 | { /* it's a long access, get two words */ | |
146 | ValReg[BITS (12, 15)] = data; | |
147 | if (words++ == 4) | |
148 | return (ARMul_DONE); | |
149 | else | |
150 | return (ARMul_INC); | |
c906108c | 151 | } |
dfcd3bfb JM |
152 | else |
153 | { /* get just one word */ | |
154 | ValReg[BITS (12, 15)] = data; | |
155 | return (ARMul_DONE); | |
c906108c | 156 | } |
dfcd3bfb | 157 | } |
c906108c | 158 | |
dfcd3bfb | 159 | static unsigned |
6d358e86 | 160 | ValSTC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type, ARMword instr, ARMword * data) |
dfcd3bfb JM |
161 | { |
162 | static unsigned words; | |
c906108c | 163 | |
dfcd3bfb JM |
164 | if (type != ARMul_DATA) |
165 | { | |
166 | words = 0; | |
167 | return (ARMul_DONE); | |
c906108c | 168 | } |
dfcd3bfb JM |
169 | if (BIT (22)) |
170 | { /* it's a long access, get two words */ | |
171 | *data = ValReg[BITS (12, 15)]; | |
172 | if (words++ == 4) | |
173 | return (ARMul_DONE); | |
174 | else | |
175 | return (ARMul_INC); | |
c906108c | 176 | } |
dfcd3bfb JM |
177 | else |
178 | { /* get just one word */ | |
179 | *data = ValReg[BITS (12, 15)]; | |
180 | return (ARMul_DONE); | |
181 | } | |
182 | } | |
c906108c | 183 | |
dfcd3bfb | 184 | static unsigned |
6d358e86 | 185 | ValMRC (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value) |
c906108c | 186 | { |
dfcd3bfb JM |
187 | *value = ValReg[BITS (16, 19)]; |
188 | return (ARMul_DONE); | |
189 | } | |
c906108c | 190 | |
dfcd3bfb | 191 | static unsigned |
6d358e86 | 192 | ValMCR (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value) |
c906108c | 193 | { |
dfcd3bfb JM |
194 | ValReg[BITS (16, 19)] = value; |
195 | return (ARMul_DONE); | |
196 | } | |
c906108c | 197 | |
dfcd3bfb JM |
198 | static unsigned |
199 | ValCDP (ARMul_State * state, unsigned type, ARMword instr) | |
c906108c | 200 | { |
dfcd3bfb JM |
201 | static unsigned long finish = 0; |
202 | ARMword howlong; | |
203 | ||
204 | howlong = ValReg[BITS (0, 3)]; | |
205 | if (BITS (20, 23) == 0) | |
206 | { | |
207 | if (type == ARMul_FIRST) | |
208 | { /* First cycle of a busy wait */ | |
209 | finish = ARMul_Time (state) + howlong; | |
210 | if (howlong == 0) | |
211 | return (ARMul_DONE); | |
212 | else | |
213 | return (ARMul_BUSY); | |
214 | } | |
215 | else if (type == ARMul_BUSY) | |
216 | { | |
217 | if (ARMul_Time (state) >= finish) | |
218 | return (ARMul_DONE); | |
219 | else | |
220 | return (ARMul_BUSY); | |
221 | } | |
c906108c | 222 | } |
dfcd3bfb JM |
223 | return (ARMul_CANT); |
224 | } | |
c906108c | 225 | |
dfcd3bfb JM |
226 | static unsigned |
227 | DoAFIQ (ARMul_State * state) | |
228 | { | |
229 | state->NfiqSig = LOW; | |
230 | state->Exception++; | |
231 | return (0); | |
c906108c SS |
232 | } |
233 | ||
dfcd3bfb JM |
234 | static unsigned |
235 | DoAIRQ (ARMul_State * state) | |
236 | { | |
237 | state->NirqSig = LOW; | |
238 | state->Exception++; | |
239 | return (0); | |
c906108c SS |
240 | } |
241 | ||
dfcd3bfb JM |
242 | static unsigned |
243 | IntCDP (ARMul_State * state, unsigned type, ARMword instr) | |
244 | { | |
245 | static unsigned long finish; | |
246 | ARMword howlong; | |
247 | ||
248 | howlong = ValReg[BITS (0, 3)]; | |
249 | switch ((int) BITS (20, 23)) | |
250 | { | |
251 | case 0: | |
252 | if (type == ARMul_FIRST) | |
253 | { /* First cycle of a busy wait */ | |
254 | finish = ARMul_Time (state) + howlong; | |
255 | if (howlong == 0) | |
256 | return (ARMul_DONE); | |
257 | else | |
258 | return (ARMul_BUSY); | |
259 | } | |
260 | else if (type == ARMul_BUSY) | |
261 | { | |
262 | if (ARMul_Time (state) >= finish) | |
263 | return (ARMul_DONE); | |
264 | else | |
265 | return (ARMul_BUSY); | |
266 | } | |
267 | return (ARMul_DONE); | |
268 | case 1: | |
269 | if (howlong == 0) | |
270 | ARMul_Abort (state, ARMul_FIQV); | |
271 | else | |
272 | ARMul_ScheduleEvent (state, howlong, DoAFIQ); | |
273 | return (ARMul_DONE); | |
274 | case 2: | |
275 | if (howlong == 0) | |
276 | ARMul_Abort (state, ARMul_IRQV); | |
277 | else | |
278 | ARMul_ScheduleEvent (state, howlong, DoAIRQ); | |
279 | return (ARMul_DONE); | |
280 | case 3: | |
281 | state->NfiqSig = HIGH; | |
282 | state->Exception--; | |
283 | return (ARMul_DONE); | |
284 | case 4: | |
285 | state->NirqSig = HIGH; | |
286 | state->Exception--; | |
287 | return (ARMul_DONE); | |
288 | case 5: | |
289 | ValReg[BITS (0, 3)] = ARMul_Time (state); | |
290 | return (ARMul_DONE); | |
c906108c | 291 | } |
dfcd3bfb JM |
292 | return (ARMul_CANT); |
293 | } | |
c906108c SS |
294 | |
295 | /***************************************************************************\ | |
296 | * Install co-processor instruction handlers in this routine * | |
297 | \***************************************************************************/ | |
298 | ||
dfcd3bfb JM |
299 | unsigned |
300 | ARMul_CoProInit (ARMul_State * state) | |
301 | { | |
302 | register unsigned i; | |
c906108c | 303 | |
dfcd3bfb JM |
304 | for (i = 0; i < 16; i++) /* initialise tham all first */ |
305 | ARMul_CoProDetach (state, i); | |
c906108c | 306 | |
dfcd3bfb JM |
307 | /* Install CoPro Instruction handlers here |
308 | The format is | |
309 | ARMul_CoProAttach(state, CP Number, Init routine, Exit routine | |
310 | LDC routine, STC routine, MRC routine, MCR routine, | |
311 | CDP routine, Read Reg routine, Write Reg routine) ; | |
c906108c SS |
312 | */ |
313 | ||
dfcd3bfb JM |
314 | ARMul_CoProAttach (state, 4, NULL, NULL, |
315 | ValLDC, ValSTC, ValMRC, ValMCR, ValCDP, NULL, NULL); | |
c906108c | 316 | |
dfcd3bfb JM |
317 | ARMul_CoProAttach (state, 5, NULL, NULL, |
318 | NULL, NULL, ValMRC, ValMCR, IntCDP, NULL, NULL); | |
c906108c | 319 | |
dfcd3bfb JM |
320 | ARMul_CoProAttach (state, 15, MMUInit, NULL, |
321 | NULL, NULL, MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); | |
c906108c SS |
322 | |
323 | ||
dfcd3bfb | 324 | /* No handlers below here */ |
c906108c | 325 | |
dfcd3bfb JM |
326 | for (i = 0; i < 16; i++) /* Call all the initialisation routines */ |
327 | if (state->CPInit[i]) | |
328 | (state->CPInit[i]) (state); | |
329 | return (TRUE); | |
330 | } | |
c906108c SS |
331 | |
332 | /***************************************************************************\ | |
333 | * Install co-processor finalisation routines in this routine * | |
334 | \***************************************************************************/ | |
335 | ||
dfcd3bfb JM |
336 | void |
337 | ARMul_CoProExit (ARMul_State * state) | |
338 | { | |
339 | register unsigned i; | |
c906108c | 340 | |
dfcd3bfb | 341 | for (i = 0; i < 16; i++) |
c906108c | 342 | if (state->CPExit[i]) |
dfcd3bfb JM |
343 | (state->CPExit[i]) (state); |
344 | for (i = 0; i < 16; i++) /* Detach all handlers */ | |
345 | ARMul_CoProDetach (state, i); | |
346 | } | |
c906108c SS |
347 | |
348 | /***************************************************************************\ | |
349 | * Routines to hook Co-processors into ARMulator * | |
350 | \***************************************************************************/ | |
351 | ||
dfcd3bfb JM |
352 | void |
353 | ARMul_CoProAttach (ARMul_State * state, unsigned number, | |
354 | ARMul_CPInits * init, ARMul_CPExits * exit, | |
355 | ARMul_LDCs * ldc, ARMul_STCs * stc, | |
356 | ARMul_MRCs * mrc, ARMul_MCRs * mcr, ARMul_CDPs * cdp, | |
357 | ARMul_CPReads * read, ARMul_CPWrites * write) | |
358 | { | |
359 | if (init != NULL) | |
360 | state->CPInit[number] = init; | |
361 | if (exit != NULL) | |
362 | state->CPExit[number] = exit; | |
363 | if (ldc != NULL) | |
364 | state->LDC[number] = ldc; | |
365 | if (stc != NULL) | |
366 | state->STC[number] = stc; | |
367 | if (mrc != NULL) | |
368 | state->MRC[number] = mrc; | |
369 | if (mcr != NULL) | |
370 | state->MCR[number] = mcr; | |
371 | if (cdp != NULL) | |
372 | state->CDP[number] = cdp; | |
373 | if (read != NULL) | |
374 | state->CPRead[number] = read; | |
375 | if (write != NULL) | |
376 | state->CPWrite[number] = write; | |
c906108c SS |
377 | } |
378 | ||
dfcd3bfb JM |
379 | void |
380 | ARMul_CoProDetach (ARMul_State * state, unsigned number) | |
381 | { | |
382 | ARMul_CoProAttach (state, number, NULL, NULL, | |
383 | NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, | |
384 | NoCoPro3R, NULL, NULL); | |
385 | state->CPInit[number] = NULL; | |
386 | state->CPExit[number] = NULL; | |
387 | state->CPRead[number] = NULL; | |
388 | state->CPWrite[number] = NULL; | |
c906108c SS |
389 | } |
390 | ||
391 | /***************************************************************************\ | |
392 | * There is no CoPro around, so Undefined Instruction trap * | |
393 | \***************************************************************************/ | |
394 | ||
dfcd3bfb | 395 | static unsigned |
6d358e86 NC |
396 | NoCoPro3R (ARMul_State * state ATTRIBUTE_UNUSED, |
397 | unsigned a ATTRIBUTE_UNUSED, | |
398 | ARMword b ATTRIBUTE_UNUSED) | |
dfcd3bfb JM |
399 | { |
400 | return (ARMul_CANT); | |
401 | } | |
c906108c | 402 | |
dfcd3bfb | 403 | static unsigned |
6d358e86 NC |
404 | NoCoPro4R ( |
405 | ARMul_State * state ATTRIBUTE_UNUSED, | |
406 | unsigned a ATTRIBUTE_UNUSED, | |
407 | ARMword b ATTRIBUTE_UNUSED, | |
408 | ARMword c ATTRIBUTE_UNUSED) | |
dfcd3bfb JM |
409 | { |
410 | return (ARMul_CANT); | |
411 | } | |
c906108c | 412 | |
dfcd3bfb | 413 | static unsigned |
6d358e86 NC |
414 | NoCoPro4W ( |
415 | ARMul_State * state ATTRIBUTE_UNUSED, | |
416 | unsigned a ATTRIBUTE_UNUSED, | |
417 | ARMword b ATTRIBUTE_UNUSED, | |
418 | ARMword * c ATTRIBUTE_UNUSED) | |
dfcd3bfb JM |
419 | { |
420 | return (ARMul_CANT); | |
421 | } |