1 |
/* |
/* |
2 |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips.c,v 1.69 2006/10/07 02:05:21 debug Exp $ |
* $Id: cpu_mips.c,v 1.75 2007/02/18 09:19:47 debug Exp $ |
29 |
* |
* |
30 |
* MIPS core CPU emulation. |
* MIPS core CPU emulation. |
31 |
*/ |
*/ |
88 |
* Convert a register number into either 'r0', 'r31' etc, or a symbolic |
* Convert a register number into either 'r0', 'r31' etc, or a symbolic |
89 |
* name, depending on machine->show_symbolic_register_names. |
* name, depending on machine->show_symbolic_register_names. |
90 |
* |
* |
91 |
* NOTE: _NOT_ reentrant. |
* NOTE: This helper function is _NOT_ reentrant. |
92 |
*/ |
*/ |
93 |
static char *regname(struct machine *machine, int r) |
static char *regname(struct machine *machine, int r) |
94 |
{ |
{ |
304 |
debug(")"); |
debug(")"); |
305 |
} |
} |
306 |
|
|
307 |
|
/* Register the CPU's interrupts: */ |
308 |
|
for (i=2; i<8; i++) { |
309 |
|
struct interrupt template; |
310 |
|
char name[50]; |
311 |
|
snprintf(name, sizeof(name), "%s.%i", cpu->path, i); |
312 |
|
memset(&template, 0, sizeof(template)); |
313 |
|
template.line = 1 << (STATUS_IM_SHIFT + i); |
314 |
|
template.name = name; |
315 |
|
template.extra = cpu; |
316 |
|
template.interrupt_assert = mips_cpu_interrupt_assert; |
317 |
|
template.interrupt_deassert = mips_cpu_interrupt_deassert; |
318 |
|
interrupt_handler_register(&template); |
319 |
|
|
320 |
|
if (i == 7) |
321 |
|
INTERRUPT_CONNECT(name, cpu->cd.mips.irq_compare); |
322 |
|
} |
323 |
|
|
324 |
/* System coprocessor (0), and FPU (1): */ |
/* System coprocessor (0), and FPU (1): */ |
325 |
cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); |
cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); |
326 |
cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); |
cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); |
1821 |
|
|
1822 |
|
|
1823 |
/* |
/* |
1824 |
* mips_cpu_interrupt(): |
* mips_cpu_interrupt_assert(), mips_cpu_interrupt_deassert(): |
|
* |
|
|
* Cause an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
|
|
* interrupt. 0 and 1 are ignored (software interrupts). |
|
1825 |
* |
* |
1826 |
* If irq_nr is >= 8, then this function calls md_interrupt(). |
* Assert or deassert a MIPS CPU interrupt by masking in or out bits |
1827 |
|
* in the CAUSE register of coprocessor 0. |
1828 |
*/ |
*/ |
1829 |
int mips_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) |
void mips_cpu_interrupt_assert(struct interrupt *interrupt) |
1830 |
{ |
{ |
1831 |
if (irq_nr >= 8) { |
struct cpu *cpu = interrupt->extra; |
1832 |
if (cpu->machine->md_interrupt != NULL) |
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= interrupt->line; |
|
cpu->machine->md_interrupt(cpu->machine, |
|
|
cpu, irq_nr, 1); |
|
|
else |
|
|
fatal("mips_cpu_interrupt(): irq_nr = %i, " |
|
|
"but md_interrupt = NULL ?\n", irq_nr); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
if (irq_nr < 2) |
|
|
return 0; |
|
|
|
|
|
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= |
|
|
((1 << irq_nr) << STATUS_IM_SHIFT); |
|
|
|
|
|
return 1; |
|
1833 |
} |
} |
1834 |
|
void mips_cpu_interrupt_deassert(struct interrupt *interrupt) |
|
|
|
|
/* |
|
|
* mips_cpu_interrupt_ack(): |
|
|
* |
|
|
* Acknowledge an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
|
|
* interrupt. Interrupts 0..1 are ignored (software interrupts). |
|
|
* |
|
|
* If irq_nr is >= 8, then it is machine dependent, and md_interrupt() is |
|
|
* called. |
|
|
*/ |
|
|
int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) |
|
1835 |
{ |
{ |
1836 |
if (irq_nr >= 8) { |
struct cpu *cpu = interrupt->extra; |
1837 |
if (cpu->machine->md_interrupt != NULL) |
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~interrupt->line; |
|
cpu->machine->md_interrupt(cpu->machine, cpu, |
|
|
irq_nr, 0); |
|
|
else |
|
|
fatal("mips_cpu_interrupt_ack(): irq_nr = %i, " |
|
|
"but md_interrupt = NULL ?\n", irq_nr); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
if (irq_nr < 2) |
|
|
return 0; |
|
|
|
|
|
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= |
|
|
~((1 << irq_nr) << STATUS_IM_SHIFT); |
|
|
|
|
|
return 1; |
|
1838 |
} |
} |
1839 |
|
|
1840 |
|
|