fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/cpu/arm/copr15.c *
7 * Created: 2004-11-09 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2004-2011 Hampa Hug <hampa@hampa.ch> *
9 * Copyright: (C) 2004-2006 Lukas Ruf <ruf@lpr.ch> *
10 *****************************************************************************/
11
12/*****************************************************************************
13 * This program is free software. You can redistribute it and / or modify it *
14 * under the terms of the GNU General Public License version 2 as published *
15 * by the Free Software Foundation. *
16 * *
17 * This program is distributed in the hope that it will be useful, but *
18 * WITHOUT ANY WARRANTY, without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
20 * Public License for more details. *
21 *****************************************************************************/
22
23/*****************************************************************************
24 * This software was developed at the Computer Engineering and Networks *
25 * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. *
26 *****************************************************************************/
27
28
29#include "arm.h"
30#include "internal.h"
31
32
33static int cp15_reset (arm_t *c, arm_copr_t *p);
34static int cp15_exec (arm_t *c, arm_copr_t *p);
35
36
37void cp15_init (arm_copr15_t *p)
38{
39 unsigned i;
40
41 arm_copr_init (&p->copr);
42
43 p->copr.ext = p;
44 p->copr.reset = cp15_reset;
45 p->copr.exec = cp15_exec;
46
47 p->reg[0] = ARM_C15_ID;
48 p->reg[1] = ARM_C15_CR_P | ARM_C15_CR_D | ARM_C15_CR_L;
49
50 for (i = 2; i < 16; i++) {
51 p->reg[i] = 0;
52 }
53
54 p->cache_type = 0;
55 p->auxiliary_control = 0;
56}
57
58arm_copr_t *cp15_new (void)
59{
60 arm_copr15_t *c;
61
62 c = malloc (sizeof (arm_copr15_t));
63 if (c == NULL) {
64 return (NULL);
65 }
66
67 cp15_init (c);
68
69 return (&c->copr);
70}
71
72void cp15_free (arm_copr15_t *p)
73{
74}
75
76void cp15_del (arm_copr15_t *p)
77{
78 if (p != NULL) {
79 cp15_free (p);
80 }
81
82 free (p);
83}
84
85
86/*
87 * Get CP15/0 (ID)
88 */
89static
90int cp15_get_reg0 (arm_t *c, arm_copr15_t *p, unsigned op2, uint32_t *val)
91{
92 switch (op2) {
93 case 0:
94 /* ID */
95 *val = p->reg[0];
96 return (0);
97
98 case 1:
99 /* XScale Cache Type */
100 *val = p->cache_type;
101 return (0);
102 }
103
104 return (1);
105}
106
107/*
108 * Get CP15/1 (Control)
109 */
110static
111int cp15_get_reg1 (arm_t *c, arm_copr15_t *p, unsigned op2, uint32_t *val)
112{
113 switch (op2) {
114 case 0:
115 /* Control */
116 *val = p->reg[1];
117 return (0);
118
119 case 1:
120 /* XScale Auxiliary Control */
121 *val = p->auxiliary_control;
122 return (0);
123 }
124
125 return (1);
126}
127
128/*
129 * Set CP15/1 (Control)
130 */
131static
132int cp15_set_reg1 (arm_t *c, arm_copr15_t *p, unsigned op2, uint32_t val)
133{
134 switch (op2) {
135 case 0:
136 /* Control */
137 val &= ~ARM_C15_CR_C;
138 val &= ~ARM_C15_CR_W;
139 val |= ARM_C15_CR_P;
140 val |= ARM_C15_CR_D;
141 val |= ARM_C15_CR_L;
142 arm_set_bits (val, ARM_C15_CR_B, c->bigendian);
143 p->reg[1] = val & 0xffffffff;
144
145 c->exception_base = (val & ARM_C15_CR_V) ? 0xffff0000 : 0x00000000;
146
147 return (0);
148
149 case 1:
150 /* XScale Auxiliary Control */
151 p->auxiliary_control = val;
152
153 return (0);
154 }
155
156 return (1);
157}
158
159/* cache functions */
160static
161int cp15_set_reg7 (arm_t *c, arm_copr15_t *p)
162{
163 unsigned rm, op2;
164
165 rm = arm_ir_rm (c->ir);
166 op2 = arm_get_bits (c->ir, 5, 3);
167
168 if ((rm == 7) && (op2 == 0)) {
169 /* invalidate all caches */
170 return (0);
171 }
172 else if ((rm == 2) && (op2 == 5)) {
173 /* ??? */
174 return (0);
175 }
176 else if (rm == 5) {
177 switch (op2) {
178 case 0x00:
179 /* invalidate entire instruction cache */
180 return (0);
181
182 case 0x01:
183 /* invalidate instruction cache line */
184 return (0);
185
186 case 0x02:
187 /* invalidate instruction cache line */
188 return (0);
189
190 case 0x04:
191 /* flush prefetch buffer */
192 return (0);
193
194 case 0x06:
195 /* flush entire branch target cache */
196 return (0);
197
198 case 0x07:
199 /* flush branch target cache entry */
200 return (0);
201 }
202
203 return (1);
204 }
205 else if (rm == 6) {
206 switch (op2) {
207 case 0x00:
208 /* invalidate entire data cache */
209 return (0);
210
211 case 0x01:
212 /* invalidate data cache line */
213 return (0);
214
215 case 0x02:
216 /* invalidate data cache line */
217 return (0);
218 }
219 }
220 else if (rm == 10) {
221 switch (op2) {
222 case 0x01:
223 /* clean data cache line */
224 return (0);
225
226 case 0x02:
227 /* clean data cache line */
228 return (0);
229
230 case 0x04:
231 /* drain write buffer */
232 return (0);
233 }
234
235 return (1);
236 }
237
238 return (1);
239}
240
241/* TLB functions */
242static
243int cp15_set_reg8 (arm_t *c, arm_copr15_t *p)
244{
245 unsigned rm, op2;
246
247 rm = arm_ir_rm (c->ir);
248 op2 = arm_get_bits (c->ir, 5, 3);
249
250 if (rm == 5) {
251 switch (op2) {
252 case 0x00:
253 /* invalidate entire instruction tlb */
254 return (0);
255
256 case 0x01:
257 /* invalidate instruction tlb single entry */
258 return (0);
259 }
260 }
261 else if (rm == 6) {
262 switch (op2) {
263 case 0x00:
264 /* invalidate entire data tlb */
265 return (0);
266
267 case 0x01:
268 /* invalidate data tlb single entry */
269 return (0);
270 }
271 }
272 else if (rm == 7) {
273 switch (op2) {
274 case 0x00:
275 /* invalidate entire unified tlb */
276 return (0);
277
278 case 0x01:
279 /* invalidate unified tlb single entry */
280 return (0);
281 }
282 }
283
284 return (1);
285}
286
287static
288int cp15_set_reg15 (arm_t *c, arm_copr15_t *p, uint32_t val)
289{
290 unsigned rm;
291
292 rm = arm_ir_rm (c->ir);
293 /* op2 = arm_get_bits (c->ir, 5, 3); */
294
295 if (rm == 1) {
296 /* xscale: coprocessor access register */
297 p->reg[15] = val & 0x00003fff;
298 return (0);
299 }
300
301 return (1);
302}
303
304static
305int cp15_op_mrc (arm_t *c, arm_copr_t *p)
306{
307 arm_copr15_t *p15;
308 unsigned op2;
309 uint32_t val;
310
311 p15 = p->ext;
312
313 op2 = arm_get_bits (c->ir, 5, 3);
314
315 switch (arm_ir_rn (c->ir)) {
316 case 0x00: /* ID register */
317 if (cp15_get_reg0 (c, p15, op2, &val)) {
318 return (1);
319 }
320 break;
321
322 case 0x01: /* control register */
323 if (cp15_get_reg1 (c, p15, op2, &val)) {
324 return (1);
325 }
326 break;
327
328 case 0x02: /* translation table base */
329 val = p15->reg[2];
330 break;
331
332 case 0x03: /* domain access control */
333 val = p15->reg[2];
334 break;
335
336 case 0x05: /* fault status */
337 val = p15->reg[5];
338 break;
339
340 case 0x06: /* fault address */
341 val = p15->reg[6];
342 break;
343
344 case 0x0f: /* implementation defined */
345 val = p15->reg[15];
346 break;
347
348 default:
349 return (1);
350 }
351
352 if (arm_rd_is_pc (c->ir)) {
353 arm_set_cpsr (c, (arm_get_cpsr (c) & ~ARM_PSR_CC) | (val & ARM_PSR_CC));
354 }
355 else {
356 arm_set_rd (c, c->ir, val & 0xffffffff);
357 }
358
359 return (0);
360}
361
362static
363int cp15_op_mcr (arm_t *c, arm_copr_t *p)
364{
365 arm_copr15_t *p15;
366 unsigned op2;
367 uint32_t val;
368
369 p15 = p->ext;
370
371 op2 = arm_get_bits (c->ir, 5, 3);
372
373 val = arm_get_rd (c, c->ir);
374
375 /* conservative flushing of translation buffer */
376 arm_tbuf_flush (c);
377
378 switch (arm_ir_rn (c->ir)) {
379 case 0x00: /* id register */
380 return (1);
381
382 case 0x01: /* control register */
383 return (cp15_set_reg1 (c, p15, op2, val));
384
385 case 0x02: /* translation table base */
386 p15->reg[2] = val & 0xffffc000;
387 break;
388
389 case 0x03: /* domain access control */
390 p15->reg[3] = val & 0xffffffff;
391 break;
392
393 case 0x07:
394 return (cp15_set_reg7 (c, p15));
395
396 case 0x08:
397 return (cp15_set_reg8 (c, p15));
398
399 case 0x0f: /* implementation defined */
400 return (cp15_set_reg15 (c, p15, val));
401
402 default:
403 return (1);
404 }
405
406 return (0);
407}
408
409static
410int cp15_reset (arm_t *c, arm_copr_t *p)
411{
412 unsigned i;
413 arm_copr15_t *p15;
414
415 p15 = p->ext;
416
417 if (c->bigendian) {
418 p15->reg[1] |= ARM_C15_CR_B;
419 }
420 else {
421 p15->reg[1] &= ~ARM_C15_CR_B;
422 }
423
424 for (i = 2; i < 16; i++) {
425 p15->reg[i] = 0;
426 }
427
428 return (0);
429}
430
431static
432int cp15_exec (arm_t *c, arm_copr_t *p)
433{
434 int r;
435 unsigned long pc;
436 char *op;
437
438 pc = arm_get_pc (c);
439
440 if (arm_is_privileged (c) == 0) {
441 return (1);
442 }
443
444 op = "?";
445
446 switch (c->ir & 0x00f00010) {
447 case 0x00000010: /* mcr */
448 op = "W";
449 r = cp15_op_mcr (c, p);
450 break;
451
452 case 0x00100010: /* mrc */
453 op = "R";
454 r = cp15_op_mrc (c, p);
455 break;
456
457 default:
458 r = 1;
459 break;
460 }
461
462 if (r == 0) {
463 arm_set_clk (c, 4, 1);
464 }
465
466 if (r) {
467 fprintf (stderr, "%08lX C15: %s Rd=%u Rn=%u Rm=%u op2=%u\n",
468 pc, op,
469 (unsigned) arm_ir_rd (c->ir),
470 (unsigned) arm_ir_rn (c->ir),
471 (unsigned) arm_ir_rm (c->ir),
472 (unsigned) arm_get_bits (c->ir, 5, 3)
473 ); fflush (stderr);
474 }
475
476 return (r);
477}