--- trunk/src/cpus/cpu_arm_coproc.c 2007/10/08 16:19:23 20 +++ trunk/src/cpus/cpu_arm_coproc.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_arm_coproc.c,v 1.15 2005/11/05 21:59:01 debug Exp $ + * $Id: cpu_arm_coproc.c,v 1.22 2006/02/17 18:38:30 debug Exp $ * * ARM coprocessor emulation. */ @@ -33,12 +33,15 @@ #include #include #include +#include #include #include "cpu.h" #include "misc.h" #include "symbol.h" +#include "i80321reg.h" + /* * arm_coproc_15(): @@ -62,21 +65,70 @@ switch (crn) { - case 0: /* Main ID register: */ - if (opcode2 != 0) - fatal("[ arm_coproc_15: TODO: cr0, opcode2=%i ]\n", + case 0: /* + * Main ID register (and Cache Type register, on XScale) + * + * Writes are supposed to be ignored, according to Intel docs. + */ + switch (opcode2) { + case 0: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.cpu_type.cpu_id; + else + fatal("[ arm_coproc_15: attempt to write " + "to the Main ID register? ]\n"); + break; + case 1: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.cachetype; + else + fatal("[ arm_coproc_15: attempt to write " + "to the Cache Type register? ]\n"); + break; + default:fatal("[ arm_coproc_15: TODO: cr0, opcode2=%i ]\n", opcode2); - if (l_bit) - cpu->cd.arm.r[rd] = cpu->cd.arm.cpu_type.cpu_id; - else - fatal("[ arm_coproc_15: attempt to write to cr0? ]\n"); + exit(1); + } break; case 1: /* Control Register: */ if (l_bit) { - cpu->cd.arm.r[rd] = cpu->cd.arm.control; + /* Load from the normal/aux control register: */ + switch (opcode2) { + case 0: cpu->cd.arm.r[rd] = cpu->cd.arm.control; + break; + case 1: cpu->cd.arm.r[rd] = cpu->cd.arm.auxctrl; + break; + default:fatal("Unimplemented opcode2 = %i\n", opcode2); + fatal("(opcode1=%i crn=%i crm=%i rd=%i l=%i)\n", + opcode1, crn, crm, rd, l_bit); + exit(1); + } + return; + } + + if (opcode2 == 1) { + /* Write to auxctrl: */ + old_control = cpu->cd.arm.auxctrl; + cpu->cd.arm.auxctrl = cpu->cd.arm.r[rd]; + if ((old_control & ARM_AUXCTRL_MD) != + (cpu->cd.arm.auxctrl & ARM_AUXCTRL_MD)) { + debug("[ setting the minidata cache attribute" + " to 0x%x ]\n", (cpu->cd.arm.auxctrl & + ARM_AUXCTRL_MD) >> ARM_AUXCTRL_MD_SHIFT); + } + if ((old_control & ARM_AUXCTRL_K) != + (cpu->cd.arm.auxctrl & ARM_AUXCTRL_K)) { + debug("[ %s write buffer coalescing ]\n", + cpu->cd.arm.auxctrl & ARM_AUXCTRL_K? + "Disabling" : "Enabling"); + } return; + } else if (opcode2 != 0) { + fatal("Unimplemented write, opcode2 = %i\n", opcode2); + fatal("(opcode1=%i crn=%i crm=%i rd=%i l=%i)\n", + opcode1, crn, crm, rd, l_bit); + exit(1); } + /* * Write to control: Check each bit individually: */ @@ -175,6 +227,7 @@ break; case 9: /* Cache lockdown: */ + fatal("[ arm_coproc_15: cache lockdown: TODO ]\n"); /* TODO */ break; @@ -196,8 +249,27 @@ } break; + /* case 14: */ + /* Breakpoint registers on XScale (possibly others?) */ + /* TODO */ + /* break; */ + case 15:/* IMPLEMENTATION DEPENDENT! */ - debug("[ arm_coproc_15: TODO: IMPLEMENTATION DEPENDENT! ]\n"); + switch (crm) { + case 1: /* + * On XScale (and others? TODO), this is the + * CoProcessor Access Register. Note/TODO: This isn't + * really used throughout the rest of the code yet. + */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.cpar; + else + cpu->cd.arm.cpar = cpu->cd.arm.r[rd]; + break; + default:fatal("[ arm_coproc_15: TODO: IMPLEMENTATION " + "DEPENDENT! ]\n"); + exit(1); + } break; default:fatal("arm_coproc_15: unimplemented crn = %i\n", crn); @@ -208,60 +280,233 @@ } -/*****************************************************************************/ - - /* - * arm_coproc_i80321(): + * arm_coproc_i80321_6(): * - * Intel 80321 coprocessor. + * Intel 80321 coprocessor 6. */ -void arm_coproc_i80321(struct cpu *cpu, int opcode1, int opcode2, int l_bit, +void arm_coproc_i80321_6(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd) { switch (crm) { - case 0: fatal("[ 80321: crm 0: TODO ]\n"); + + case 0: switch (crn) { + case 0: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_inten; + else + cpu->cd.arm.i80321_inten = cpu->cd.arm.r[rd]; + break; + case 4: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_isteer; + else { + cpu->cd.arm.i80321_isteer = cpu->cd.arm.r[rd]; + if (cpu->cd.arm.r[rd] != 0) { + fatal("ARM xscale interrupt steering" + " is not yet implemented\n"); + exit(1); + } + } + break; + case 8: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_isrc; + else { + cpu->cd.arm.i80321_isrc = cpu->cd.arm.r[rd]; + fatal("TODO: XScale int ack?\n"); + exit(1); + } + break; + default:goto unknown; + } break; - case 1: fatal("[ 80321: crm 1: TODO ]\n"); + + case 1: +/* fatal("TIMER opcode1=%i opcode2=%i crn=" + "%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit); */ + switch (crn) { case 0: /* tmr0: */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.tmr0; + else + cpu->cd.arm.tmr0 = cpu->cd.arm.r[rd]; + break; + case 1: /* tmr1: */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.tmr1; + else + cpu->cd.arm.tmr1 = cpu->cd.arm.r[rd]; break; case 2: /* tcr0: */ + if (l_bit) { + /* NOTE/TODO: Ugly hack: timer increment */ + cpu->cd.arm.tcr0 ++; + cpu->cd.arm.r[rd] = cpu->cd.arm.tcr0; + } else { + cpu->cd.arm.tcr0 = cpu->cd.arm.r[rd]; + } + break; + case 3: /* tcr1: */ + if (l_bit) { + /* NOTE/TODO: Ugly hack: timer increment */ + cpu->cd.arm.tcr1 ++; + cpu->cd.arm.r[rd] = cpu->cd.arm.tcr1; + } else { + cpu->cd.arm.tcr1 = cpu->cd.arm.r[rd]; + } break; case 4: /* trr0: */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.trr0; + else + cpu->cd.arm.trr0 = cpu->cd.arm.r[rd]; + break; + case 5: /* trr1: */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.trr1; + else + cpu->cd.arm.trr1 = cpu->cd.arm.r[rd]; break; case 6: /* tisr: */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.tisr; + else { + /* Writing clears interrupts: */ + cpu->cd.arm.tisr &= ~cpu->cd.arm.r[rd]; + if (!(cpu->cd.arm.tisr & TISR_TMR0)) + cpu_interrupt_ack(cpu, 9); /* TMR0 */ + if (!(cpu->cd.arm.tisr & TISR_TMR1)) + cpu_interrupt_ack(cpu, 10); /* TMR1 */ + } break; - default:fatal("arm_coproc_i80321: unimplemented crn = %i\n", - crn); - fatal("(opcode1=%i opcode2=%i crm=%i rd=%i l=%i)\n", - opcode1, opcode2, crm, rd, l_bit); - exit(1); + case 7: /* wdtcr: */ + if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.wdtcr; + else + cpu->cd.arm.wdtcr = cpu->cd.arm.r[rd]; + break; + default:goto unknown; } break; - default:fatal("arm_coproc_i80321: unimplemented opcode1=%i opcode2=%i" - " crn=%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, - crn, crm, rd, l_bit); - exit(1); + + default:goto unknown; } + + return; + +unknown: + fatal("arm_coproc_i80321_6: unimplemented opcode1=%i opcode2=%i crn=" + "%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit); + exit(1); } /* - * arm_coproc_i80321_14(): + * arm_coproc_xscale_14(): * - * Intel 80321 coprocessor 14. + * XScale coprocessor 14, Performance Monitoring Unit. */ -void arm_coproc_i80321_14(struct cpu *cpu, int opcode1, int opcode2, int l_bit, +void arm_coproc_xscale_14(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd) { + if (opcode2 != 0) { + fatal("TODO: opcode2 = %i\n", opcode2); + goto unknown; + } + switch (crm) { - case 0: fatal("[ 80321_14: crm 0: TODO ]\n"); + + case 0: switch (crn) { + case 0: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmnc; + else + cpu->cd.arm.xsc1_pmnc = cpu->cd.arm.r[rd]; + break; + case 1: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_ccnt; + else + cpu->cd.arm.xsc1_ccnt = cpu->cd.arm.r[rd]; + break; + case 2: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmn0; + else + cpu->cd.arm.xsc1_pmn0 = cpu->cd.arm.r[rd]; + break; + case 3: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmn1; + else + cpu->cd.arm.xsc1_pmn1 = cpu->cd.arm.r[rd]; + break; + case 7: /* UNIMPLEMENTED!!! TODO */ + /* Possibly some kind of idle or sleep function. */ + break; + default:goto unknown; + } break; - default:fatal("arm_coproc_i80321_14: unimplemented opcode1=%i opcode2=" - "%i crn=%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, - crn, crm, rd, l_bit); - exit(1); + + case 1: switch (crn) { + case 0: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmnc; + else + cpu->cd.arm.xsc2_pmnc = cpu->cd.arm.r[rd]; + break; + case 1: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_ccnt; + else + cpu->cd.arm.xsc2_ccnt = cpu->cd.arm.r[rd]; + break; + case 4: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_inten; + else + cpu->cd.arm.xsc2_inten = cpu->cd.arm.r[rd]; + break; + case 5: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_flag; + else + cpu->cd.arm.xsc2_flag = cpu->cd.arm.r[rd]; + break; + case 8: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_evtsel; + else + cpu->cd.arm.xsc2_evtsel = cpu->cd.arm.r[rd]; + break; + default:goto unknown; + } + break; + + case 2: switch (crn) { + case 0: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn0; + else + cpu->cd.arm.xsc2_pmn0 = cpu->cd.arm.r[rd]; + break; + case 1: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn1; + else + cpu->cd.arm.xsc2_pmn1 = cpu->cd.arm.r[rd]; + break; + case 2: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn2; + else + cpu->cd.arm.xsc2_pmn2 = cpu->cd.arm.r[rd]; + break; + case 3: if (l_bit) + cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn3; + else + cpu->cd.arm.xsc2_pmn3 = cpu->cd.arm.r[rd]; + break; + default:goto unknown; + } + break; + + default:goto unknown; } + + return; + +unknown: + fatal("arm_coproc_xscale_14: unimplemented opcode1=%i opcode2=" + "%i crn=%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, + crm, rd, l_bit); + exit(1); }