/[gxemul]/trunk/src/cpus/cpu_arm_coproc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpus/cpu_arm_coproc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (13 years ago) by dpavlin
File MIME type: text/plain
File size: 13911 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


1 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_arm_coproc.c,v 1.24 2006/06/24 21:47:23 debug Exp $
29 *
30 * ARM coprocessor emulation.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <ctype.h>
38
39 #include "cpu.h"
40 #include "machine.h"
41 #include "misc.h"
42 #include "symbol.h"
43
44 #include "i80321reg.h"
45
46
47 /*
48 * arm_coproc_15():
49 *
50 * The system control coprocessor.
51 */
52 void arm_coproc_15(struct cpu *cpu, int opcode1, int opcode2, int l_bit,
53 int crn, int crm, int rd)
54 {
55 uint32_t old_control;
56
57 /* Some sanity checks: */
58 if (opcode1 != 0) {
59 fatal("arm_coproc_15: opcode1 = %i, should be 0\n", opcode1);
60 exit(1);
61 }
62 if (rd == ARM_PC) {
63 fatal("arm_coproc_15: rd = PC\n");
64 exit(1);
65 }
66
67 switch (crn) {
68
69 case 0: /*
70 * Main ID register (and Cache Type register, on XScale)
71 *
72 * Writes are supposed to be ignored, according to Intel docs.
73 */
74 switch (opcode2) {
75 case 0: if (l_bit)
76 cpu->cd.arm.r[rd] = cpu->cd.arm.cpu_type.cpu_id;
77 else
78 fatal("[ arm_coproc_15: attempt to write "
79 "to the Main ID register? ]\n");
80 break;
81 case 1: if (l_bit)
82 cpu->cd.arm.r[rd] = cpu->cd.arm.cachetype;
83 else
84 fatal("[ arm_coproc_15: attempt to write "
85 "to the Cache Type register? ]\n");
86 break;
87 default:fatal("[ arm_coproc_15: TODO: cr0, opcode2=%i ]\n",
88 opcode2);
89 exit(1);
90 }
91 break;
92
93 case 1: /* Control Register: */
94 if (l_bit) {
95 /* Load from the normal/aux control register: */
96 switch (opcode2) {
97 case 0: cpu->cd.arm.r[rd] = cpu->cd.arm.control;
98 break;
99 case 1: cpu->cd.arm.r[rd] = cpu->cd.arm.auxctrl;
100 break;
101 default:fatal("Unimplemented opcode2 = %i\n", opcode2);
102 fatal("(opcode1=%i crn=%i crm=%i rd=%i l=%i)\n",
103 opcode1, crn, crm, rd, l_bit);
104 exit(1);
105 }
106 return;
107 }
108
109 if (opcode2 == 1) {
110 /* Write to auxctrl: */
111 old_control = cpu->cd.arm.auxctrl;
112 cpu->cd.arm.auxctrl = cpu->cd.arm.r[rd];
113 if ((old_control & ARM_AUXCTRL_MD) !=
114 (cpu->cd.arm.auxctrl & ARM_AUXCTRL_MD)) {
115 debug("[ setting the minidata cache attribute"
116 " to 0x%x ]\n", (cpu->cd.arm.auxctrl &
117 ARM_AUXCTRL_MD) >> ARM_AUXCTRL_MD_SHIFT);
118 }
119 if ((old_control & ARM_AUXCTRL_K) !=
120 (cpu->cd.arm.auxctrl & ARM_AUXCTRL_K)) {
121 debug("[ %s write buffer coalescing ]\n",
122 cpu->cd.arm.auxctrl & ARM_AUXCTRL_K?
123 "Disabling" : "Enabling");
124 }
125 return;
126 } else if (opcode2 != 0) {
127 fatal("Unimplemented write, opcode2 = %i\n", opcode2);
128 fatal("(opcode1=%i crn=%i crm=%i rd=%i l=%i)\n",
129 opcode1, crn, crm, rd, l_bit);
130 exit(1);
131 }
132
133 /*
134 * Write to control: Check each bit individually:
135 */
136 old_control = cpu->cd.arm.control;
137 cpu->cd.arm.control = cpu->cd.arm.r[rd];
138 if ((old_control & ARM_CONTROL_MMU) !=
139 (cpu->cd.arm.control & ARM_CONTROL_MMU)) {
140 debug("[ %s the MMU ]\n", cpu->cd.arm.control &
141 ARM_CONTROL_MMU? "enabling" : "disabling");
142 cpu->translate_v2p =
143 cpu->cd.arm.control & ARM_CONTROL_MMU?
144 arm_translate_v2p_mmu : arm_translate_v2p;
145 }
146 if ((old_control & ARM_CONTROL_ALIGN) !=
147 (cpu->cd.arm.control & ARM_CONTROL_ALIGN))
148 debug("[ %s alignment checks ]\n", cpu->cd.arm.control &
149 ARM_CONTROL_ALIGN? "enabling" : "disabling");
150 if ((old_control & ARM_CONTROL_CACHE) !=
151 (cpu->cd.arm.control & ARM_CONTROL_CACHE))
152 debug("[ %s the [data] cache ]\n", cpu->cd.arm.control &
153 ARM_CONTROL_CACHE? "enabling" : "disabling");
154 if ((old_control & ARM_CONTROL_WBUFFER) !=
155 (cpu->cd.arm.control & ARM_CONTROL_WBUFFER))
156 debug("[ %s the write buffer ]\n", cpu->cd.arm.control &
157 ARM_CONTROL_WBUFFER? "enabling" : "disabling");
158 if ((old_control & ARM_CONTROL_BIG) !=
159 (cpu->cd.arm.control & ARM_CONTROL_BIG)) {
160 fatal("ERROR: Trying to switch endianness. Not "
161 "supported yet.\n");
162 exit(1);
163 }
164 if ((old_control & ARM_CONTROL_ICACHE) !=
165 (cpu->cd.arm.control & ARM_CONTROL_ICACHE))
166 debug("[ %s the icache ]\n", cpu->cd.arm.control &
167 ARM_CONTROL_ICACHE? "enabling" : "disabling");
168 /* TODO: More bits. */
169 break;
170
171 case 2: /* Translation Table Base register: */
172 /* NOTE: 16 KB aligned. */
173 if (l_bit)
174 cpu->cd.arm.r[rd] = cpu->cd.arm.ttb & 0xffffc000;
175 else {
176 cpu->cd.arm.ttb = cpu->cd.arm.r[rd];
177 if (cpu->cd.arm.ttb & 0x3fff)
178 fatal("[ WARNING! low bits of new TTB non-"
179 "zero? 0x%08x ]\n", cpu->cd.arm.ttb);
180 cpu->cd.arm.ttb &= 0xffffc000;
181 }
182 break;
183
184 case 3: /* Domain Access Control Register: */
185 if (l_bit)
186 cpu->cd.arm.r[rd] = cpu->cd.arm.dacr;
187 else
188 cpu->cd.arm.dacr = cpu->cd.arm.r[rd];
189 break;
190
191 case 5: /* Fault Status Register: */
192 /* Note: Only the lowest 8 bits are defined. */
193 if (l_bit)
194 cpu->cd.arm.r[rd] = cpu->cd.arm.fsr & 0xff;
195 else
196 cpu->cd.arm.fsr = cpu->cd.arm.r[rd] & 0xff;
197 break;
198
199 case 6: /* Fault Address Register: */
200 if (l_bit)
201 cpu->cd.arm.r[rd] = cpu->cd.arm.far;
202 else
203 cpu->cd.arm.far = cpu->cd.arm.r[rd];
204 break;
205
206 case 7: /* Cache functions: */
207 if (l_bit) {
208 fatal("[ arm_coproc_15: attempt to read cr7? ]\n");
209 return;
210 }
211 /* debug("[ arm_coproc_15: cache op: TODO ]\n"); */
212 /* TODO: */
213 break;
214
215 case 8: /* TLB functions: */
216 if (l_bit) {
217 fatal("[ arm_coproc_15: attempt to read cr8? ]\n");
218 return;
219 }
220 /* fatal("[ arm_coproc_15: TLB: op2=%i crm=%i rd=0x%08x ]\n",
221 opcode2, crm, cpu->cd.arm.r[rd]); */
222 if (opcode2 == 0)
223 cpu->invalidate_translation_caches(cpu, 0,
224 INVALIDATE_ALL);
225 else
226 cpu->invalidate_translation_caches(cpu,
227 cpu->cd.arm.r[rd], INVALIDATE_VADDR);
228 break;
229
230 case 9: /* Cache lockdown: */
231 fatal("[ arm_coproc_15: cache lockdown: TODO ]\n");
232 /* TODO */
233 break;
234
235 case 13:/* Process ID Register: */
236 if (opcode2 != 0)
237 fatal("[ arm_coproc_15: PID access, but opcode2 "
238 "= %i? (should be 0) ]\n", opcode2);
239 if (crm != 0)
240 fatal("[ arm_coproc_15: PID access, but crm "
241 "= %i? (should be 0) ]\n", crm);
242 if (l_bit)
243 cpu->cd.arm.r[rd] = cpu->cd.arm.pid;
244 else
245 cpu->cd.arm.pid = cpu->cd.arm.r[rd];
246 if (cpu->cd.arm.pid != 0) {
247 fatal("ARM TODO: pid!=0. Fast Context Switch"
248 " Extension not implemented yet\n");
249 exit(1);
250 }
251 break;
252
253 /* case 14: */
254 /* Breakpoint registers on XScale (possibly others?) */
255 /* TODO */
256 /* break; */
257
258 case 15:/* IMPLEMENTATION DEPENDENT! */
259 switch (crm) {
260 case 1: /*
261 * On XScale (and others? TODO), this is the
262 * CoProcessor Access Register. Note/TODO: This isn't
263 * really used throughout the rest of the code yet.
264 */
265 if (l_bit)
266 cpu->cd.arm.r[rd] = cpu->cd.arm.cpar;
267 else
268 cpu->cd.arm.cpar = cpu->cd.arm.r[rd];
269 break;
270 default:fatal("[ arm_coproc_15: TODO: IMPLEMENTATION "
271 "DEPENDENT! ]\n");
272 exit(1);
273 }
274 break;
275
276 default:fatal("arm_coproc_15: unimplemented crn = %i\n", crn);
277 fatal("(opcode1=%i opcode2=%i crm=%i rd=%i l=%i)\n",
278 opcode1, opcode2, crm, rd, l_bit);
279 exit(1);
280 }
281 }
282
283
284 /*
285 * arm_coproc_i80321_6():
286 *
287 * Intel 80321 coprocessor 6.
288 */
289 void arm_coproc_i80321_6(struct cpu *cpu, int opcode1, int opcode2, int l_bit,
290 int crn, int crm, int rd)
291 {
292 switch (crm) {
293
294 case 0: switch (crn) {
295 case 0: if (l_bit) {
296 cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_inten;
297 fatal("TODO: XScale read from inten?\n");
298 exit(1);
299 } else
300 cpu->cd.arm.i80321_inten = cpu->cd.arm.r[rd];
301 break;
302 case 4: if (l_bit)
303 cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_isteer;
304 else {
305 cpu->cd.arm.i80321_isteer = cpu->cd.arm.r[rd];
306 if (cpu->cd.arm.r[rd] != 0) {
307 fatal("ARM xscale interrupt steering"
308 " is not yet implemented\n");
309 exit(1);
310 }
311 }
312 break;
313 case 8: if (l_bit)
314 cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_isrc;
315 else {
316 cpu->cd.arm.i80321_isrc = cpu->cd.arm.r[rd];
317 fatal("TODO: XScale int ack?\n");
318 exit(1);
319 }
320 break;
321 default:goto unknown;
322 }
323 break;
324
325 case 1: /* fatal("TIMER opcode1=%i opcode2=%i crn="
326 "%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit); */
327
328 switch (crn) {
329 case 0: /* tmr0: */
330 if (l_bit)
331 cpu->cd.arm.r[rd] = cpu->cd.arm.tmr0;
332 else
333 cpu->cd.arm.tmr0 = cpu->cd.arm.r[rd];
334 break;
335 case 1: /* tmr1: */
336 if (l_bit)
337 cpu->cd.arm.r[rd] = cpu->cd.arm.tmr1;
338 else
339 cpu->cd.arm.tmr1 = cpu->cd.arm.r[rd];
340 break;
341 case 2: /* tcr0: */
342 if (l_bit) {
343 /* NOTE/TODO: Ugly hack: timer increment */
344 cpu->cd.arm.tcr0 ++;
345 cpu->cd.arm.r[rd] = cpu->cd.arm.tcr0;
346 } else {
347 cpu->cd.arm.tcr0 = cpu->cd.arm.r[rd];
348 }
349 break;
350 case 3: /* tcr1: */
351 if (l_bit) {
352 /* NOTE/TODO: Ugly hack: timer increment */
353 cpu->cd.arm.tcr1 ++;
354 cpu->cd.arm.r[rd] = cpu->cd.arm.tcr1;
355 } else {
356 cpu->cd.arm.tcr1 = cpu->cd.arm.r[rd];
357 }
358 break;
359 case 4: /* trr0: */
360 if (l_bit)
361 cpu->cd.arm.r[rd] = cpu->cd.arm.trr0;
362 else
363 cpu->cd.arm.trr0 = cpu->cd.arm.r[rd];
364 break;
365 case 5: /* trr1: */
366 if (l_bit)
367 cpu->cd.arm.r[rd] = cpu->cd.arm.trr1;
368 else
369 cpu->cd.arm.trr1 = cpu->cd.arm.r[rd];
370 break;
371 case 6: /* tisr: */
372 if (l_bit)
373 cpu->cd.arm.r[rd] = cpu->cd.arm.tisr;
374 else {
375 /* Writing clears interrupts: */
376 cpu->cd.arm.tisr &= ~cpu->cd.arm.r[rd];
377 if (!(cpu->cd.arm.tisr & TISR_TMR0))
378 cpu_interrupt_ack(cpu, 9); /* TMR0 */
379 if (!(cpu->cd.arm.tisr & TISR_TMR1))
380 cpu_interrupt_ack(cpu, 10); /* TMR1 */
381 }
382 break;
383 case 7: /* wdtcr: */
384 if (l_bit)
385 cpu->cd.arm.r[rd] = cpu->cd.arm.wdtcr;
386 else
387 cpu->cd.arm.wdtcr = cpu->cd.arm.r[rd];
388 break;
389 default:goto unknown;
390 }
391 break;
392
393 default:goto unknown;
394 }
395
396 return;
397
398 unknown:
399 fatal("arm_coproc_i80321_6: unimplemented opcode1=%i opcode2=%i crn="
400 "%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit);
401 exit(1);
402 }
403
404
405 /*
406 * arm_coproc_xscale_14():
407 *
408 * XScale coprocessor 14, Performance Monitoring Unit.
409 */
410 void arm_coproc_xscale_14(struct cpu *cpu, int opcode1, int opcode2, int l_bit,
411 int crn, int crm, int rd)
412 {
413 if (opcode2 != 0) {
414 fatal("TODO: opcode2 = %i\n", opcode2);
415 goto unknown;
416 }
417
418 switch (crm) {
419
420 case 0: switch (crn) {
421 case 0: if (l_bit)
422 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmnc;
423 else
424 cpu->cd.arm.xsc1_pmnc = cpu->cd.arm.r[rd];
425 break;
426 case 1: if (l_bit)
427 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_ccnt;
428 else
429 cpu->cd.arm.xsc1_ccnt = cpu->cd.arm.r[rd];
430 break;
431 case 2: if (l_bit)
432 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmn0;
433 else
434 cpu->cd.arm.xsc1_pmn0 = cpu->cd.arm.r[rd];
435 break;
436 case 3: if (l_bit)
437 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmn1;
438 else
439 cpu->cd.arm.xsc1_pmn1 = cpu->cd.arm.r[rd];
440 break;
441 case 7: /* UNIMPLEMENTED!!! TODO */
442 /* Possibly some kind of idle or sleep function. */
443 break;
444 default:goto unknown;
445 }
446 break;
447
448 case 1: switch (crn) {
449 case 0: if (l_bit)
450 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmnc;
451 else
452 cpu->cd.arm.xsc2_pmnc = cpu->cd.arm.r[rd];
453 break;
454 case 1: if (l_bit)
455 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_ccnt;
456 else
457 cpu->cd.arm.xsc2_ccnt = cpu->cd.arm.r[rd];
458 break;
459 case 4: if (l_bit)
460 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_inten;
461 else
462 cpu->cd.arm.xsc2_inten = cpu->cd.arm.r[rd];
463 break;
464 case 5: if (l_bit)
465 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_flag;
466 else
467 cpu->cd.arm.xsc2_flag = cpu->cd.arm.r[rd];
468 break;
469 case 8: if (l_bit)
470 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_evtsel;
471 else
472 cpu->cd.arm.xsc2_evtsel = cpu->cd.arm.r[rd];
473 break;
474 default:goto unknown;
475 }
476 break;
477
478 case 2: switch (crn) {
479 case 0: if (l_bit)
480 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn0;
481 else
482 cpu->cd.arm.xsc2_pmn0 = cpu->cd.arm.r[rd];
483 break;
484 case 1: if (l_bit)
485 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn1;
486 else
487 cpu->cd.arm.xsc2_pmn1 = cpu->cd.arm.r[rd];
488 break;
489 case 2: if (l_bit)
490 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn2;
491 else
492 cpu->cd.arm.xsc2_pmn2 = cpu->cd.arm.r[rd];
493 break;
494 case 3: if (l_bit)
495 cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn3;
496 else
497 cpu->cd.arm.xsc2_pmn3 = cpu->cd.arm.r[rd];
498 break;
499 default:goto unknown;
500 }
501 break;
502
503 default:goto unknown;
504 }
505
506 return;
507
508 unknown:
509 fatal("arm_coproc_xscale_14: unimplemented opcode1=%i opcode2="
510 "%i crn=%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn,
511 crm, rd, l_bit);
512 exit(1);
513 }
514

  ViewVC Help
Powered by ViewVC 1.1.26