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