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