On Fri, Feb 11, 2011 at 1:11 AM, Michael Walle <mich...@walle.cc> wrote: > This patch adds the interrupt controller of the lm32. Because the PIC is > accessed through special control registers and opcodes, there are callbacks > from the lm32 translation code to this model. > > Signed-off-by: Michael Walle <mich...@walle.cc> > --- > hw/lm32_pic.c | 191 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/lm32_pic.h | 10 +++ > hw/lm32_pic_cpu.c | 37 ++++++++++ > trace-events | 9 +++ > 4 files changed, 247 insertions(+), 0 deletions(-) > create mode 100644 hw/lm32_pic.c > create mode 100644 hw/lm32_pic.h > create mode 100644 hw/lm32_pic_cpu.c > > diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c > new file mode 100644 > index 0000000..dbef535 > --- /dev/null > +++ b/hw/lm32_pic.c > @@ -0,0 +1,191 @@ > +/* > + * LatticeMico32 CPU interrupt controller logic. > + * > + * Copyright (c) 2010 Michael Walle <mich...@walle.cc> > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > + > +#include <assert.h> > + > +#include "hw.h" > +#include "pc.h" > +#include "monitor.h" > +#include "sysbus.h" > +#include "trace.h" > +#include "lm32_pic.h" > + > +struct LM32PicState { > + SysBusDevice busdev; > + qemu_irq parent_irq; > + uint32_t im; /* interrupt mask */ > + uint32_t ip; /* interrupt pending */ > + uint32_t irq_state; > + > + /* statistics */ > + uint32_t stats_irq_count[32]; > +}; > +typedef struct LM32PicState LM32PicState; > + > +static LM32PicState *pic; > +void pic_info(Monitor *mon) > +{ > + if (pic == NULL) { > + return; > + } > + > + monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", > + pic->im, pic->ip, pic->irq_state); > +} > + > +void irq_info(Monitor *mon) > +{ > + int i; > + uint32_t count; > + > + if (pic == NULL) { > + return; > + } > + > + monitor_printf(mon, "IRQ statistics:\n"); > + for (i = 0; i < 32; i++) { > + count = pic->stats_irq_count[i]; > + if (count > 0) { > + monitor_printf(mon, "%2d: %u\n", i, count); > + } > + } > +} > + > +static void update_irq(LM32PicState *s) > +{ > + s->ip |= s->irq_state; > + > + if (s->ip & s->im) { > + trace_lm32_pic_raise_irq(); > + qemu_irq_raise(s->parent_irq); > + } else { > + trace_lm32_pic_lower_irq(); > + qemu_irq_lower(s->parent_irq); > + } > +} > + > +static void irq_handler(void *opaque, int irq, int level) > +{ > + LM32PicState *s = opaque; > + > + assert(irq < 32); > + trace_lm32_pic_interrupt(irq, level); > + > + if (level) { > + s->irq_state |= (1 << irq); > + s->stats_irq_count[irq]++; > + } else { > + s->irq_state &= ~(1 << irq); > + } > + > + update_irq(s); > +} > + > +void lm32_pic_set_im(CPUState *env, uint32_t im)
Again, this and the functions below should be reworked so that CPUState is not passed to a device. > +{ > + LM32PicState *s = env->pic_env; > + > + trace_lm32_pic_set_im(im); > + s->im = im; > + > + update_irq(s); > +} > + > +void lm32_pic_set_ip(CPUState *env, uint32_t ip) > +{ > + LM32PicState *s = env->pic_env; > + > + trace_lm32_pic_set_ip(ip); > + > + /* ack interrupt */ > + s->ip &= ~ip; > + > + update_irq(s); > +} > + > +uint32_t lm32_pic_get_im(CPUState *env) > +{ > + LM32PicState *s = env->pic_env; > + > + trace_lm32_pic_get_im(s->im); > + return s->im; > +} > + > +uint32_t lm32_pic_get_ip(CPUState *env) > +{ > + LM32PicState *s = env->pic_env; > + > + trace_lm32_pic_get_ip(s->ip); > + return s->ip; > +} > + > +static void pic_reset(void *opaque) > +{ > + LM32PicState *s = opaque; > + int i; > + > + s->im = 0; > + s->ip = 0; > + s->irq_state = 0; > + for (i = 0; i < 32; i++) { > + s->stats_irq_count[i] = 0; > + } > + qemu_irq_lower(s->parent_irq); Remove. > +} > + > +static int lm32_pic_init(SysBusDevice *dev) > +{ > + LM32PicState *s = FROM_SYSBUS(typeof(*s), dev); > + > + qdev_init_gpio_in(&dev->qdev, irq_handler, 32); > + sysbus_init_irq(dev, &s->parent_irq); > + qemu_register_reset(pic_reset, s); qdev reset field > + > + pic = s; > + > + return 0; > +} > + > +static const VMStateDescription vmstate_lm32_pic = { > + .name = "lm32-pic", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(im, LM32PicState), > + VMSTATE_UINT32(ip, LM32PicState), > + VMSTATE_UINT32(irq_state, LM32PicState), > + VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static SysBusDeviceInfo lm32_pic_info = { > + .init = lm32_pic_init, > + .qdev.name = "lm32-pic", > + .qdev.size = sizeof(LM32PicState), > + .qdev.vmsd = &vmstate_lm32_pic, > +}; > + > +static void lm32_pic_register(void) > +{ > + sysbus_register_withprop(&lm32_pic_info); > +} > + > +device_init(lm32_pic_register) > diff --git a/hw/lm32_pic.h b/hw/lm32_pic.h > new file mode 100644 > index 0000000..ce39ac7 > --- /dev/null > +++ b/hw/lm32_pic.h > @@ -0,0 +1,10 @@ > +#ifndef __LM32_PIC QEMU_HW_LM32_PIC_H > +#define __LM32_PIC > + > +#include "qemu-common.h" > + > +uint32_t lm32_pic_get_ip(CPUState *env); > +uint32_t lm32_pic_get_im(CPUState *env); > +void lm32_pic_set_ip(CPUState *env, uint32_t ip); > +void lm32_pic_set_im(CPUState *env, uint32_t im); > +#endif > diff --git a/hw/lm32_pic_cpu.c b/hw/lm32_pic_cpu.c > new file mode 100644 > index 0000000..8bbeccc > --- /dev/null > +++ b/hw/lm32_pic_cpu.c > @@ -0,0 +1,37 @@ > +/* > + * LatticeMico32 CPU interrupt wrapper logic. > + * > + * Copyright (c) 2010 Michael Walle <mich...@walle.cc> > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > + > +#include "hw.h" > + > +static void lm32_pic_cpu_handler(void *opaque, int irq, int level) > +{ > + CPUState *env = (CPUState *)opaque; Useless cast in C. > + > + if (level) { > + cpu_interrupt(env, CPU_INTERRUPT_HARD); > + } else { > + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); > + } > +} > + > +qemu_irq *lm32_pic_init_cpu(CPUState *env); Belongs to a header. > +qemu_irq *lm32_pic_init_cpu(CPUState *env) > +{ > + return qemu_allocate_irqs(lm32_pic_cpu_handler, env, 1); > +} The whole file does not seem very useful. I'd merge this to board file instead. > diff --git a/trace-events b/trace-events > index e6138ea..557375e 100644 > --- a/trace-events > +++ b/trace-events > @@ -254,3 +254,12 @@ disable spice_vmc_write(ssize_t out, int len) "spice > wrottn %lu of requested %zd > disable spice_vmc_read(int bytes, int len) "spice read %lu of requested %zd" > disable spice_vmc_register_interface(void *scd) "spice vmc registered > interface %p" > disable spice_vmc_unregister_interface(void *scd) "spice vmc unregistered > interface %p" > + > +# hw/lm32_pic.c > +disable lm32_pic_raise_irq(void) "Raise CPU interrupt" > +disable lm32_pic_lower_irq(void) "Lower CPU interrupt" > +disable lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d" > +disable lm32_pic_set_im(uint32_t im) "im 0x%08x" > +disable lm32_pic_set_ip(uint32_t ip) "ip 0x%08x" > +disable lm32_pic_get_im(uint32_t im) "im 0x%08x" > +disable lm32_pic_get_ip(uint32_t ip) "ip 0x%08x" > -- > 1.7.2.3 > > >