From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=54896 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Po0vb-0000vM-48 for qemu-devel@nongnu.org; Fri, 11 Feb 2011 16:53:27 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Po0sf-0005Gz-QM for qemu-devel@nongnu.org; Fri, 11 Feb 2011 16:50:23 -0500 Received: from mail-vx0-f173.google.com ([209.85.220.173]:40627) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Po0sf-0005Gm-LM for qemu-devel@nongnu.org; Fri, 11 Feb 2011 16:50:21 -0500 Received: by vxb40 with SMTP id 40so1625775vxb.4 for ; Fri, 11 Feb 2011 13:50:21 -0800 (PST) MIME-Version: 1.0 In-Reply-To: <1297379530-23487-7-git-send-email-michael@walle.cc> References: <1297379530-23487-1-git-send-email-michael@walle.cc> <1297379530-23487-7-git-send-email-michael@walle.cc> From: Blue Swirl Date: Fri, 11 Feb 2011 23:49:59 +0200 Message-ID: Subject: Re: [Qemu-devel] [PATCH 06/17] lm32: interrupt controller model Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Michael Walle Cc: "Edgar E. Iglesias" , Richard Henderson , qemu-devel@nongnu.org, Alexander Graf On Fri, Feb 11, 2011 at 1:11 AM, Michael Walle wrote: > This patch adds the interrupt controller of the lm32. Because the PIC is > accessed through special control registers and opcodes, there are callbac= ks > from the lm32 translation code to this model. > > Signed-off-by: Michael Walle > --- > =C2=A0hw/lm32_pic.c =C2=A0 =C2=A0 | =C2=A0191 +++++++++++++++++++++++++++= ++++++++++++++++++++++++++ > =C2=A0hw/lm32_pic.h =C2=A0 =C2=A0 | =C2=A0 10 +++ > =C2=A0hw/lm32_pic_cpu.c | =C2=A0 37 ++++++++++ > =C2=A0trace-events =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A09 +++ > =C2=A04 files changed, 247 insertions(+), 0 deletions(-) > =C2=A0create mode 100644 hw/lm32_pic.c > =C2=A0create mode 100644 hw/lm32_pic.h > =C2=A0create 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 @@ > +/* > + * =C2=A0LatticeMico32 CPU interrupt controller logic. > + * > + * =C2=A0Copyright (c) 2010 Michael Walle > + * > + * 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. =C2=A0See the GN= U > + * 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 . > + */ > + > +#include > + > +#include "hw.h" > +#include "pc.h" > +#include "monitor.h" > +#include "sysbus.h" > +#include "trace.h" > +#include "lm32_pic.h" > + > +struct LM32PicState { > + =C2=A0 =C2=A0SysBusDevice busdev; > + =C2=A0 =C2=A0qemu_irq parent_irq; > + =C2=A0 =C2=A0uint32_t im; =C2=A0 =C2=A0 =C2=A0 =C2=A0/* interrupt mask = */ > + =C2=A0 =C2=A0uint32_t ip; =C2=A0 =C2=A0 =C2=A0 =C2=A0/* interrupt pendi= ng */ > + =C2=A0 =C2=A0uint32_t irq_state; > + > + =C2=A0 =C2=A0/* statistics */ > + =C2=A0 =C2=A0uint32_t stats_irq_count[32]; > +}; > +typedef struct LM32PicState LM32PicState; > + > +static LM32PicState *pic; > +void pic_info(Monitor *mon) > +{ > + =C2=A0 =C2=A0if (pic =3D=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0monitor_printf(mon, "lm32-pic: im=3D%08x ip=3D%08x irq_sta= te=3D%08x\n", > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pic->im, pic->ip, pic->irq_sta= te); > +} > + > +void irq_info(Monitor *mon) > +{ > + =C2=A0 =C2=A0int i; > + =C2=A0 =C2=A0uint32_t count; > + > + =C2=A0 =C2=A0if (pic =3D=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0monitor_printf(mon, "IRQ statistics:\n"); > + =C2=A0 =C2=A0for (i =3D 0; i < 32; i++) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0count =3D pic->stats_irq_count[i]; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (count > 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0monitor_printf(mon, "%2d: %u\n= ", i, count); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0} > +} > + > +static void update_irq(LM32PicState *s) > +{ > + =C2=A0 =C2=A0s->ip |=3D s->irq_state; > + > + =C2=A0 =C2=A0if (s->ip & s->im) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0trace_lm32_pic_raise_irq(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_irq_raise(s->parent_irq); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0trace_lm32_pic_lower_irq(); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_irq_lower(s->parent_irq); > + =C2=A0 =C2=A0} > +} > + > +static void irq_handler(void *opaque, int irq, int level) > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D opaque; > + > + =C2=A0 =C2=A0assert(irq < 32); > + =C2=A0 =C2=A0trace_lm32_pic_interrupt(irq, level); > + > + =C2=A0 =C2=A0if (level) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0s->irq_state |=3D (1 << irq); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0s->stats_irq_count[irq]++; > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0s->irq_state &=3D ~(1 << irq); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0update_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. > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D env->pic_env; > + > + =C2=A0 =C2=A0trace_lm32_pic_set_im(im); > + =C2=A0 =C2=A0s->im =3D im; > + > + =C2=A0 =C2=A0update_irq(s); > +} > + > +void lm32_pic_set_ip(CPUState *env, uint32_t ip) > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D env->pic_env; > + > + =C2=A0 =C2=A0trace_lm32_pic_set_ip(ip); > + > + =C2=A0 =C2=A0/* ack interrupt */ > + =C2=A0 =C2=A0s->ip &=3D ~ip; > + > + =C2=A0 =C2=A0update_irq(s); > +} > + > +uint32_t lm32_pic_get_im(CPUState *env) > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D env->pic_env; > + > + =C2=A0 =C2=A0trace_lm32_pic_get_im(s->im); > + =C2=A0 =C2=A0return s->im; > +} > + > +uint32_t lm32_pic_get_ip(CPUState *env) > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D env->pic_env; > + > + =C2=A0 =C2=A0trace_lm32_pic_get_ip(s->ip); > + =C2=A0 =C2=A0return s->ip; > +} > + > +static void pic_reset(void *opaque) > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D opaque; > + =C2=A0 =C2=A0int i; > + > + =C2=A0 =C2=A0s->im =3D 0; > + =C2=A0 =C2=A0s->ip =3D 0; > + =C2=A0 =C2=A0s->irq_state =3D 0; > + =C2=A0 =C2=A0for (i =3D 0; i < 32; i++) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0s->stats_irq_count[i] =3D 0; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0qemu_irq_lower(s->parent_irq); Remove. > +} > + > +static int lm32_pic_init(SysBusDevice *dev) > +{ > + =C2=A0 =C2=A0LM32PicState *s =3D FROM_SYSBUS(typeof(*s), dev); > + > + =C2=A0 =C2=A0qdev_init_gpio_in(&dev->qdev, irq_handler, 32); > + =C2=A0 =C2=A0sysbus_init_irq(dev, &s->parent_irq); > + =C2=A0 =C2=A0qemu_register_reset(pic_reset, s); qdev reset field > + > + =C2=A0 =C2=A0pic =3D s; > + > + =C2=A0 =C2=A0return 0; > +} > + > +static const VMStateDescription vmstate_lm32_pic =3D { > + =C2=A0 =C2=A0.name =3D "lm32-pic", > + =C2=A0 =C2=A0.version_id =3D 1, > + =C2=A0 =C2=A0.minimum_version_id =3D 1, > + =C2=A0 =C2=A0.minimum_version_id_old =3D 1, > + =C2=A0 =C2=A0.fields =C2=A0 =C2=A0 =C2=A0=3D (VMStateField[]) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT32(im, LM32PicState), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT32(ip, LM32PicState), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT32(irq_state, LM32PicState), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT32_ARRAY(stats_irq_count, LM32Pi= cState, 32), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_END_OF_LIST() > + =C2=A0 =C2=A0} > +}; > + > +static SysBusDeviceInfo lm32_pic_info =3D { > + =C2=A0 =C2=A0.init =3D lm32_pic_init, > + =C2=A0 =C2=A0.qdev.name =3D "lm32-pic", > + =C2=A0 =C2=A0.qdev.size =3D sizeof(LM32PicState), > + =C2=A0 =C2=A0.qdev.vmsd =C2=A0=3D &vmstate_lm32_pic, > +}; > + > +static void lm32_pic_register(void) > +{ > + =C2=A0 =C2=A0sysbus_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 @@ > +/* > + * =C2=A0LatticeMico32 CPU interrupt wrapper logic. > + * > + * =C2=A0Copyright (c) 2010 Michael Walle > + * > + * 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. =C2=A0See the GN= U > + * 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 . > + */ > + > +#include "hw.h" > + > +static void lm32_pic_cpu_handler(void *opaque, int irq, int level) > +{ > + =C2=A0 =C2=A0CPUState *env =3D (CPUState *)opaque; Useless cast in C. > + > + =C2=A0 =C2=A0if (level) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_interrupt(env, CPU_INTERRUPT_HARD); > + =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_reset_interrupt(env, CPU_INTERRUPT_HARD)= ; > + =C2=A0 =C2=A0} > +} > + > +qemu_irq *lm32_pic_init_cpu(CPUState *env); Belongs to a header. > +qemu_irq *lm32_pic_init_cpu(CPUState *env) > +{ > + =C2=A0 =C2=A0return qemu_allocate_irqs(lm32_pic_cpu_handler, env, 1); > +} The whole file does not seem very useful. I'd merge this to board file inst= ead. > 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 > =C2=A0disable spice_vmc_read(int bytes, int len) "spice read %lu of reque= sted %zd" > =C2=A0disable spice_vmc_register_interface(void *scd) "spice vmc register= ed interface %p" > =C2=A0disable spice_vmc_unregister_interface(void *scd) "spice vmc unregi= stered 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 > > >