/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months 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 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 26 * $Id: cpu_arm_coproc.c,v 1.24 2006/06/24 21:47:23 debug Exp $
29 dpavlin 14 *
30     * ARM coprocessor emulation.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36 dpavlin 22 #include <unistd.h>
37 dpavlin 14 #include <ctype.h>
38    
39     #include "cpu.h"
40 dpavlin 24 #include "machine.h"
41 dpavlin 14 #include "misc.h"
42     #include "symbol.h"
43    
44 dpavlin 22 #include "i80321reg.h"
45 dpavlin 14
46 dpavlin 22
47 dpavlin 14 /*
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 dpavlin 22 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 dpavlin 14 opcode2);
89 dpavlin 22 exit(1);
90     }
91 dpavlin 14 break;
92    
93     case 1: /* Control Register: */
94     if (l_bit) {
95 dpavlin 22 /* 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 dpavlin 14 return;
107     }
108 dpavlin 22
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 dpavlin 14 /*
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 dpavlin 18 (cpu->cd.arm.control & ARM_CONTROL_MMU)) {
140 dpavlin 14 debug("[ %s the MMU ]\n", cpu->cd.arm.control &
141     ARM_CONTROL_MMU? "enabling" : "disabling");
142 dpavlin 26 cpu->translate_v2p =
143 dpavlin 18 cpu->cd.arm.control & ARM_CONTROL_MMU?
144 dpavlin 26 arm_translate_v2p_mmu : arm_translate_v2p;
145 dpavlin 18 }
146 dpavlin 14 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 dpavlin 18 cpu->invalidate_translation_caches(cpu, 0,
224 dpavlin 14 INVALIDATE_ALL);
225     else
226 dpavlin 18 cpu->invalidate_translation_caches(cpu,
227 dpavlin 14 cpu->cd.arm.r[rd], INVALIDATE_VADDR);
228     break;
229    
230 dpavlin 20 case 9: /* Cache lockdown: */
231 dpavlin 22 fatal("[ arm_coproc_15: cache lockdown: TODO ]\n");
232 dpavlin 20 /* TODO */
233     break;
234    
235 dpavlin 14 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 dpavlin 22 /* case 14: */
254     /* Breakpoint registers on XScale (possibly others?) */
255     /* TODO */
256     /* break; */
257    
258 dpavlin 18 case 15:/* IMPLEMENTATION DEPENDENT! */
259 dpavlin 22 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 dpavlin 14 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 dpavlin 22 * arm_coproc_i80321_6():
286 dpavlin 14 *
287 dpavlin 22 * Intel 80321 coprocessor 6.
288 dpavlin 14 */
289 dpavlin 22 void arm_coproc_i80321_6(struct cpu *cpu, int opcode1, int opcode2, int l_bit,
290 dpavlin 14 int crn, int crm, int rd)
291     {
292     switch (crm) {
293 dpavlin 22
294     case 0: switch (crn) {
295 dpavlin 24 case 0: if (l_bit) {
296 dpavlin 22 cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_inten;
297 dpavlin 24 fatal("TODO: XScale read from inten?\n");
298     exit(1);
299     } else
300 dpavlin 22 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 dpavlin 14 break;
324 dpavlin 22
325 dpavlin 24 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 dpavlin 22
328 dpavlin 14 switch (crn) {
329     case 0: /* tmr0: */
330 dpavlin 22 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 dpavlin 14 break;
335 dpavlin 22 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 dpavlin 14 case 2: /* tcr0: */
342 dpavlin 22 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 dpavlin 14 break;
350 dpavlin 22 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 dpavlin 14 case 4: /* trr0: */
360 dpavlin 22 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 dpavlin 14 break;
365 dpavlin 22 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 dpavlin 14 case 6: /* tisr: */
372 dpavlin 22 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 dpavlin 14 break;
383 dpavlin 22 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 dpavlin 14 }
391     break;
392 dpavlin 22
393     default:goto unknown;
394 dpavlin 14 }
395 dpavlin 22
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 dpavlin 14 }
403    
404    
405     /*
406 dpavlin 22 * arm_coproc_xscale_14():
407 dpavlin 14 *
408 dpavlin 22 * XScale coprocessor 14, Performance Monitoring Unit.
409 dpavlin 14 */
410 dpavlin 22 void arm_coproc_xscale_14(struct cpu *cpu, int opcode1, int opcode2, int l_bit,
411 dpavlin 14 int crn, int crm, int rd)
412     {
413 dpavlin 22 if (opcode2 != 0) {
414     fatal("TODO: opcode2 = %i\n", opcode2);
415     goto unknown;
416     }
417    
418 dpavlin 14 switch (crm) {
419 dpavlin 22
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 dpavlin 14 break;
447 dpavlin 22
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 dpavlin 14 }
505 dpavlin 22
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 dpavlin 14 }
514    

  ViewVC Help
Powered by ViewVC 1.1.26