All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3
@ 2011-01-03 14:06 Fabien Chouteau
  2011-01-03 14:07 ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual Fabien Chouteau
  2011-01-04 21:02 ` [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3 Andreas Färber
  0 siblings, 2 replies; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau

Hi everyone,
New version of the Leon3 emulation. Many modifications since v1, mostly to
follow the Qemu architecture and to implement features in a more generic way.

Again, please feel free to comment.

Regards,

--------------------------------------------------------------------------------

This patch set introduces a new SPARC V8 machine: Leon3. It's an open-source
VHDL System-On-Chip, well known in space industry (more information on
http://www.gaisler.com).

Leon3 is made of multiple components available in the GrLib VHDL library.
Three devices are implemented: uart, timers and IRQ manager.
You can find code for these peripherals in the grlib_* files.

Modifications have been done to the SPARC cpu emulation code to handle
Leon3's specific behavior:
 - IRQ management
 - Cache control
 - Asr17 (implementation-dependent Ancillary State Registers)
 - Shutdown

Fabien Chouteau (6):
  Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual.
  Emulation of GRLIB IRQMP as defined in GRLIB IP Core User's Manual.
  Emulation of GRLIB APB UART as defined in GRLIB IP Core User's
    Manual.
  Header file for the GRLIB components.
  Emulation of Leon3.
  SPARCV8 asr17 register support.

 Makefile.target          |    5 +-
 hw/grlib.h               |  121 +++++++++++++
 hw/grlib_apbuart.c       |  208 ++++++++++++++++++++++
 hw/grlib_gptimer.c       |  427 ++++++++++++++++++++++++++++++++++++++++++++++
 hw/grlib_irqmp.c         |  402 +++++++++++++++++++++++++++++++++++++++++++
 hw/leon3.c               |  202 ++++++++++++++++++++++
 target-sparc/cpu.h       |   40 +++--
 target-sparc/helper.c    |    8 +-
 target-sparc/helper.h    |    1 +
 target-sparc/op_helper.c |  151 ++++++++++++++++-
 target-sparc/translate.c |   24 +++-
 11 files changed, 1567 insertions(+), 22 deletions(-)
 create mode 100644 hw/grlib.h
 create mode 100644 hw/grlib_apbuart.c
 create mode 100644 hw/grlib_gptimer.c
 create mode 100644 hw/grlib_irqmp.c
 create mode 100644 hw/leon3.c

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual.
  2011-01-03 14:06 [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3 Fabien Chouteau
@ 2011-01-03 14:07 ` Fabien Chouteau
  2011-01-03 14:07   ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Fabien Chouteau
  2011-01-04 18:46   ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer " Blue Swirl
  2011-01-04 21:02 ` [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3 Andreas Färber
  1 sibling, 2 replies; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau


Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 hw/grlib_gptimer.c |  427 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 427 insertions(+), 0 deletions(-)

diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
new file mode 100644
index 0000000..e33d506
--- /dev/null
+++ b/hw/grlib_gptimer.c
@@ -0,0 +1,427 @@
+/*
+ * QEMU GRLIB GPTimer Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+//#define DEBUG_TIMER
+
+#ifdef DEBUG_TIMER
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("GPTIMER: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
+#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
+
+#define GPTIMER_MAX_TIMERS 8
+
+/* GPTimer Config register fields */
+#define GPTIMER_ENABLE      (1 << 0)
+#define GPTIMER_RESTART     (1 << 1)
+#define GPTIMER_LOAD        (1 << 2)
+#define GPTIMER_INT_ENABLE  (1 << 3)
+#define GPTIMER_INT_PENDING (1 << 4)
+#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
+#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
+
+/* Memory mapped register offsets */
+#define SCALER_OFFSET         0x00
+#define SCALER_RELOAD_OFFSET  0x04
+#define CONFIG_OFFSET         0x08
+#define COUNTER_OFFSET        0x00
+#define COUNTER_RELOAD_OFFSET 0x04
+#define TIMER_BASE            0x10
+
+typedef struct GPTimer     GPTimer;
+typedef struct GPTimerUnit GPTimerUnit;
+
+struct GPTimer
+{
+    QEMUBH *bh;
+    struct ptimer_state *ptimer;
+
+    qemu_irq     irq;
+    int          id;
+    GPTimerUnit *unit;
+
+    /* registers */
+    uint32_t counter;
+    uint32_t reload;
+    uint32_t config;
+};
+
+struct GPTimerUnit
+{
+    SysBusDevice  busdev;
+
+    uint32_t nr_timers;         /* Number of timers available */
+    uint32_t freq_hz;           /* System frequency */
+    uint32_t irq_line;          /* Base irq line */
+
+    GPTimer *timers;
+
+    /* registers */
+    uint32_t scaler;
+    uint32_t reload;
+    uint32_t config;
+};
+
+static void grlib_gptimer_enable(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+    DPRINTF("%s id:%d\n", __func__, timer->id);
+
+    ptimer_stop(timer->ptimer);
+
+    if (!(timer->config & GPTIMER_ENABLE)) {
+        /* Timer disabled */
+        DPRINTF("%s id:%d Timer disabled (config 0x%x)\n", __func__,
+                timer->id, timer->config);
+        return;
+    }
+
+    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
+       underflow. Set count + 1 to simulate the GPTimer behavior. */
+
+    DPRINTF("%s id:%d set count 0x%x and run\n",
+            __func__,
+            timer->id,
+            timer->counter + 1);
+
+    ptimer_set_count(timer->ptimer, timer->counter + 1);
+    ptimer_run(timer->ptimer, 1);
+}
+
+static void grlib_gptimer_restart(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+    DPRINTF("%s id:%d reload val: 0x%x\n", __func__, timer->id, timer->reload);
+
+    timer->counter = timer->reload;
+    grlib_gptimer_enable(timer);
+}
+
+static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
+{
+    int i = 0;
+    uint32_t value = 0;
+
+    assert(unit != NULL);
+
+
+    if (scaler > 0) {
+        value = unit->freq_hz / (scaler + 1);
+    } else {
+        value = unit->freq_hz;
+    }
+
+    DPRINTF("%s scaler:%d freq:0x%x\n", __func__, scaler, value);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        ptimer_set_freq(unit->timers[i].ptimer, value);
+    }
+}
+
+static void grlib_gptimer_hit(void *opaque)
+{
+    GPTimer *timer = opaque;
+    assert(timer != NULL);
+
+    DPRINTF("%s id:%d\n", __func__, timer->id);
+
+    /* Timer expired */
+
+    if (timer->config & GPTIMER_INT_ENABLE) {
+        /* Set the pending bit (only unset by write in the config register) */
+        timer->config |= GPTIMER_INT_PENDING;
+        qemu_irq_pulse(timer->irq);
+    }
+
+    if (timer->config & GPTIMER_RESTART) {
+        grlib_gptimer_restart(timer);
+    }
+}
+
+static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
+{
+    GPTimerUnit *unit  = opaque;
+    uint32_t     value = 0;
+
+    addr &= 0xff;
+
+    assert(unit != NULL);
+
+    /* Unit registers */
+    switch (addr)
+    {
+        case SCALER_OFFSET:
+            DPRINTF("%s scaler: 0x%x\n", __func__, unit->scaler);
+            return unit->scaler;
+
+        case SCALER_RELOAD_OFFSET:
+            DPRINTF("%s reload: 0x%x\n", __func__, unit->reload);
+            return unit->reload;
+
+        case CONFIG_OFFSET:
+            DPRINTF("%s unit config: 0x%x\n", __func__, unit->config);
+            return unit->config;
+
+        default:
+            break;
+    }
+
+    target_phys_addr_t timer_addr = (addr % TIMER_BASE);
+    int                id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr)
+        {
+            case COUNTER_OFFSET:
+                value = ptimer_get_count (unit->timers[id].ptimer);
+                DPRINTF("%s counter value for timer %d: 0x%x\n",
+                        __func__, id, value);
+                return value;
+
+            case COUNTER_RELOAD_OFFSET:
+                value = unit->timers[id].reload;
+                DPRINTF("%s reload value for timer %d: 0x%x\n",
+                        __func__, id, value);
+                return value;
+
+            case CONFIG_OFFSET:
+                DPRINTF("%s config for timer %d: 0x%x\n",
+                        __func__, id, unit->timers[id].config);
+                return unit->timers[id].config;
+
+            default:
+                break;
+        }
+
+    }
+
+    DPRINTF("read unknown register " TARGET_FMT_plx "\n", addr);
+    return 0;
+}
+
+static void
+grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    GPTimerUnit *unit = opaque;
+
+    addr &= 0xff;
+
+    assert(unit != NULL);
+
+    /* Unit registers */
+    switch (addr)
+    {
+        case SCALER_OFFSET:
+            value &= 0xFFFF; /* clean up the value */
+            unit->scaler = value;
+            return;
+
+        case SCALER_RELOAD_OFFSET:
+            value &= 0xFFFF; /* clean up the value */
+            unit->reload = value;
+            grlib_gptimer_set_scaler(unit, value);
+            return;
+
+        case CONFIG_OFFSET:
+            /* Read Only (disable timer freeze not supported) */
+            return;
+
+        default:
+            break;
+    }
+
+    target_phys_addr_t timer_addr = (addr % TIMER_BASE);
+    int                id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr)
+        {
+            case COUNTER_OFFSET:
+                DPRINTF("%s counter value for timer %d: 0x%x\n",
+                        __func__, id, value);
+                unit->timers[id].counter = value;
+                grlib_gptimer_enable(&unit->timers[id]);
+                return;
+
+            case COUNTER_RELOAD_OFFSET:
+                DPRINTF("%s reload value for timer %d: 0x%x\n",
+                        __func__, id, value);
+                unit->timers[id].reload = value;
+                return;
+
+            case CONFIG_OFFSET:
+                DPRINTF("%s config for timer %d: 0x%x\n", __func__, id, value);
+
+                if (value & GPTIMER_INT_PENDING) {
+                    /* clear pending bit */
+                    value &= ~GPTIMER_INT_PENDING;
+                } else {
+                    /* keep pending bit */
+                    value |= unit->timers[id].config & GPTIMER_INT_PENDING;
+                }
+
+                unit->timers[id].config = value;
+
+                /* gptimer_restart calls gptimer_enable, so if "enable" and
+                   "load" bits are present, we just have to call restart. */
+
+                if (value & GPTIMER_LOAD) {
+                    grlib_gptimer_restart(&unit->timers[id]);
+                } else if (value & GPTIMER_ENABLE) {
+                    grlib_gptimer_enable(&unit->timers[id]);
+                }
+
+                /* These fields must always be read as 0 */
+                value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
+
+                unit->timers[id].config = value;
+                return;
+
+            default:
+                break;
+        }
+
+    }
+
+    DPRINTF("write unknown register " TARGET_FMT_plx "\n", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
+    NULL, NULL, grlib_gptimer_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
+    NULL, NULL, grlib_gptimer_writel,
+};
+
+static void grlib_gptimer_reset(DeviceState *d)
+{
+    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
+    int          i    = 0;
+
+    assert(unit != NULL);
+
+    unit->scaler = 0;
+    unit->reload = 0;
+    unit->config = 0;
+
+    unit->config  = unit->nr_timers;
+    unit->config |= unit->irq_line << 3;
+    unit->config |= 1 << 8;     /* separate interrupt */
+    unit->config |= 1 << 9;     /* Disable timer freeze */
+
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->counter = 0;
+        timer->reload = 0;
+        timer->config = 0;
+        ptimer_stop(timer->ptimer);
+        ptimer_set_count(timer->ptimer, 0);
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+}
+
+static int grlib_gptimer_init(SysBusDevice *dev)
+{
+    GPTimerUnit  *unit = FROM_SYSBUS(typeof (*unit), dev);
+    unsigned int  i;
+    int           timer_regs;
+
+    assert(unit->nr_timers > 0);
+    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
+    unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->unit   = unit;
+        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
+        timer->ptimer = ptimer_init(timer->bh);
+        timer->id     = i;
+
+        /* One IRQ line for each timer */
+        sysbus_init_irq(dev, &timer->irq);
+
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+
+    timer_regs = cpu_register_io_memory(grlib_gptimer_read,
+                                        grlib_gptimer_write,
+                                        unit);
+    if (timer_regs < 0) {
+        return -1;
+    }
+
+    sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
+                     timer_regs);
+    return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+    .init       = grlib_gptimer_init,
+    .qdev.name  = "grlib,gptimer",
+    .qdev.reset = grlib_gptimer_reset,
+    .qdev.size  = sizeof(GPTimerUnit),
+    .qdev.props = (Property[]) {
+        {
+            .name   = "frequency",
+            .info   = &qdev_prop_uint32,
+            .offset = offsetof(GPTimerUnit, freq_hz),
+            .defval = (uint32_t[]) { 2 },
+        },{
+            .name   = "irq-line",
+            .info   = &qdev_prop_uint32,
+            .offset = offsetof(GPTimerUnit, irq_line),
+            .defval = (uint32_t[]) { 8 },
+        },{
+            .name   = "nr-timers",
+            .info   = &qdev_prop_uint32,
+            .offset = offsetof(GPTimerUnit, nr_timers),
+            .defval = (uint32_t[]) { 2 },
+        },
+        {/* end of list */}
+    }
+};
+
+static void grlib_gptimer_register(void)
+{
+    sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP as defined in GRLIB IP Core User's Manual.
  2011-01-03 14:07 ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual Fabien Chouteau
@ 2011-01-03 14:07   ` Fabien Chouteau
  2011-01-03 14:07     ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART " Fabien Chouteau
  2011-01-04 19:02     ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Blue Swirl
  2011-01-04 18:46   ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer " Blue Swirl
  1 sibling, 2 replies; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau


Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 hw/grlib_irqmp.c |  402 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 402 insertions(+), 0 deletions(-)

diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
new file mode 100644
index 0000000..9f947d1
--- /dev/null
+++ b/hw/grlib_irqmp.c
@@ -0,0 +1,402 @@
+/*
+ * QEMU GRLIB IRQMP Emulator
+ *
+ * (Multiprocessor and extended interrupt not supported)
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "cpu.h"
+
+#include "grlib.h"
+
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQMP: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define IRQMP_MAX_CPU 16
+#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
+
+/* Memory mapped register offsets */
+#define LEVEL_OFFSET     0x00
+#define PENDING_OFFSET   0x04
+#define FORCE0_OFFSET    0x08
+#define CLEAR_OFFSET     0x0C
+#define MP_STATUS_OFFSET 0x10
+#define BROADCAST_OFFSET 0x14
+#define MASK_OFFSET      0x40
+#define FORCE_OFFSET     0x80
+#define EXTENDED_OFFSET  0xC0
+
+typedef struct IRQMPState IRQMPState;
+
+typedef struct IRQMP
+{
+    SysBusDevice busdev;
+
+    CPUSPARCState *env;
+
+    IRQMPState *state;
+} IRQMP;
+
+struct IRQMPState
+{
+    uint32_t level;
+    uint32_t pending;
+    uint32_t clear;
+    uint32_t broadcast;
+
+    uint32_t mask[IRQMP_MAX_CPU];
+    uint32_t force[IRQMP_MAX_CPU];
+    uint32_t extended[IRQMP_MAX_CPU];
+
+    IRQMP    *parent;
+};
+
+static void grlib_irqmp_check_irqs(IRQMPState *state)
+{
+    assert(state != NULL);
+    CPUState *env   = state->parent->env;
+    assert(env != NULL);
+
+    uint32_t pend   = 0;
+    uint32_t level0 = 0;
+    uint32_t level1 = 0;
+
+
+    /* IRQ for CPU 0 (no SMP support) */
+    pend = (state->pending | state->force[0])
+        & state->mask[0];
+
+
+    level0 = pend & ~state->level;
+    level1 = pend &  state->level;
+
+    DPRINTF("pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n",
+            state->pending, state->force[0],
+            state->mask[0], level1, level0);
+
+    /* Trigger level1 interrupt first and level0 if there is no level1 */
+    if (level1 != 0) {
+        env->pil_in = level1;
+    } else {
+        env->pil_in = level0;
+    }
+
+    if (env->pil_in && (env->interrupt_index == 0 ||
+                        (env->interrupt_index & ~15) == TT_EXTINT)) {
+        unsigned int i;
+
+        for (i = 15; i > 0; i--) {
+            if (env->pil_in & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+
+                env->interrupt_index = TT_EXTINT | i;
+                if (old_interrupt != env->interrupt_index) {
+                    DPRINTF("Set CPU IRQ %d\n", i);
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                }
+                break;
+            }
+        }
+    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15);
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+void grlib_irqmp_ack(DeviceState *dev, int intno)
+{
+    assert(dev != NULL);
+
+    SysBusDevice *sdev = sysbus_from_qdev(dev);
+    assert(sdev != NULL);
+
+    IRQMP *irqmp = FROM_SYSBUS(typeof (*irqmp), sdev);
+    assert(irqmp != NULL);
+
+    IRQMPState *state = irqmp->state;
+    assert(state != NULL);
+
+    uint32_t mask;
+
+    intno &= 15;
+    mask = 1 << intno;
+
+    DPRINTF("grlib_irqmp_ack %d\n", intno);
+
+    /* Clear registers */
+    state->pending  &= ~mask;
+    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+    grlib_irqmp_check_irqs(state);
+}
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level)
+{
+    assert(opaque != NULL);
+
+    IRQMP *irqmp = FROM_SYSBUS(typeof (*irqmp), sysbus_from_qdev(opaque));
+    assert(irqmp != NULL);
+
+    IRQMPState *s = irqmp->state;
+    assert(s         != NULL);
+    assert(s->parent != NULL);
+
+    int i = 0;
+
+
+    if (level) {
+        DPRINTF("Raise CPU IRQ %d\n", irq);
+
+        if (s->broadcast & 1 << irq) {
+            /* Broadcasted IRQ */
+            for (i = 0; i < IRQMP_MAX_CPU; i++) {
+                s->force[i] |= 1 << irq;
+            }
+        } else {
+            s->pending |= 1 << irq;
+        }
+        grlib_irqmp_check_irqs(s);
+
+    }
+}
+
+static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
+{
+    IRQMP *irqmp = opaque;
+    assert(irqmp != NULL);
+
+    IRQMPState *state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr)
+    {
+        case LEVEL_OFFSET:
+            return state->level;
+
+        case PENDING_OFFSET:
+            return state->pending;
+
+        case FORCE0_OFFSET:
+            /* This register is an "alias" for the force register of CPU 0 */
+            return state->force[0];
+
+        case CLEAR_OFFSET:
+        case MP_STATUS_OFFSET:
+            /* Always read as 0 */
+            return 0;
+
+        case BROADCAST_OFFSET:
+            return state->broadcast;
+
+        default:
+            break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->mask[cpu];
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->force[cpu];
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->extended[cpu];
+    }
+
+    DPRINTF("read unknown register " TARGET_FMT_plx "\n", addr);
+    return 0;
+}
+
+static void
+grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    IRQMP *irqmp = opaque;
+    assert(irqmp != NULL);
+
+    IRQMPState *state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr)
+    {
+        case LEVEL_OFFSET:
+            value &= 0xFFFF << 1; /* clean up the value */
+            state->level = value;
+            return;
+
+        case PENDING_OFFSET:
+            /* Read Only */
+            return;
+
+        case FORCE0_OFFSET:
+            /* This register is an "alias" for the force register of CPU 0 */
+
+            value &= 0xFFFE; /* clean up the value */
+            state->force[0] = value;
+            grlib_irqmp_check_irqs(irqmp->state);
+            return;
+
+        case CLEAR_OFFSET:
+            value &= ~1; /* clean up the value */
+            state->pending &= ~value;
+            return;
+
+        case MP_STATUS_OFFSET:
+            /* Read Only (no SMP support) */
+            return;
+
+        case BROADCAST_OFFSET:
+            value &= 0xFFFE; /* clean up the value */
+            state->broadcast = value;
+            return;
+
+        default:
+            break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= ~1; /* clean up the value */
+        state->mask[cpu] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        uint32_t force = value & 0xFFFE;
+        uint32_t clear = (value >> 16) & 0xFFFE;
+        uint32_t old   = state->force[cpu];
+
+        state->force[cpu] = (old | force) & ~clear;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= 0xF; /* clean up the value */
+        state->extended[cpu] = value;
+        return;
+    }
+
+    DPRINTF("write unknown register " TARGET_FMT_plx "\n", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_irqmp_read[] = {
+    NULL, NULL, &grlib_irqmp_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_irqmp_write[] = {
+    NULL, NULL, &grlib_irqmp_writel,
+};
+
+static void grlib_irqmp_reset(DeviceState *d)
+{
+    IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
+    assert(irqmp        != NULL);
+    assert(irqmp->state != NULL);
+
+    memset(irqmp->state, 0, sizeof *irqmp->state);
+    irqmp->state->parent = irqmp;
+}
+
+static int grlib_irqmp_init(SysBusDevice *dev)
+{
+    IRQMP *irqmp = FROM_SYSBUS(typeof (*irqmp), dev);
+    int    irqmp_regs;
+
+    assert(irqmp != NULL);
+    assert(irqmp->env != NULL);
+
+    irqmp_regs = cpu_register_io_memory(grlib_irqmp_read,
+                                        grlib_irqmp_write,
+                                        irqmp);
+
+    irqmp->state = qemu_mallocz(sizeof *irqmp->state);
+
+    if (irqmp_regs < 0) {
+        return -1;
+    }
+
+    sysbus_init_mmio(dev, IRQMP_REG_SIZE, irqmp_regs);
+
+    return 0;
+}
+
+static SysBusDeviceInfo grlib_irqmp_info = {
+    .init = grlib_irqmp_init,
+    .qdev.name  = "grlib,irqmp",
+    .qdev.reset = grlib_irqmp_reset,
+    .qdev.size  = sizeof(IRQMP),
+    .qdev.props = (Property[]) {
+        {
+            .name   = "cpustate",
+            .info   = &qdev_prop_ptr,
+            .offset = offsetof(IRQMP, env),
+            .defval = (void*[]) { NULL },
+        },
+        {/* end of list */}
+    }
+};
+
+static void grlib_irqmp_register(void)
+{
+    sysbus_register_withprop(&grlib_irqmp_info);
+}
+
+device_init(grlib_irqmp_register)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART as defined in GRLIB IP Core User's Manual.
  2011-01-03 14:07   ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Fabien Chouteau
@ 2011-01-03 14:07     ` Fabien Chouteau
  2011-01-03 14:07       ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Fabien Chouteau
  2011-01-04 18:38       ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART as defined in GRLIB IP Core User's Manual Blue Swirl
  2011-01-04 19:02     ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Blue Swirl
  1 sibling, 2 replies; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau


Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 hw/grlib_apbuart.c |  208 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 208 insertions(+), 0 deletions(-)

diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
new file mode 100644
index 0000000..a2ff8ed
--- /dev/null
+++ b/hw/grlib_apbuart.c
@@ -0,0 +1,208 @@
+/*
+ * QEMU GRLIB APB UART Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+
+//#define DEBUG_UART
+
+#ifdef DEBUG_UART
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("APBUART: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define UART_REG_SIZE 20     /* Size of memory mapped registers */
+
+/* UART status register fields */
+#define UART_DATA_READY           (1 <<  0)
+#define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
+#define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
+#define UART_BREAK_RECEIVED       (1 <<  3)
+#define UART_OVERRUN              (1 <<  4)
+#define UART_PARITY_ERROR         (1 <<  5)
+#define UART_FRAMING_ERROR        (1 <<  6)
+#define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
+#define UART_RECEIVE_FIFO_HALF    (1 <<  8)
+#define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
+#define UART_RECEIVE_FIFO_FULL    (1 << 10)
+
+/* UART control register fields */
+#define UART_RECEIVE_ENABLE          (1 <<  0)
+#define UART_TRANSMIT_ENABLE         (1 <<  1)
+#define UART_RECEIVE_INTERRUPT       (1 <<  2)
+#define UART_TRANSMIT_INTERRUPT      (1 <<  3)
+#define UART_PARITY_SELECT           (1 <<  4)
+#define UART_PARITY_ENABLE           (1 <<  5)
+#define UART_FLOW_CONTROL            (1 <<  6)
+#define UART_LOOPBACK                (1 <<  7)
+#define UART_EXTERNAL_CLOCK          (1 <<  8)
+#define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
+#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
+#define UART_FIFO_DEBUG_MODE         (1 << 11)
+#define UART_OUTPUT_ENABLE           (1 << 12)
+#define UART_FIFO_AVAILABLE          (1 << 31)
+
+/* Memory mapped register offsets */
+#define DATA_OFFSET       0x00
+#define STATUS_OFFSET     0x04
+#define CONTROL_OFFSET    0x08
+#define SCALER_OFFSET     0x0C  /* not supported */
+#define FIFO_DEBUG_OFFSET 0x10  /* not supported */
+
+typedef struct UART
+{
+    SysBusDevice busdev;
+
+    qemu_irq irq;
+
+    CharDriverState *chr;
+
+    /* registers */
+    uint32_t receive;
+    uint32_t status;
+    uint32_t control;
+} UART;
+
+static int grlib_apbuart_can_receive(void *opaque)
+{
+    UART *uart = opaque;
+    assert(uart != NULL);
+
+    return !!(uart->status & UART_DATA_READY);
+}
+
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    UART *uart = opaque;
+    assert(uart != NULL);
+
+    uart->receive  = *buf;
+    uart->status  |= UART_DATA_READY;
+
+    if (uart->control & UART_RECEIVE_INTERRUPT) {
+        qemu_irq_pulse(uart->irq);
+    }
+}
+
+static void grlib_apbuart_event(void *opaque, int event)
+{
+    DPRINTF("uart: event %x\n", event);
+}
+
+static void
+grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    UART          *uart = opaque;
+    unsigned char  c    = 0;
+
+    addr &= 0xff;
+
+    assert(uart != NULL);
+
+    /* Unit registers */
+    switch (addr)
+    {
+        case DATA_OFFSET:
+            c = value & 0xFF;
+            qemu_chr_write(uart->chr, &c, 1);
+            return;
+
+        case STATUS_OFFSET:
+            /* Read Only */
+            return;
+
+        case CONTROL_OFFSET:
+            /* Not supported */
+            return;
+
+        case SCALER_OFFSET:
+            /* Not supported */
+            return;
+
+        default:
+            break;
+    }
+
+    DPRINTF("write unknown register " TARGET_FMT_plx "\n", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
+    NULL, NULL, NULL,
+};
+
+static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
+    NULL, NULL, grlib_apbuart_writel,
+};
+
+static int grlib_apbuart_init(SysBusDevice *dev)
+{
+    UART *uart      = FROM_SYSBUS(typeof (*uart), dev);
+    int   uart_regs = 0;
+
+    assert(uart != NULL);
+    assert(uart->chr != NULL);
+
+    qemu_chr_add_handlers(uart->chr,
+                          grlib_apbuart_can_receive,
+                          grlib_apbuart_receive,
+                          grlib_apbuart_event,
+                          uart);
+
+    sysbus_init_irq(dev, &uart->irq);
+
+    uart_regs = cpu_register_io_memory(grlib_apbuart_read,
+                                       grlib_apbuart_write,
+                                       uart);
+    if (uart_regs < 0) {
+        return -1;
+    }
+
+    sysbus_init_mmio(dev, UART_REG_SIZE, uart_regs);
+
+    return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+    .init       = grlib_apbuart_init,
+    .qdev.name  = "grlib,apbuart",
+    .qdev.size  = sizeof(UART),
+    .qdev.props = (Property[]) {
+        {
+            .name   = "chrdev",
+            .info   = &qdev_prop_ptr,
+            .offset = offsetof(UART, chr),
+            .defval = (void*[]) { NULL },
+        },
+        {/* end of list */}
+    }
+};
+
+static void grlib_gptimer_register(void)
+{
+    sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components.
  2011-01-03 14:07     ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART " Fabien Chouteau
@ 2011-01-03 14:07       ` Fabien Chouteau
  2011-01-03 14:07         ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Fabien Chouteau
  2011-01-04 19:04         ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Blue Swirl
  2011-01-04 18:38       ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART as defined in GRLIB IP Core User's Manual Blue Swirl
  1 sibling, 2 replies; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau


Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 hw/grlib.h |  121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 121 insertions(+), 0 deletions(-)

diff --git a/hw/grlib.h b/hw/grlib.h
new file mode 100644
index 0000000..bb3c01e
--- /dev/null
+++ b/hw/grlib.h
@@ -0,0 +1,121 @@
+/*
+ * QEMU GRLIB Components
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _GRLIB_H_
+#define _GRLIB_H_
+
+#include "qdev.h"
+#include "sysbus.h"
+
+/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ */
+
+/* IRQMP */
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level);
+
+void grlib_irqmp_ack(DeviceState *dev, int intno);
+
+static inline
+DeviceState *grlib_irqmp_create(target_phys_addr_t   base,
+                                CPUState            *env,
+                                qemu_irq           **cpu_irqs,
+                                uint32_t             nr_irqs)
+{
+    DeviceState *dev;
+
+    assert(cpu_irqs != NULL);
+
+    dev = qdev_create(NULL, "grlib,irqmp");
+    qdev_prop_set_ptr(dev, "cpustate", env);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    env->irq_manager = dev;
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
+                                   dev,
+                                   nr_irqs);
+
+    return dev;
+}
+
+/* GPTimer */
+
+static inline
+DeviceState *grlib_gptimer_create(target_phys_addr_t  base,
+                                  uint32_t            nr_timers,
+                                  uint32_t            freq,
+                                  qemu_irq           *cpu_irqs,
+                                  int                 base_irq)
+{
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_create(NULL, "grlib,gptimer");
+    qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
+    qdev_prop_set_uint32(dev, "frequency", freq);
+    qdev_prop_set_uint32(dev, "irq-line", base_irq);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    for (i = 0; i < nr_timers; i++)
+        sysbus_connect_irq(sysbus_from_qdev(dev), i, cpu_irqs[base_irq + i]);
+
+    return dev;
+}
+
+/* APB UART */
+
+static inline
+DeviceState *grlib_apbuart_create(target_phys_addr_t  base,
+                                  CharDriverState    *serial,
+                                  qemu_irq            irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "grlib,apbuart");
+    qdev_prop_set_ptr(dev, "chrdev", serial);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+    sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* ! _GRLIB_H_ */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3.
  2011-01-03 14:07       ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Fabien Chouteau
@ 2011-01-03 14:07         ` Fabien Chouteau
  2011-01-03 14:07           ` [Qemu-devel] [PATCH v2 6/6] SPARCV8 asr17 register support Fabien Chouteau
  2011-01-04 18:56           ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Blue Swirl
  2011-01-04 19:04         ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Blue Swirl
  1 sibling, 2 replies; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau


Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 Makefile.target          |    5 +-
 hw/leon3.c               |  202 ++++++++++++++++++++++++++++++++++++++++++++++
 target-sparc/cpu.h       |   39 ++++++---
 target-sparc/helper.c    |    7 +-
 target-sparc/helper.h    |    1 +
 target-sparc/op_helper.c |  151 ++++++++++++++++++++++++++++++++++-
 target-sparc/translate.c |   14 +++-
 7 files changed, 397 insertions(+), 22 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 2800f47..f40e04f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -290,7 +290,10 @@ obj-sparc-y += cirrus_vga.o
 else
 obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
 obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
-obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
+obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
+
+# GRLIB
+obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
 endif
 
 obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
diff --git a/hw/leon3.c b/hw/leon3.c
new file mode 100644
index 0000000..d5fe863
--- /dev/null
+++ b/hw/leon3.c
@@ -0,0 +1,202 @@
+/*
+ * QEMU Leon3 System Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+
+#include "grlib.h"
+
+//#define DEBUG_LEON3
+
+#ifdef DEBUG_LEON3
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/* Default system clock.  */
+#define CPU_CLK (40 * 1000 * 1000)
+
+#define PROM_FILENAME        "u-boot.bin"
+
+#define MAX_PILS 16
+
+typedef struct ResetData {
+    CPUState *env;
+    uint64_t  entry;            /* save kernel entry in case of reset */
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *)opaque;
+    assert(s != NULL);
+    CPUState *env = s->env;
+    assert(env != NULL);
+
+    cpu_reset(env);
+
+    env->halted = 0;
+    env->pc     = s->entry;
+    env->npc    = s->entry + 4;
+}
+
+static void leon3_irq_ack(void *irq_manager, int intno)
+{
+    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
+    leon3_cache_control_int();
+}
+
+static void leon3_generic_hw_init(ram_addr_t  ram_size,
+                                  const char *boot_device,
+                                  const char *kernel_filename,
+                                  const char *kernel_cmdline,
+                                  const char *initrd_filename,
+                                  const char *cpu_model)
+{
+    CPUState   *env;
+    ram_addr_t  ram_offset, prom_offset;
+    int         ret;
+    char       *filename;
+    qemu_irq   *cpu_irqs = NULL;
+    int         bios_size;
+    int         prom_size;
+    int         aligned_bios_size;
+    ResetData  *reset_info;
+
+    /* Init CPU */
+    if (!cpu_model) {
+        cpu_model = "LEON3";
+    }
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
+    cpu_sparc_set_id(env, 0);
+
+    /* Reset data */
+    reset_info        = qemu_mallocz(sizeof(ResetData));
+    reset_info->env   = env;
+    qemu_register_reset(main_cpu_reset, reset_info);
+
+    /* Allocate IRQ manager */
+    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS);
+
+    env->qemu_irq_ack = leon3_irq_ack;
+
+    /* Allocate RAM */
+    if ((uint64_t)ram_size > (1UL << 30)) {
+        fprintf(stderr,
+                "qemu: Too much memory for this machine: %d, maximum 1G\n",
+                (unsigned int)(ram_size / (1024 * 1024)));
+        exit(1);
+    }
+
+    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
+    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+
+    /* Allocate BIOS */
+    prom_size = 8 * 1024 * 1024; /* 8Mb */
+    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
+    cpu_register_physical_memory(0x00000000, prom_size,
+                                 prom_offset | IO_MEM_ROM);
+
+    /* Load boot prom */
+    if (bios_name == NULL) {
+        bios_name = PROM_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+    bios_size = get_image_size(filename);
+
+    if (bios_size > prom_size) {
+        fprintf(stderr, "qemu: could not load prom '%s': file too big \n",
+                filename);
+        exit(1);
+    }
+
+    if (bios_size > 0) {
+        aligned_bios_size =
+            (bios_size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+
+        ret = load_image_targphys(filename, 0x00000000, bios_size);
+        if (ret < 0 || ret > prom_size) {
+            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
+            exit(1);
+        }
+    }
+    else if (kernel_filename == NULL) {
+        fprintf(stderr,"Can't read bios image %s\n", filename);
+        exit(1);
+    }
+
+    /* Can directly load an application. */
+    if (kernel_filename != NULL) {
+        long     kernel_size;
+        uint64_t entry;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1 /* big endian */, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        if (bios_size <= 0) {
+            /* If there is no bios/monitor, start the application.  */
+            env->pc = entry;
+            env->npc = entry + 4;
+            reset_info->entry = entry;
+        }
+    }
+
+    /* Allocate timers */
+    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+
+    /* Allocate uart */
+    if (serial_hds[0]) {
+        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+    }
+}
+
+QEMUMachine leon3_generic_machine = {
+    .name     = "leon3_generic",
+    .desc     = "Leon-3 generic",
+    .init     = leon3_generic_hw_init,
+    .use_scsi = 0,
+};
+
+static void leon3_machine_init(void)
+{
+    qemu_register_machine(&leon3_generic_machine);
+}
+
+machine_init(leon3_machine_init);
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 7e0d17c..7795be4 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -251,20 +251,21 @@ typedef struct sparc_def_t {
     uint32_t maxtl;
 } sparc_def_t;
 
-#define CPU_FEATURE_FLOAT    (1 << 0)
-#define CPU_FEATURE_FLOAT128 (1 << 1)
-#define CPU_FEATURE_SWAP     (1 << 2)
-#define CPU_FEATURE_MUL      (1 << 3)
-#define CPU_FEATURE_DIV      (1 << 4)
-#define CPU_FEATURE_FLUSH    (1 << 5)
-#define CPU_FEATURE_FSQRT    (1 << 6)
-#define CPU_FEATURE_FMUL     (1 << 7)
-#define CPU_FEATURE_VIS1     (1 << 8)
-#define CPU_FEATURE_VIS2     (1 << 9)
-#define CPU_FEATURE_FSMULD   (1 << 10)
-#define CPU_FEATURE_HYPV     (1 << 11)
-#define CPU_FEATURE_CMT      (1 << 12)
-#define CPU_FEATURE_GL       (1 << 13)
+#define CPU_FEATURE_FLOAT        (1 << 0)
+#define CPU_FEATURE_FLOAT128     (1 << 1)
+#define CPU_FEATURE_SWAP         (1 << 2)
+#define CPU_FEATURE_MUL          (1 << 3)
+#define CPU_FEATURE_DIV          (1 << 4)
+#define CPU_FEATURE_FLUSH        (1 << 5)
+#define CPU_FEATURE_FSQRT        (1 << 6)
+#define CPU_FEATURE_FMUL         (1 << 7)
+#define CPU_FEATURE_VIS1         (1 << 8)
+#define CPU_FEATURE_VIS2         (1 << 9)
+#define CPU_FEATURE_FSMULD       (1 << 10)
+#define CPU_FEATURE_HYPV         (1 << 11)
+#define CPU_FEATURE_CMT          (1 << 12)
+#define CPU_FEATURE_GL           (1 << 13)
+#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
 #ifndef TARGET_SPARC64
 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
@@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
 #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
 #endif
     sparc_def_t *def;
+
+    void *irq_manager;
+    void (*qemu_irq_ack) (void *irq_manager, int intno);
+
+    /* Leon3 cache control */
+    uint32_t cache_control;
 } CPUSPARCState;
 
 #ifndef NO_CPU_IO_DEFS
@@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
 int cpu_cwp_dec(CPUState *env1, int cwp);
 void cpu_set_cwp(CPUState *env1, int new_cwp);
 
+void     leon3_cache_control_st(target_ulong addr, uint64_t val, int size);
+uint64_t leon3_cache_control_ld(target_ulong addr, int size);
+void     leon3_cache_control_int(void);
+
 /* sun4m.c, sun4u.c */
 void cpu_check_irqs(CPUSPARCState *env);
 
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index e84c312..49bdb58 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
     env->pc = 0;
     env->npc = env->pc + 4;
 #endif
+    env->cache_control = 0;
 }
 
 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
@@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
         .mmu_sfsr_mask = 0xffffffff,
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
     },
     {
         .name = "LEON3",
         .iu_version = 0xf3000000,
         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
         .mmu_version = 0xf3000000,
-        .mmu_bm = 0x00004000,
+        .mmu_bm = 0x00000000,
         .mmu_ctpr_mask = 0x007ffff0,
         .mmu_cxr_mask = 0x0000003f,
         .mmu_sfsr_mask = 0xffffffff,
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
     },
 #endif
 };
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 6f103e7..004eaaa 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
 DEF_HELPER_0(fcmpeq_fcc3, void)
 #endif
 DEF_HELPER_1(raise_exception, void, int)
+DEF_HELPER_0(shutdown, void)
 #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
 #define F_HELPER_DQ_0_0(name)                   \
     F_HELPER_0_0(name ## d);                    \
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index be3c1e0..0390aec 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,6 +1,7 @@
 #include "exec.h"
 #include "host-utils.h"
 #include "helper.h"
+#include "sysemu.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
@@ -9,6 +10,7 @@
 //#define DEBUG_ASI
 //#define DEBUG_PCALL
 //#define DEBUG_PSTATE
+//#define DEBUG_CACHE_CONTROL
 
 #ifdef DEBUG_MMU
 #define DPRINTF_MMU(fmt, ...)                                   \
@@ -36,6 +38,13 @@
 #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
 #endif
 
+#ifdef DEBUG_CACHE_CONTROL
+#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
+    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
+#endif
+
 #ifdef TARGET_SPARC64
 #ifndef TARGET_ABI32
 #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
@@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
     raise_exception(tt);
 }
 
+void helper_shutdown(void)
+{
+    qemu_system_shutdown_request();
+}
+
 void helper_check_align(target_ulong addr, uint32_t align)
 {
     if (addr & align) {
@@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
 
     helper_check_align(addr, size - 1);
     switch (asi) {
-    case 2: /* SuperSparc MXCC registers */
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            ret = leon3_cache_control_ld(addr, size);
+            break;
         case 0x01c00a00: /* MXCC control register */
             if (size == 8)
                 ret = env->mxccregs[3];
@@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
 {
     helper_check_align(addr, size - 1);
     switch(asi) {
-    case 2: /* SuperSparc MXCC registers */
+    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
         switch (addr) {
+        case 0x00:          /* Leon3 Cache Control */
+        case 0x08:          /* Leon3 Instruction Cache config */
+        case 0x0C:          /* Leon3 Date Cache config */
+            leon3_cache_control_st(addr, val, size);
+            break;
+
         case 0x01c00000: /* MXCC stream data register 0 */
             if (size == 8)
                 env->mxccdata[0] = val;
@@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
     env->pc = env->tbr;
     env->npc = env->pc + 4;
     env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+    /* IRQ acknowledgment */
+    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
+        env->qemu_irq_ack(env->irq_manager, intno);
+    }
+#endif
 }
 #endif
 
@@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
 #endif
 }
 #endif
+
+/* Leon3 cache control */
+
+/* Cache control: emulate the behavior of cache control registers but without
+   any effect on the emulated CPU */
+
+#define CACHE_STATE_MASK 0x3
+#define CACHE_DISABLED   0x0
+#define CACHE_FROZEN     0x1
+#define CACHE_ENABLED    0x3
+
+/* Cache Control register fields */
+
+#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
+#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
+#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
+#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
+#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
+#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
+#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
+#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */
+
+
+void leon3_cache_control_int(void)
+{
+    uint32_t state = 0;
+
+    if (env->cache_control & CACHE_CTRL_IF) {
+        /* Instruction cache state */
+        state = env->cache_control & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
+        }
+
+        env->cache_control &= ~CACHE_STATE_MASK;
+        env->cache_control |= state;
+    }
+
+    if (env->cache_control & CACHE_CTRL_DF) {
+        /* Data cache state */
+        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
+        if (state == CACHE_ENABLED) {
+            state = CACHE_FROZEN;
+            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
+        }
+
+        env->cache_control &= ~(CACHE_STATE_MASK << 2);
+        env->cache_control |= (state << 2);
+    }
+}
+
+void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
+{
+    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
+                          addr, val, size);
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return;
+    }
+
+    switch (addr) {
+        case 0x00:              /* Cache control */
+
+            /* These values must always be read as zeros */
+            val &= ~CACHE_CTRL_FD;
+            val &= ~CACHE_CTRL_FI;
+            val &= ~CACHE_CTRL_IB;
+            val &= ~CACHE_CTRL_IP;
+            val &= ~CACHE_CTRL_DP;
+
+            env->cache_control = val;
+            break;
+        case 0x04:              /* Instruction cache configuration */
+        case 0x08:              /* Data cache configuration */
+            /* Read Only */
+            break;
+        default:
+            DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
+            break;
+    };
+}
+
+uint64_t leon3_cache_control_ld(target_ulong addr, int size)
+{
+    uint64_t ret = 0;
+
+    if (size != 4) {
+        DPRINTF_CACHE_CONTROL("32bits only\n");
+        return 0;
+    }
+
+    switch (addr) {
+        case 0x00:              /* Cache control */
+            ret = env->cache_control;
+            break;
+
+            /* Configuration registers are read and only always keep those
+               predefined values */
+
+        case 0x04:              /* Instruction cache configuration */
+            ret = 0x10220000;
+            break;
+        case 0x08:              /* Data cache configuration */
+            ret = 0x18220000;
+            break;
+        default:
+            DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
+            break;
+    };
+    DPRINTF_CACHE_CONTROL("st addr:%08x, ret:%" PRIx64 ", size:%d\n",
+                          addr, ret, size);
+    return ret;
+}
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 23f9519..b0e8044 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1997,8 +1997,9 @@ static void disas_sparc_insn(DisasContext * dc)
                     } else
                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
                 }
+
                 cond = GET_FIELD(insn, 3, 6);
-                if (cond == 0x8) {
+                if (cond == 0x8) { /* Trap Always */
                     save_state(dc, cpu_cond);
                     if ((dc->def->features & CPU_FEATURE_HYPV) &&
                         supervisor(dc))
@@ -2007,7 +2008,16 @@ static void disas_sparc_insn(DisasContext * dc)
                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
-                    gen_helper_raise_exception(cpu_tmp32);
+
+                    if (rs2 == 0
+                          &&
+                        dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
+
+                        gen_helper_shutdown();
+
+                    } else {
+                        gen_helper_raise_exception(cpu_tmp32);
+                    }
                 } else if (cond != 0) {
                     TCGv r_cond = tcg_temp_new();
                     int l1;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v2 6/6] SPARCV8 asr17 register support.
  2011-01-03 14:07         ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Fabien Chouteau
@ 2011-01-03 14:07           ` Fabien Chouteau
  2011-01-04 18:31             ` Blue Swirl
  2011-01-04 18:56           ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Blue Swirl
  1 sibling, 1 reply; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-03 14:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Fabien Chouteau


Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
---
 target-sparc/cpu.h       |    1 +
 target-sparc/helper.c    |    3 ++-
 target-sparc/translate.c |   10 ++++++++++
 3 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 7795be4..fe082e3 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -266,6 +266,7 @@ typedef struct sparc_def_t {
 #define CPU_FEATURE_CMT          (1 << 12)
 #define CPU_FEATURE_GL           (1 << 13)
 #define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
+#define CPU_FEATURE_ASR17        (1 << 15)
 #ifndef TARGET_SPARC64
 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 49bdb58..baab379 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1302,7 +1302,8 @@ static const sparc_def_t sparc_defs[] = {
         .mmu_sfsr_mask = 0xffffffff,
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
-        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
+        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
+        CPU_FEATURE_ASR17,
     },
 #endif
 };
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index b0e8044..05f942f 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2068,6 +2068,16 @@ static void disas_sparc_insn(DisasContext * dc)
                 case 0x10 ... 0x1f: /* implementation-dependent in the
                                        SPARCv8 manual, rdy on the
                                        microSPARC II */
+                    if (rs1 == 0x11) { /* Read Asr17 */
+                        TCGv r_const;
+                        CHECK_IU_FEATURE(dc, ASR17);
+                        /* Asr17 for a Leon3 monoprocessor */
+                        r_const = tcg_const_tl((1 << 8)
+                                               | (dc->def->nwindows - 1));
+                        gen_movl_TN_reg(rd, r_const);
+                        tcg_temp_free(r_const);
+                        break;
+                    }
 #endif
                     gen_movl_TN_reg(rd, cpu_y);
                     break;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 6/6] SPARCV8 asr17 register support.
  2011-01-03 14:07           ` [Qemu-devel] [PATCH v2 6/6] SPARCV8 asr17 register support Fabien Chouteau
@ 2011-01-04 18:31             ` Blue Swirl
  0 siblings, 0 replies; 18+ messages in thread
From: Blue Swirl @ 2011-01-04 18:31 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  target-sparc/cpu.h       |    1 +
>  target-sparc/helper.c    |    3 ++-
>  target-sparc/translate.c |   10 ++++++++++
>  3 files changed, 13 insertions(+), 1 deletions(-)
>
> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
> index 7795be4..fe082e3 100644
> --- a/target-sparc/cpu.h
> +++ b/target-sparc/cpu.h
> @@ -266,6 +266,7 @@ typedef struct sparc_def_t {
>  #define CPU_FEATURE_CMT          (1 << 12)
>  #define CPU_FEATURE_GL           (1 << 13)
>  #define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
> +#define CPU_FEATURE_ASR17        (1 << 15)
>  #ifndef TARGET_SPARC64
>  #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
> index 49bdb58..baab379 100644
> --- a/target-sparc/helper.c
> +++ b/target-sparc/helper.c
> @@ -1302,7 +1302,8 @@ static const sparc_def_t sparc_defs[] = {
>         .mmu_sfsr_mask = 0xffffffff,
>         .mmu_trcr_mask = 0xffffffff,
>         .nwindows = 8,
> -        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
> +        CPU_FEATURE_ASR17,
>     },
>  #endif
>  };
> diff --git a/target-sparc/translate.c b/target-sparc/translate.c
> index b0e8044..05f942f 100644
> --- a/target-sparc/translate.c
> +++ b/target-sparc/translate.c
> @@ -2068,6 +2068,16 @@ static void disas_sparc_insn(DisasContext * dc)
>                 case 0x10 ... 0x1f: /* implementation-dependent in the
>                                        SPARCv8 manual, rdy on the
>                                        microSPARC II */
> +                    if (rs1 == 0x11) { /* Read Asr17 */
> +                        TCGv r_const;
> +                        CHECK_IU_FEATURE(dc, ASR17);

This would make the instruction illegal for those CPUs which didn't
have this feature, now it is handled like rdy. So please change the if
() above to also handle the feature check without the macro.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART as defined in GRLIB IP Core User's Manual.
  2011-01-03 14:07     ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART " Fabien Chouteau
  2011-01-03 14:07       ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Fabien Chouteau
@ 2011-01-04 18:38       ` Blue Swirl
  1 sibling, 0 replies; 18+ messages in thread
From: Blue Swirl @ 2011-01-04 18:38 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  hw/grlib_apbuart.c |  208 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 208 insertions(+), 0 deletions(-)
>
> diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
> new file mode 100644
> index 0000000..a2ff8ed
> --- /dev/null
> +++ b/hw/grlib_apbuart.c
> @@ -0,0 +1,208 @@
> +/*
> + * QEMU GRLIB APB UART Emulator
> + *
> + * Copyright (c) 2010-2011 AdaCore
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "sysbus.h"
> +#include "qemu-char.h"
> +
> +//#define DEBUG_UART
> +
> +#ifdef DEBUG_UART
> +#define DPRINTF(fmt, ...)                                       \
> +    do { printf("APBUART: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...)
> +#endif

Instead of DPRINTFs, you could use tracepoints. They are much faster
and more flexible.

> +
> +#define UART_REG_SIZE 20     /* Size of memory mapped registers */
> +
> +/* UART status register fields */
> +#define UART_DATA_READY           (1 <<  0)
> +#define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
> +#define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
> +#define UART_BREAK_RECEIVED       (1 <<  3)
> +#define UART_OVERRUN              (1 <<  4)
> +#define UART_PARITY_ERROR         (1 <<  5)
> +#define UART_FRAMING_ERROR        (1 <<  6)
> +#define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
> +#define UART_RECEIVE_FIFO_HALF    (1 <<  8)
> +#define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
> +#define UART_RECEIVE_FIFO_FULL    (1 << 10)
> +
> +/* UART control register fields */
> +#define UART_RECEIVE_ENABLE          (1 <<  0)
> +#define UART_TRANSMIT_ENABLE         (1 <<  1)
> +#define UART_RECEIVE_INTERRUPT       (1 <<  2)
> +#define UART_TRANSMIT_INTERRUPT      (1 <<  3)
> +#define UART_PARITY_SELECT           (1 <<  4)
> +#define UART_PARITY_ENABLE           (1 <<  5)
> +#define UART_FLOW_CONTROL            (1 <<  6)
> +#define UART_LOOPBACK                (1 <<  7)
> +#define UART_EXTERNAL_CLOCK          (1 <<  8)
> +#define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
> +#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
> +#define UART_FIFO_DEBUG_MODE         (1 << 11)
> +#define UART_OUTPUT_ENABLE           (1 << 12)
> +#define UART_FIFO_AVAILABLE          (1 << 31)
> +
> +/* Memory mapped register offsets */
> +#define DATA_OFFSET       0x00
> +#define STATUS_OFFSET     0x04
> +#define CONTROL_OFFSET    0x08
> +#define SCALER_OFFSET     0x0C  /* not supported */
> +#define FIFO_DEBUG_OFFSET 0x10  /* not supported */
> +
> +typedef struct UART
> +{
> +    SysBusDevice busdev;
> +
> +    qemu_irq irq;
> +
> +    CharDriverState *chr;
> +
> +    /* registers */
> +    uint32_t receive;
> +    uint32_t status;
> +    uint32_t control;
> +} UART;
> +
> +static int grlib_apbuart_can_receive(void *opaque)
> +{
> +    UART *uart = opaque;
> +    assert(uart != NULL);

I don't think this can ever trigger.

> +
> +    return !!(uart->status & UART_DATA_READY);
> +}
> +
> +static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
> +{
> +    UART *uart = opaque;
> +    assert(uart != NULL);

Also here.

> +
> +    uart->receive  = *buf;
> +    uart->status  |= UART_DATA_READY;
> +
> +    if (uart->control & UART_RECEIVE_INTERRUPT) {
> +        qemu_irq_pulse(uart->irq);
> +    }
> +}
> +
> +static void grlib_apbuart_event(void *opaque, int event)
> +{
> +    DPRINTF("uart: event %x\n", event);
> +}
> +
> +static void
> +grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
> +{
> +    UART          *uart = opaque;
> +    unsigned char  c    = 0;
> +
> +    addr &= 0xff;

This is not needed. If you just want to adjust DPRINTF output, move
the operation there.

> +
> +    assert(uart != NULL);

This will never trigger.

> +
> +    /* Unit registers */
> +    switch (addr)
> +    {
> +        case DATA_OFFSET:
> +            c = value & 0xFF;
> +            qemu_chr_write(uart->chr, &c, 1);
> +            return;
> +
> +        case STATUS_OFFSET:
> +            /* Read Only */
> +            return;
> +
> +        case CONTROL_OFFSET:
> +            /* Not supported */
> +            return;
> +
> +        case SCALER_OFFSET:
> +            /* Not supported */
> +            return;
> +
> +        default:
> +            break;
> +    }
> +
> +    DPRINTF("write unknown register " TARGET_FMT_plx "\n", addr);
> +}
> +
> +static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
> +    NULL, NULL, NULL,
> +};
> +
> +static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
> +    NULL, NULL, grlib_apbuart_writel,
> +};
> +
> +static int grlib_apbuart_init(SysBusDevice *dev)
> +{
> +    UART *uart      = FROM_SYSBUS(typeof (*uart), dev);
> +    int   uart_regs = 0;
> +
> +    assert(uart != NULL);
> +    assert(uart->chr != NULL);

These will also never trigger.

> +
> +    qemu_chr_add_handlers(uart->chr,
> +                          grlib_apbuart_can_receive,
> +                          grlib_apbuart_receive,
> +                          grlib_apbuart_event,
> +                          uart);
> +
> +    sysbus_init_irq(dev, &uart->irq);
> +
> +    uart_regs = cpu_register_io_memory(grlib_apbuart_read,
> +                                       grlib_apbuart_write,
> +                                       uart);
> +    if (uart_regs < 0) {
> +        return -1;
> +    }
> +
> +    sysbus_init_mmio(dev, UART_REG_SIZE, uart_regs);
> +
> +    return 0;
> +}
> +
> +static SysBusDeviceInfo grlib_gptimer_info = {
> +    .init       = grlib_apbuart_init,
> +    .qdev.name  = "grlib,apbuart",
> +    .qdev.size  = sizeof(UART),
> +    .qdev.props = (Property[]) {
> +        {
> +            .name   = "chrdev",
> +            .info   = &qdev_prop_ptr,
> +            .offset = offsetof(UART, chr),
> +            .defval = (void*[]) { NULL },

There's DEFINE_PROP_CHR() macro, please use that.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual.
  2011-01-03 14:07 ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual Fabien Chouteau
  2011-01-03 14:07   ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Fabien Chouteau
@ 2011-01-04 18:46   ` Blue Swirl
  2011-01-17 11:43     ` Fabien Chouteau
  1 sibling, 1 reply; 18+ messages in thread
From: Blue Swirl @ 2011-01-04 18:46 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  hw/grlib_gptimer.c |  427 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 427 insertions(+), 0 deletions(-)
>
> diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
> new file mode 100644
> index 0000000..e33d506
> --- /dev/null
> +++ b/hw/grlib_gptimer.c
> @@ -0,0 +1,427 @@
> +/*
> + * QEMU GRLIB GPTimer Emulator
> + *
> + * Copyright (c) 2010-2011 AdaCore
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "sysbus.h"
> +#include "qemu-timer.h"
> +
> +//#define DEBUG_TIMER
> +
> +#ifdef DEBUG_TIMER
> +#define DPRINTF(fmt, ...)                                       \
> +    do { printf("GPTIMER: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...)
> +#endif
> +
> +#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
> +#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
> +
> +#define GPTIMER_MAX_TIMERS 8
> +
> +/* GPTimer Config register fields */
> +#define GPTIMER_ENABLE      (1 << 0)
> +#define GPTIMER_RESTART     (1 << 1)
> +#define GPTIMER_LOAD        (1 << 2)
> +#define GPTIMER_INT_ENABLE  (1 << 3)
> +#define GPTIMER_INT_PENDING (1 << 4)
> +#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
> +#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
> +
> +/* Memory mapped register offsets */
> +#define SCALER_OFFSET         0x00
> +#define SCALER_RELOAD_OFFSET  0x04
> +#define CONFIG_OFFSET         0x08
> +#define COUNTER_OFFSET        0x00
> +#define COUNTER_RELOAD_OFFSET 0x04
> +#define TIMER_BASE            0x10
> +
> +typedef struct GPTimer     GPTimer;
> +typedef struct GPTimerUnit GPTimerUnit;
> +
> +struct GPTimer
> +{
> +    QEMUBH *bh;
> +    struct ptimer_state *ptimer;
> +
> +    qemu_irq     irq;
> +    int          id;
> +    GPTimerUnit *unit;
> +
> +    /* registers */
> +    uint32_t counter;
> +    uint32_t reload;
> +    uint32_t config;
> +};
> +
> +struct GPTimerUnit
> +{
> +    SysBusDevice  busdev;
> +
> +    uint32_t nr_timers;         /* Number of timers available */
> +    uint32_t freq_hz;           /* System frequency */
> +    uint32_t irq_line;          /* Base irq line */
> +
> +    GPTimer *timers;
> +
> +    /* registers */
> +    uint32_t scaler;
> +    uint32_t reload;
> +    uint32_t config;
> +};
> +
> +static void grlib_gptimer_enable(GPTimer *timer)
> +{
> +    assert(timer != NULL);
> +
> +    DPRINTF("%s id:%d\n", __func__, timer->id);
> +
> +    ptimer_stop(timer->ptimer);
> +
> +    if (!(timer->config & GPTIMER_ENABLE)) {
> +        /* Timer disabled */
> +        DPRINTF("%s id:%d Timer disabled (config 0x%x)\n", __func__,
> +                timer->id, timer->config);
> +        return;
> +    }
> +
> +    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
> +       underflow. Set count + 1 to simulate the GPTimer behavior. */
> +
> +    DPRINTF("%s id:%d set count 0x%x and run\n",
> +            __func__,
> +            timer->id,
> +            timer->counter + 1);
> +
> +    ptimer_set_count(timer->ptimer, timer->counter + 1);
> +    ptimer_run(timer->ptimer, 1);
> +}
> +
> +static void grlib_gptimer_restart(GPTimer *timer)
> +{
> +    assert(timer != NULL);
> +
> +    DPRINTF("%s id:%d reload val: 0x%x\n", __func__, timer->id, timer->reload);
> +
> +    timer->counter = timer->reload;
> +    grlib_gptimer_enable(timer);
> +}
> +
> +static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
> +{
> +    int i = 0;
> +    uint32_t value = 0;
> +
> +    assert(unit != NULL);
> +
> +
> +    if (scaler > 0) {
> +        value = unit->freq_hz / (scaler + 1);
> +    } else {
> +        value = unit->freq_hz;
> +    }
> +
> +    DPRINTF("%s scaler:%d freq:0x%x\n", __func__, scaler, value);
> +
> +    for (i = 0; i < unit->nr_timers; i++) {
> +        ptimer_set_freq(unit->timers[i].ptimer, value);
> +    }
> +}
> +
> +static void grlib_gptimer_hit(void *opaque)
> +{
> +    GPTimer *timer = opaque;
> +    assert(timer != NULL);
> +
> +    DPRINTF("%s id:%d\n", __func__, timer->id);
> +
> +    /* Timer expired */
> +
> +    if (timer->config & GPTIMER_INT_ENABLE) {
> +        /* Set the pending bit (only unset by write in the config register) */
> +        timer->config |= GPTIMER_INT_PENDING;
> +        qemu_irq_pulse(timer->irq);
> +    }
> +
> +    if (timer->config & GPTIMER_RESTART) {
> +        grlib_gptimer_restart(timer);
> +    }
> +}
> +
> +static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    GPTimerUnit *unit  = opaque;
> +    uint32_t     value = 0;
> +
> +    addr &= 0xff;

Not needed.

> +
> +    assert(unit != NULL);

Won't trigger.

> +
> +    /* Unit registers */
> +    switch (addr)
> +    {
> +        case SCALER_OFFSET:
> +            DPRINTF("%s scaler: 0x%x\n", __func__, unit->scaler);
> +            return unit->scaler;
> +
> +        case SCALER_RELOAD_OFFSET:
> +            DPRINTF("%s reload: 0x%x\n", __func__, unit->reload);
> +            return unit->reload;
> +
> +        case CONFIG_OFFSET:
> +            DPRINTF("%s unit config: 0x%x\n", __func__, unit->config);
> +            return unit->config;
> +
> +        default:
> +            break;
> +    }
> +
> +    target_phys_addr_t timer_addr = (addr % TIMER_BASE);
> +    int                id         = (addr - TIMER_BASE) / TIMER_BASE;

These should be in the beginning of the function or split it, see my
previous comments.

> +
> +    if (id >= 0 && id < unit->nr_timers) {
> +
> +        /* GPTimer registers */
> +        switch (timer_addr)
> +        {
> +            case COUNTER_OFFSET:
> +                value = ptimer_get_count (unit->timers[id].ptimer);
> +                DPRINTF("%s counter value for timer %d: 0x%x\n",
> +                        __func__, id, value);
> +                return value;
> +
> +            case COUNTER_RELOAD_OFFSET:
> +                value = unit->timers[id].reload;
> +                DPRINTF("%s reload value for timer %d: 0x%x\n",
> +                        __func__, id, value);
> +                return value;
> +
> +            case CONFIG_OFFSET:
> +                DPRINTF("%s config for timer %d: 0x%x\n",
> +                        __func__, id, unit->timers[id].config);
> +                return unit->timers[id].config;
> +
> +            default:
> +                break;
> +        }
> +
> +    }
> +
> +    DPRINTF("read unknown register " TARGET_FMT_plx "\n", addr);
> +    return 0;
> +}
> +
> +static void
> +grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)

See above.

> +{
> +    GPTimerUnit *unit = opaque;
> +
> +    addr &= 0xff;
> +
> +    assert(unit != NULL);
> +
> +    /* Unit registers */
> +    switch (addr)
> +    {
> +        case SCALER_OFFSET:
> +            value &= 0xFFFF; /* clean up the value */
> +            unit->scaler = value;
> +            return;
> +
> +        case SCALER_RELOAD_OFFSET:
> +            value &= 0xFFFF; /* clean up the value */
> +            unit->reload = value;
> +            grlib_gptimer_set_scaler(unit, value);
> +            return;
> +
> +        case CONFIG_OFFSET:
> +            /* Read Only (disable timer freeze not supported) */
> +            return;
> +
> +        default:
> +            break;
> +    }
> +
> +    target_phys_addr_t timer_addr = (addr % TIMER_BASE);
> +    int                id         = (addr - TIMER_BASE) / TIMER_BASE;
> +
> +    if (id >= 0 && id < unit->nr_timers) {
> +
> +        /* GPTimer registers */
> +        switch (timer_addr)
> +        {
> +            case COUNTER_OFFSET:
> +                DPRINTF("%s counter value for timer %d: 0x%x\n",
> +                        __func__, id, value);
> +                unit->timers[id].counter = value;
> +                grlib_gptimer_enable(&unit->timers[id]);
> +                return;
> +
> +            case COUNTER_RELOAD_OFFSET:
> +                DPRINTF("%s reload value for timer %d: 0x%x\n",
> +                        __func__, id, value);
> +                unit->timers[id].reload = value;
> +                return;
> +
> +            case CONFIG_OFFSET:
> +                DPRINTF("%s config for timer %d: 0x%x\n", __func__, id, value);
> +
> +                if (value & GPTIMER_INT_PENDING) {
> +                    /* clear pending bit */
> +                    value &= ~GPTIMER_INT_PENDING;
> +                } else {
> +                    /* keep pending bit */
> +                    value |= unit->timers[id].config & GPTIMER_INT_PENDING;
> +                }
> +
> +                unit->timers[id].config = value;
> +
> +                /* gptimer_restart calls gptimer_enable, so if "enable" and
> +                   "load" bits are present, we just have to call restart. */
> +
> +                if (value & GPTIMER_LOAD) {
> +                    grlib_gptimer_restart(&unit->timers[id]);
> +                } else if (value & GPTIMER_ENABLE) {
> +                    grlib_gptimer_enable(&unit->timers[id]);
> +                }
> +
> +                /* These fields must always be read as 0 */
> +                value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
> +
> +                unit->timers[id].config = value;
> +                return;
> +
> +            default:
> +                break;
> +        }
> +
> +    }
> +
> +    DPRINTF("write unknown register " TARGET_FMT_plx "\n", addr);
> +}
> +
> +static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
> +    NULL, NULL, grlib_gptimer_readl,
> +};
> +
> +static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
> +    NULL, NULL, grlib_gptimer_writel,
> +};
> +
> +static void grlib_gptimer_reset(DeviceState *d)
> +{
> +    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
> +    int          i    = 0;
> +
> +    assert(unit != NULL);
> +
> +    unit->scaler = 0;
> +    unit->reload = 0;
> +    unit->config = 0;
> +
> +    unit->config  = unit->nr_timers;
> +    unit->config |= unit->irq_line << 3;
> +    unit->config |= 1 << 8;     /* separate interrupt */
> +    unit->config |= 1 << 9;     /* Disable timer freeze */
> +
> +
> +    for (i = 0; i < unit->nr_timers; i++) {
> +        GPTimer *timer = &unit->timers[i];
> +
> +        timer->counter = 0;
> +        timer->reload = 0;
> +        timer->config = 0;
> +        ptimer_stop(timer->ptimer);
> +        ptimer_set_count(timer->ptimer, 0);
> +        ptimer_set_freq(timer->ptimer, unit->freq_hz);
> +    }
> +}
> +
> +static int grlib_gptimer_init(SysBusDevice *dev)
> +{
> +    GPTimerUnit  *unit = FROM_SYSBUS(typeof (*unit), dev);
> +    unsigned int  i;
> +    int           timer_regs;
> +
> +    assert(unit->nr_timers > 0);
> +    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
> +    unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
> +
> +    for (i = 0; i < unit->nr_timers; i++) {
> +        GPTimer *timer = &unit->timers[i];
> +
> +        timer->unit   = unit;
> +        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
> +        timer->ptimer = ptimer_init(timer->bh);
> +        timer->id     = i;
> +
> +        /* One IRQ line for each timer */
> +        sysbus_init_irq(dev, &timer->irq);
> +
> +        ptimer_set_freq(timer->ptimer, unit->freq_hz);
> +    }
> +
> +    timer_regs = cpu_register_io_memory(grlib_gptimer_read,
> +                                        grlib_gptimer_write,
> +                                        unit);
> +    if (timer_regs < 0) {
> +        return -1;
> +    }
> +
> +    sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
> +                     timer_regs);
> +    return 0;
> +}
> +
> +static SysBusDeviceInfo grlib_gptimer_info = {
> +    .init       = grlib_gptimer_init,
> +    .qdev.name  = "grlib,gptimer",
> +    .qdev.reset = grlib_gptimer_reset,
> +    .qdev.size  = sizeof(GPTimerUnit),
> +    .qdev.props = (Property[]) {
> +        {
> +            .name   = "frequency",
> +            .info   = &qdev_prop_uint32,
> +            .offset = offsetof(GPTimerUnit, freq_hz),
> +            .defval = (uint32_t[]) { 2 },

Please use DEFINE_PROP_UINT32() for the properties.

> +        },{
> +            .name   = "irq-line",
> +            .info   = &qdev_prop_uint32,
> +            .offset = offsetof(GPTimerUnit, irq_line),
> +            .defval = (uint32_t[]) { 8 },
> +        },{
> +            .name   = "nr-timers",
> +            .info   = &qdev_prop_uint32,
> +            .offset = offsetof(GPTimerUnit, nr_timers),
> +            .defval = (uint32_t[]) { 2 },
> +        },
> +        {/* end of list */}
> +    }
> +};
> +
> +static void grlib_gptimer_register(void)
> +{
> +    sysbus_register_withprop(&grlib_gptimer_info);
> +}
> +
> +device_init(grlib_gptimer_register)
> --
> 1.7.1
>
>
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3.
  2011-01-03 14:07         ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Fabien Chouteau
  2011-01-03 14:07           ` [Qemu-devel] [PATCH v2 6/6] SPARCV8 asr17 register support Fabien Chouteau
@ 2011-01-04 18:56           ` Blue Swirl
  2011-01-17 16:01             ` Fabien Chouteau
  1 sibling, 1 reply; 18+ messages in thread
From: Blue Swirl @ 2011-01-04 18:56 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  Makefile.target          |    5 +-
>  hw/leon3.c               |  202 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-sparc/cpu.h       |   39 ++++++---
>  target-sparc/helper.c    |    7 +-
>  target-sparc/helper.h    |    1 +
>  target-sparc/op_helper.c |  151 ++++++++++++++++++++++++++++++++++-
>  target-sparc/translate.c |   14 +++-
>  7 files changed, 397 insertions(+), 22 deletions(-)
>
> diff --git a/Makefile.target b/Makefile.target
> index 2800f47..f40e04f 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -290,7 +290,10 @@ obj-sparc-y += cirrus_vga.o
>  else
>  obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
>  obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
> -obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
> +obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
> +
> +# GRLIB
> +obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
>  endif
>
>  obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
> diff --git a/hw/leon3.c b/hw/leon3.c
> new file mode 100644
> index 0000000..d5fe863
> --- /dev/null
> +++ b/hw/leon3.c
> @@ -0,0 +1,202 @@
> +/*
> + * QEMU Leon3 System Emulator
> + *
> + * Copyright (c) 2010-2011 AdaCore
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "hw.h"
> +#include "qemu-timer.h"
> +#include "qemu-char.h"
> +#include "sysemu.h"
> +#include "boards.h"
> +#include "loader.h"
> +#include "elf.h"
> +
> +#include "grlib.h"
> +
> +//#define DEBUG_LEON3
> +
> +#ifdef DEBUG_LEON3
> +#define DPRINTF(fmt, ...)                                       \
> +    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...)
> +#endif
> +
> +/* Default system clock.  */
> +#define CPU_CLK (40 * 1000 * 1000)
> +
> +#define PROM_FILENAME        "u-boot.bin"
> +
> +#define MAX_PILS 16
> +
> +typedef struct ResetData {
> +    CPUState *env;
> +    uint64_t  entry;            /* save kernel entry in case of reset */

uint32_t should be enough.

> +} ResetData;
> +
> +static void main_cpu_reset(void *opaque)
> +{
> +    ResetData *s = (ResetData *)opaque;
> +    assert(s != NULL);
> +    CPUState *env = s->env;
> +    assert(env != NULL);

These asserts won't ever trigger.

> +
> +    cpu_reset(env);
> +
> +    env->halted = 0;
> +    env->pc     = s->entry;
> +    env->npc    = s->entry + 4;
> +}
> +
> +static void leon3_irq_ack(void *irq_manager, int intno)
> +{
> +    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
> +    leon3_cache_control_int();
> +}
> +
> +static void leon3_generic_hw_init(ram_addr_t  ram_size,
> +                                  const char *boot_device,
> +                                  const char *kernel_filename,
> +                                  const char *kernel_cmdline,
> +                                  const char *initrd_filename,
> +                                  const char *cpu_model)
> +{
> +    CPUState   *env;
> +    ram_addr_t  ram_offset, prom_offset;
> +    int         ret;
> +    char       *filename;
> +    qemu_irq   *cpu_irqs = NULL;
> +    int         bios_size;
> +    int         prom_size;
> +    int         aligned_bios_size;
> +    ResetData  *reset_info;
> +
> +    /* Init CPU */
> +    if (!cpu_model) {
> +        cpu_model = "LEON3";
> +    }
> +
> +    env = cpu_init(cpu_model);
> +    if (!env) {
> +        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
> +        exit(1);
> +    }
> +
> +    cpu_sparc_set_id(env, 0);
> +
> +    /* Reset data */
> +    reset_info        = qemu_mallocz(sizeof(ResetData));
> +    reset_info->env   = env;
> +    qemu_register_reset(main_cpu_reset, reset_info);
> +
> +    /* Allocate IRQ manager */
> +    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS);
> +
> +    env->qemu_irq_ack = leon3_irq_ack;
> +
> +    /* Allocate RAM */
> +    if ((uint64_t)ram_size > (1UL << 30)) {
> +        fprintf(stderr,
> +                "qemu: Too much memory for this machine: %d, maximum 1G\n",
> +                (unsigned int)(ram_size / (1024 * 1024)));
> +        exit(1);
> +    }
> +
> +    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
> +    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
> +
> +    /* Allocate BIOS */
> +    prom_size = 8 * 1024 * 1024; /* 8Mb */
> +    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
> +    cpu_register_physical_memory(0x00000000, prom_size,
> +                                 prom_offset | IO_MEM_ROM);
> +
> +    /* Load boot prom */
> +    if (bios_name == NULL) {
> +        bios_name = PROM_FILENAME;
> +    }
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> +
> +    bios_size = get_image_size(filename);
> +
> +    if (bios_size > prom_size) {
> +        fprintf(stderr, "qemu: could not load prom '%s': file too big \n",
> +                filename);
> +        exit(1);
> +    }
> +
> +    if (bios_size > 0) {
> +        aligned_bios_size =
> +            (bios_size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
> +
> +        ret = load_image_targphys(filename, 0x00000000, bios_size);
> +        if (ret < 0 || ret > prom_size) {
> +            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
> +            exit(1);
> +        }
> +    }
> +    else if (kernel_filename == NULL) {
> +        fprintf(stderr,"Can't read bios image %s\n", filename);
> +        exit(1);
> +    }
> +
> +    /* Can directly load an application. */
> +    if (kernel_filename != NULL) {
> +        long     kernel_size;
> +        uint64_t entry;

uint32_t

> +
> +        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
> +                               1 /* big endian */, ELF_MACHINE, 0);
> +        if (kernel_size < 0) {
> +            fprintf(stderr, "qemu: could not load kernel '%s'\n",
> +                    kernel_filename);
> +            exit(1);
> +        }
> +        if (bios_size <= 0) {
> +            /* If there is no bios/monitor, start the application.  */
> +            env->pc = entry;
> +            env->npc = entry + 4;
> +            reset_info->entry = entry;
> +        }
> +    }
> +
> +    /* Allocate timers */
> +    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
> +
> +    /* Allocate uart */
> +    if (serial_hds[0]) {
> +        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
> +    }
> +}
> +
> +QEMUMachine leon3_generic_machine = {
> +    .name     = "leon3_generic",
> +    .desc     = "Leon-3 generic",
> +    .init     = leon3_generic_hw_init,
> +    .use_scsi = 0,
> +};
> +
> +static void leon3_machine_init(void)
> +{
> +    qemu_register_machine(&leon3_generic_machine);
> +}
> +
> +machine_init(leon3_machine_init);
> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
> index 7e0d17c..7795be4 100644
> --- a/target-sparc/cpu.h
> +++ b/target-sparc/cpu.h
> @@ -251,20 +251,21 @@ typedef struct sparc_def_t {
>     uint32_t maxtl;
>  } sparc_def_t;
>
> -#define CPU_FEATURE_FLOAT    (1 << 0)
> -#define CPU_FEATURE_FLOAT128 (1 << 1)
> -#define CPU_FEATURE_SWAP     (1 << 2)
> -#define CPU_FEATURE_MUL      (1 << 3)
> -#define CPU_FEATURE_DIV      (1 << 4)
> -#define CPU_FEATURE_FLUSH    (1 << 5)
> -#define CPU_FEATURE_FSQRT    (1 << 6)
> -#define CPU_FEATURE_FMUL     (1 << 7)
> -#define CPU_FEATURE_VIS1     (1 << 8)
> -#define CPU_FEATURE_VIS2     (1 << 9)
> -#define CPU_FEATURE_FSMULD   (1 << 10)
> -#define CPU_FEATURE_HYPV     (1 << 11)
> -#define CPU_FEATURE_CMT      (1 << 12)
> -#define CPU_FEATURE_GL       (1 << 13)
> +#define CPU_FEATURE_FLOAT        (1 << 0)
> +#define CPU_FEATURE_FLOAT128     (1 << 1)
> +#define CPU_FEATURE_SWAP         (1 << 2)
> +#define CPU_FEATURE_MUL          (1 << 3)
> +#define CPU_FEATURE_DIV          (1 << 4)
> +#define CPU_FEATURE_FLUSH        (1 << 5)
> +#define CPU_FEATURE_FSQRT        (1 << 6)
> +#define CPU_FEATURE_FMUL         (1 << 7)
> +#define CPU_FEATURE_VIS1         (1 << 8)
> +#define CPU_FEATURE_VIS2         (1 << 9)
> +#define CPU_FEATURE_FSMULD       (1 << 10)
> +#define CPU_FEATURE_HYPV         (1 << 11)
> +#define CPU_FEATURE_CMT          (1 << 12)
> +#define CPU_FEATURE_GL           (1 << 13)
> +#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
>  #ifndef TARGET_SPARC64
>  #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
> @@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
>  #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
>  #endif
>     sparc_def_t *def;
> +
> +    void *irq_manager;
> +    void (*qemu_irq_ack) (void *irq_manager, int intno);
> +
> +    /* Leon3 cache control */
> +    uint32_t cache_control;
>  } CPUSPARCState;
>
>  #ifndef NO_CPU_IO_DEFS
> @@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
>  int cpu_cwp_dec(CPUState *env1, int cwp);
>  void cpu_set_cwp(CPUState *env1, int new_cwp);
>
> +void     leon3_cache_control_st(target_ulong addr, uint64_t val, int size);
> +uint64_t leon3_cache_control_ld(target_ulong addr, int size);
> +void     leon3_cache_control_int(void);

Is there any need to export these?

> +
>  /* sun4m.c, sun4u.c */
>  void cpu_check_irqs(CPUSPARCState *env);
>
> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
> index e84c312..49bdb58 100644
> --- a/target-sparc/helper.c
> +++ b/target-sparc/helper.c
> @@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
>     env->pc = 0;
>     env->npc = env->pc + 4;
>  #endif
> +    env->cache_control = 0;
>  }
>
>  static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
> @@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
>         .mmu_sfsr_mask = 0xffffffff,
>         .mmu_trcr_mask = 0xffffffff,
>         .nwindows = 8,
> -        .features = CPU_DEFAULT_FEATURES,
> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>     },
>     {
>         .name = "LEON3",
>         .iu_version = 0xf3000000,
>         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
>         .mmu_version = 0xf3000000,
> -        .mmu_bm = 0x00004000,
> +        .mmu_bm = 0x00000000,
>         .mmu_ctpr_mask = 0x007ffff0,
>         .mmu_cxr_mask = 0x0000003f,
>         .mmu_sfsr_mask = 0xffffffff,
>         .mmu_trcr_mask = 0xffffffff,
>         .nwindows = 8,
> -        .features = CPU_DEFAULT_FEATURES,
> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>     },
>  #endif
>  };
> diff --git a/target-sparc/helper.h b/target-sparc/helper.h
> index 6f103e7..004eaaa 100644
> --- a/target-sparc/helper.h
> +++ b/target-sparc/helper.h
> @@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
>  DEF_HELPER_0(fcmpeq_fcc3, void)
>  #endif
>  DEF_HELPER_1(raise_exception, void, int)
> +DEF_HELPER_0(shutdown, void)
>  #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
>  #define F_HELPER_DQ_0_0(name)                   \
>     F_HELPER_0_0(name ## d);                    \
> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
> index be3c1e0..0390aec 100644
> --- a/target-sparc/op_helper.c
> +++ b/target-sparc/op_helper.c
> @@ -1,6 +1,7 @@
>  #include "exec.h"
>  #include "host-utils.h"
>  #include "helper.h"
> +#include "sysemu.h"
>
>  //#define DEBUG_MMU
>  //#define DEBUG_MXCC
> @@ -9,6 +10,7 @@
>  //#define DEBUG_ASI
>  //#define DEBUG_PCALL
>  //#define DEBUG_PSTATE
> +//#define DEBUG_CACHE_CONTROL
>
>  #ifdef DEBUG_MMU
>  #define DPRINTF_MMU(fmt, ...)                                   \
> @@ -36,6 +38,13 @@
>  #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
>  #endif
>
> +#ifdef DEBUG_CACHE_CONTROL
> +#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
> +    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
> +#endif
> +
>  #ifdef TARGET_SPARC64
>  #ifndef TARGET_ABI32
>  #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
> @@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
>     raise_exception(tt);
>  }
>
> +void helper_shutdown(void)
> +{
> +    qemu_system_shutdown_request();
> +}
> +
>  void helper_check_align(target_ulong addr, uint32_t align)
>  {
>     if (addr & align) {
> @@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
>
>     helper_check_align(addr, size - 1);
>     switch (asi) {
> -    case 2: /* SuperSparc MXCC registers */
> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>         switch (addr) {
> +        case 0x00:          /* Leon3 Cache Control */
> +        case 0x08:          /* Leon3 Instruction Cache config */
> +        case 0x0C:          /* Leon3 Date Cache config */
> +            ret = leon3_cache_control_ld(addr, size);
> +            break;
>         case 0x01c00a00: /* MXCC control register */
>             if (size == 8)
>                 ret = env->mxccregs[3];
> @@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
>  {
>     helper_check_align(addr, size - 1);
>     switch(asi) {
> -    case 2: /* SuperSparc MXCC registers */
> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>         switch (addr) {
> +        case 0x00:          /* Leon3 Cache Control */
> +        case 0x08:          /* Leon3 Instruction Cache config */
> +        case 0x0C:          /* Leon3 Date Cache config */
> +            leon3_cache_control_st(addr, val, size);
> +            break;
> +
>         case 0x01c00000: /* MXCC stream data register 0 */
>             if (size == 8)
>                 env->mxccdata[0] = val;
> @@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
>     env->pc = env->tbr;
>     env->npc = env->pc + 4;
>     env->exception_index = -1;
> +
> +#if !defined(CONFIG_USER_ONLY)
> +    /* IRQ acknowledgment */
> +    if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
> +        env->qemu_irq_ack(env->irq_manager, intno);
> +    }
> +#endif
>  }
>  #endif
>
> @@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
>  #endif
>  }
>  #endif
> +
> +/* Leon3 cache control */
> +
> +/* Cache control: emulate the behavior of cache control registers but without
> +   any effect on the emulated CPU */
> +
> +#define CACHE_STATE_MASK 0x3
> +#define CACHE_DISABLED   0x0
> +#define CACHE_FROZEN     0x1
> +#define CACHE_ENABLED    0x3
> +
> +/* Cache Control register fields */
> +
> +#define CACHE_CTRL_IF (1 <<  4)  /* Instruction Cache Freeze on Interrupt */
> +#define CACHE_CTRL_DF (1 <<  5)  /* Data Cache Freeze on Interrupt */
> +#define CACHE_CTRL_DP (1 << 14)  /* Data cache flush pending */
> +#define CACHE_CTRL_IP (1 << 15)  /* Instruction cache flush pending */
> +#define CACHE_CTRL_IB (1 << 16)  /* Instruction burst fetch */
> +#define CACHE_CTRL_FI (1 << 21)  /* Flush Instruction cache (Write only) */
> +#define CACHE_CTRL_FD (1 << 22)  /* Flush Data cache (Write only) */
> +#define CACHE_CTRL_DS (1 << 23)  /* Data cache snoop enable */

These should be at the top of the file.

> +
> +
> +void leon3_cache_control_int(void)
> +{
> +    uint32_t state = 0;
> +
> +    if (env->cache_control & CACHE_CTRL_IF) {
> +        /* Instruction cache state */
> +        state = env->cache_control & CACHE_STATE_MASK;
> +        if (state == CACHE_ENABLED) {
> +            state = CACHE_FROZEN;
> +            DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
> +        }
> +
> +        env->cache_control &= ~CACHE_STATE_MASK;
> +        env->cache_control |= state;
> +    }
> +
> +    if (env->cache_control & CACHE_CTRL_DF) {
> +        /* Data cache state */
> +        state = (env->cache_control >> 2) & CACHE_STATE_MASK;
> +        if (state == CACHE_ENABLED) {
> +            state = CACHE_FROZEN;
> +            DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
> +        }
> +
> +        env->cache_control &= ~(CACHE_STATE_MASK << 2);
> +        env->cache_control |= (state << 2);
> +    }
> +}
> +
> +void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
> +{
> +    DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
> +                          addr, val, size);
> +
> +    if (size != 4) {
> +        DPRINTF_CACHE_CONTROL("32bits only\n");
> +        return;
> +    }
> +
> +    switch (addr) {
> +        case 0x00:              /* Cache control */
> +
> +            /* These values must always be read as zeros */
> +            val &= ~CACHE_CTRL_FD;
> +            val &= ~CACHE_CTRL_FI;
> +            val &= ~CACHE_CTRL_IB;
> +            val &= ~CACHE_CTRL_IP;
> +            val &= ~CACHE_CTRL_DP;
> +
> +            env->cache_control = val;
> +            break;
> +        case 0x04:              /* Instruction cache configuration */
> +        case 0x08:              /* Data cache configuration */
> +            /* Read Only */
> +            break;
> +        default:
> +            DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
> +            break;
> +    };
> +}
> +
> +uint64_t leon3_cache_control_ld(target_ulong addr, int size)
> +{
> +    uint64_t ret = 0;
> +
> +    if (size != 4) {
> +        DPRINTF_CACHE_CONTROL("32bits only\n");
> +        return 0;
> +    }
> +
> +    switch (addr) {
> +        case 0x00:              /* Cache control */
> +            ret = env->cache_control;
> +            break;
> +
> +            /* Configuration registers are read and only always keep those
> +               predefined values */
> +
> +        case 0x04:              /* Instruction cache configuration */
> +            ret = 0x10220000;
> +            break;
> +        case 0x08:              /* Data cache configuration */
> +            ret = 0x18220000;
> +            break;
> +        default:
> +            DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
> +            break;
> +    };
> +    DPRINTF_CACHE_CONTROL("st addr:%08x, ret:%" PRIx64 ", size:%d\n",
> +                          addr, ret, size);
> +    return ret;
> +}
> diff --git a/target-sparc/translate.c b/target-sparc/translate.c
> index 23f9519..b0e8044 100644
> --- a/target-sparc/translate.c
> +++ b/target-sparc/translate.c
> @@ -1997,8 +1997,9 @@ static void disas_sparc_insn(DisasContext * dc)
>                     } else
>                         tcg_gen_mov_tl(cpu_dst, cpu_src1);
>                 }
> +
>                 cond = GET_FIELD(insn, 3, 6);
> -                if (cond == 0x8) {
> +                if (cond == 0x8) { /* Trap Always */
>                     save_state(dc, cpu_cond);
>                     if ((dc->def->features & CPU_FEATURE_HYPV) &&
>                         supervisor(dc))
> @@ -2007,7 +2008,16 @@ static void disas_sparc_insn(DisasContext * dc)
>                         tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
>                     tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
>                     tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
> -                    gen_helper_raise_exception(cpu_tmp32);
> +
> +                    if (rs2 == 0
> +                          &&

Please merge with the next or previous line.

> +                        dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
> +
> +                        gen_helper_shutdown();
> +
> +                    } else {
> +                        gen_helper_raise_exception(cpu_tmp32);
> +                    }
>                 } else if (cond != 0) {
>                     TCGv r_cond = tcg_temp_new();
>                     int l1;
> --
> 1.7.1
>
>
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP as defined in GRLIB IP Core User's Manual.
  2011-01-03 14:07   ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Fabien Chouteau
  2011-01-03 14:07     ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART " Fabien Chouteau
@ 2011-01-04 19:02     ` Blue Swirl
  1 sibling, 0 replies; 18+ messages in thread
From: Blue Swirl @ 2011-01-04 19:02 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  hw/grlib_irqmp.c |  402 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 402 insertions(+), 0 deletions(-)
>
> diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
> new file mode 100644
> index 0000000..9f947d1
> --- /dev/null
> +++ b/hw/grlib_irqmp.c
> @@ -0,0 +1,402 @@
> +/*
> + * QEMU GRLIB IRQMP Emulator
> + *
> + * (Multiprocessor and extended interrupt not supported)
> + *
> + * Copyright (c) 2010-2011 AdaCore
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "sysbus.h"
> +#include "cpu.h"
> +
> +#include "grlib.h"
> +
> +//#define DEBUG_IRQ
> +
> +#ifdef DEBUG_IRQ
> +#define DPRINTF(fmt, ...)                                       \
> +    do { printf("IRQMP: " fmt , ## __VA_ARGS__); } while (0)
> +#else
> +#define DPRINTF(fmt, ...)
> +#endif
> +
> +#define IRQMP_MAX_CPU 16
> +#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
> +
> +/* Memory mapped register offsets */
> +#define LEVEL_OFFSET     0x00
> +#define PENDING_OFFSET   0x04
> +#define FORCE0_OFFSET    0x08
> +#define CLEAR_OFFSET     0x0C
> +#define MP_STATUS_OFFSET 0x10
> +#define BROADCAST_OFFSET 0x14
> +#define MASK_OFFSET      0x40
> +#define FORCE_OFFSET     0x80
> +#define EXTENDED_OFFSET  0xC0
> +
> +typedef struct IRQMPState IRQMPState;
> +
> +typedef struct IRQMP
> +{
> +    SysBusDevice busdev;
> +
> +    CPUSPARCState *env;

No.

> +
> +    IRQMPState *state;
> +} IRQMP;
> +
> +struct IRQMPState
> +{
> +    uint32_t level;
> +    uint32_t pending;
> +    uint32_t clear;
> +    uint32_t broadcast;
> +
> +    uint32_t mask[IRQMP_MAX_CPU];
> +    uint32_t force[IRQMP_MAX_CPU];
> +    uint32_t extended[IRQMP_MAX_CPU];
> +
> +    IRQMP    *parent;
> +};
> +
> +static void grlib_irqmp_check_irqs(IRQMPState *state)
> +{
> +    assert(state != NULL);
> +    CPUState *env   = state->parent->env;
> +    assert(env != NULL);
> +
> +    uint32_t pend   = 0;
> +    uint32_t level0 = 0;
> +    uint32_t level1 = 0;
> +
> +
> +    /* IRQ for CPU 0 (no SMP support) */
> +    pend = (state->pending | state->force[0])
> +        & state->mask[0];
> +
> +
> +    level0 = pend & ~state->level;
> +    level1 = pend &  state->level;
> +
> +    DPRINTF("pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x\n",
> +            state->pending, state->force[0],
> +            state->mask[0], level1, level0);
> +
> +    /* Trigger level1 interrupt first and level0 if there is no level1 */
> +    if (level1 != 0) {
> +        env->pil_in = level1;
> +    } else {
> +        env->pil_in = level0;
> +    }
> +
> +    if (env->pil_in && (env->interrupt_index == 0 ||
> +                        (env->interrupt_index & ~15) == TT_EXTINT)) {
> +        unsigned int i;
> +
> +        for (i = 15; i > 0; i--) {
> +            if (env->pil_in & (1 << i)) {
> +                int old_interrupt = env->interrupt_index;
> +
> +                env->interrupt_index = TT_EXTINT | i;
> +                if (old_interrupt != env->interrupt_index) {
> +                    DPRINTF("Set CPU IRQ %d\n", i);
> +                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
> +                }
> +                break;
> +            }
> +        }
> +    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
> +        DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15);
> +        env->interrupt_index = 0;
> +        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
> +    }
> +}
> +
> +void grlib_irqmp_ack(DeviceState *dev, int intno)
> +{
> +    assert(dev != NULL);
> +
> +    SysBusDevice *sdev = sysbus_from_qdev(dev);
> +    assert(sdev != NULL);
> +
> +    IRQMP *irqmp = FROM_SYSBUS(typeof (*irqmp), sdev);
> +    assert(irqmp != NULL);
> +
> +    IRQMPState *state = irqmp->state;
> +    assert(state != NULL);
> +
> +    uint32_t mask;
> +
> +    intno &= 15;
> +    mask = 1 << intno;
> +
> +    DPRINTF("grlib_irqmp_ack %d\n", intno);
> +
> +    /* Clear registers */
> +    state->pending  &= ~mask;
> +    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
> +
> +    grlib_irqmp_check_irqs(state);
> +}
> +
> +void grlib_irqmp_set_irq(void *opaque, int irq, int level)
> +{
> +    assert(opaque != NULL);
> +
> +    IRQMP *irqmp = FROM_SYSBUS(typeof (*irqmp), sysbus_from_qdev(opaque));
> +    assert(irqmp != NULL);
> +
> +    IRQMPState *s = irqmp->state;
> +    assert(s         != NULL);
> +    assert(s->parent != NULL);
> +
> +    int i = 0;

Don't mix variable declarations with code (asserts).

> +
> +
> +    if (level) {
> +        DPRINTF("Raise CPU IRQ %d\n", irq);
> +
> +        if (s->broadcast & 1 << irq) {
> +            /* Broadcasted IRQ */
> +            for (i = 0; i < IRQMP_MAX_CPU; i++) {
> +                s->force[i] |= 1 << irq;
> +            }
> +        } else {
> +            s->pending |= 1 << irq;
> +        }
> +        grlib_irqmp_check_irqs(s);
> +
> +    }
> +}
> +
> +static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    IRQMP *irqmp = opaque;
> +    assert(irqmp != NULL);
> +
> +    IRQMPState *state = irqmp->state;
> +    assert(state != NULL);
> +
> +    addr &= 0xff;

Useless.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components.
  2011-01-03 14:07       ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Fabien Chouteau
  2011-01-03 14:07         ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Fabien Chouteau
@ 2011-01-04 19:04         ` Blue Swirl
  1 sibling, 0 replies; 18+ messages in thread
From: Blue Swirl @ 2011-01-04 19:04 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
>
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
> ---
>  hw/grlib.h |  121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 121 insertions(+), 0 deletions(-)
>
> diff --git a/hw/grlib.h b/hw/grlib.h
> new file mode 100644
> index 0000000..bb3c01e
> --- /dev/null
> +++ b/hw/grlib.h
> @@ -0,0 +1,121 @@
> +/*
> + * QEMU GRLIB Components
> + *
> + * Copyright (c) 2010-2011 AdaCore
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef _GRLIB_H_
> +#define _GRLIB_H_
> +
> +#include "qdev.h"
> +#include "sysbus.h"
> +
> +/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
> + * http://www.gaisler.com/products/grlib/grip.pdf
> + */
> +
> +/* IRQMP */
> +
> +void grlib_irqmp_set_irq(void *opaque, int irq, int level);
> +
> +void grlib_irqmp_ack(DeviceState *dev, int intno);
> +
> +static inline
> +DeviceState *grlib_irqmp_create(target_phys_addr_t   base,
> +                                CPUState            *env,
> +                                qemu_irq           **cpu_irqs,
> +                                uint32_t             nr_irqs)
> +{
> +    DeviceState *dev;
> +
> +    assert(cpu_irqs != NULL);
> +
> +    dev = qdev_create(NULL, "grlib,irqmp");
> +    qdev_prop_set_ptr(dev, "cpustate", env);
> +
> +    if (qdev_init(dev)) {
> +        return NULL;
> +    }
> +
> +    env->irq_manager = dev;
> +
> +    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
> +
> +    *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
> +                                   dev,
> +                                   nr_irqs);
> +
> +    return dev;
> +}
> +
> +/* GPTimer */
> +
> +static inline
> +DeviceState *grlib_gptimer_create(target_phys_addr_t  base,
> +                                  uint32_t            nr_timers,
> +                                  uint32_t            freq,
> +                                  qemu_irq           *cpu_irqs,
> +                                  int                 base_irq)
> +{
> +    DeviceState *dev;
> +    int i;
> +
> +    dev = qdev_create(NULL, "grlib,gptimer");
> +    qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
> +    qdev_prop_set_uint32(dev, "frequency", freq);
> +    qdev_prop_set_uint32(dev, "irq-line", base_irq);
> +
> +    if (qdev_init(dev)) {
> +        return NULL;
> +    }
> +
> +    sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
> +
> +    for (i = 0; i < nr_timers; i++)

Missing braces.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3
  2011-01-03 14:06 [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3 Fabien Chouteau
  2011-01-03 14:07 ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual Fabien Chouteau
@ 2011-01-04 21:02 ` Andreas Färber
  1 sibling, 0 replies; 18+ messages in thread
From: Andreas Färber @ 2011-01-04 21:02 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

Hi Fabien,

Am 03.01.2011 um 15:06 schrieb Fabien Chouteau:

> New version of the Leon3 emulation. Many modifications since v1,  
> mostly to
> follow the Qemu architecture and to implement features in a more  
> generic way.
>
> Again, please feel free to comment.

Informally, if you look through the commits, we roughly follow the  
GNOME guidelines [1]:

* The subject line does not end with a dot.
* All six patches could be prefixed with a "sparc" tag as  
categorization for people who don't know Leon3 or GRLIB.
* Usually an empty commit body indicates that some explanation is  
missing. (guilty there myself, I admit...)
* I'd put the "as described in ..." info into a sentence in the body  
of the commit message to shorten the subject.

You might want to split up patch 4 to go alongside 1-3, so that  
GPTimer is accompanied by the link to the GRLIB docs.

Regards,
Andreas

[1] http://live.gnome.org/Git/CommitMessages

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual.
  2011-01-04 18:46   ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer " Blue Swirl
@ 2011-01-17 11:43     ` Fabien Chouteau
  2011-01-17 19:45       ` Blue Swirl
  0 siblings, 1 reply; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-17 11:43 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On 01/04/2011 07:46 PM, Blue Swirl wrote:
> On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau<chouteau@adacore.com>  wrote:+}
>> +static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
>> +{
>> +    GPTimerUnit *unit  = opaque;
>> +    uint32_t     value = 0;
>> +
>> +    addr&= 0xff;
>
> Not needed.
>

When io-memory starts at 0x8000300 and its size is 48 bytes, Qemu gives me
address like this one (for example):

0x320

But only the last two bytes of the address are significant, that's why I use
this bit-mask.

Maybe I do not initialize io-memory in a proper way...

-- 
Fabien Chouteau

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3.
  2011-01-04 18:56           ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Blue Swirl
@ 2011-01-17 16:01             ` Fabien Chouteau
  2011-01-17 19:55               ` Blue Swirl
  0 siblings, 1 reply; 18+ messages in thread
From: Fabien Chouteau @ 2011-01-17 16:01 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On 01/04/2011 07:56 PM, Blue Swirl wrote:
> On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau<chouteau@adacore.com>  wrote:
>> diff --git a/hw/leon3.c b/hw/leon3.c
>> new file mode 100644
>> index 0000000..d5fe863
>> --- /dev/null
>> +++ b/hw/leon3.c
>> @@ -0,0 +1,202 @@
>> +/*
>> + * QEMU Leon3 System Emulator
>> + *
>> + * Copyright (c) 2010-2011 AdaCore
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +#include "hw.h"
>> +#include "qemu-timer.h"
>> +#include "qemu-char.h"
>> +#include "sysemu.h"
>> +#include "boards.h"
>> +#include "loader.h"
>> +#include "elf.h"
>> +
>> +#include "grlib.h"
>> +
>> +//#define DEBUG_LEON3
>> +
>> +#ifdef DEBUG_LEON3
>> +#define DPRINTF(fmt, ...)                                       \
>> +    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF(fmt, ...)
>> +#endif
>> +
>> +/* Default system clock.  */
>> +#define CPU_CLK (40 * 1000 * 1000)
>> +
>> +#define PROM_FILENAME        "u-boot.bin"
>> +
>> +#define MAX_PILS 16
>> +
>> +typedef struct ResetData {
>> +    CPUState *env;
>> +    uint64_t  entry;            /* save kernel entry in case of reset */
>
> uint32_t should be enough.
>
>> +} ResetData;
>> +
>> +static void main_cpu_reset(void *opaque)
>> +{
>> +    ResetData *s = (ResetData *)opaque;
>> +    assert(s != NULL);
>> +    CPUState *env = s->env;
>> +    assert(env != NULL);
>
> These asserts won't ever trigger.
>
>> +
>> +    cpu_reset(env);
>> +
>> +    env->halted = 0;
>> +    env->pc     = s->entry;
>> +    env->npc    = s->entry + 4;
>> +}
>> +
>> +static void leon3_irq_ack(void *irq_manager, int intno)
>> +{
>> +    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
>> +    leon3_cache_control_int();
>> +}
>> +
>> +static void leon3_generic_hw_init(ram_addr_t  ram_size,
>> +                                  const char *boot_device,
>> +                                  const char *kernel_filename,
>> +                                  const char *kernel_cmdline,
>> +                                  const char *initrd_filename,
>> +                                  const char *cpu_model)
>> +{
>> +    CPUState   *env;
>> +    ram_addr_t  ram_offset, prom_offset;
>> +    int         ret;
>> +    char       *filename;
>> +    qemu_irq   *cpu_irqs = NULL;
>> +    int         bios_size;
>> +    int         prom_size;
>> +    int         aligned_bios_size;
>> +    ResetData  *reset_info;
>> +
>> +    /* Init CPU */
>> +    if (!cpu_model) {
>> +        cpu_model = "LEON3";
>> +    }
>> +
>> +    env = cpu_init(cpu_model);
>> +    if (!env) {
>> +        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
>> +        exit(1);
>> +    }
>> +
>> +    cpu_sparc_set_id(env, 0);
>> +
>> +    /* Reset data */
>> +    reset_info        = qemu_mallocz(sizeof(ResetData));
>> +    reset_info->env   = env;
>> +    qemu_register_reset(main_cpu_reset, reset_info);
>> +
>> +    /* Allocate IRQ manager */
>> +    grlib_irqmp_create(0x80000200, env,&cpu_irqs, MAX_PILS);
>> +
>> +    env->qemu_irq_ack = leon3_irq_ack;
>> +
>> +    /* Allocate RAM */
>> +    if ((uint64_t)ram_size>  (1UL<<  30)) {
>> +        fprintf(stderr,
>> +                "qemu: Too much memory for this machine: %d, maximum 1G\n",
>> +                (unsigned int)(ram_size / (1024 * 1024)));
>> +        exit(1);
>> +    }
>> +
>> +    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
>> +    cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
>> +
>> +    /* Allocate BIOS */
>> +    prom_size = 8 * 1024 * 1024; /* 8Mb */
>> +    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
>> +    cpu_register_physical_memory(0x00000000, prom_size,
>> +                                 prom_offset | IO_MEM_ROM);
>> +
>> +    /* Load boot prom */
>> +    if (bios_name == NULL) {
>> +        bios_name = PROM_FILENAME;
>> +    }
>> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>> +
>> +    bios_size = get_image_size(filename);
>> +
>> +    if (bios_size>  prom_size) {
>> +        fprintf(stderr, "qemu: could not load prom '%s': file too big \n",
>> +                filename);
>> +        exit(1);
>> +    }
>> +
>> +    if (bios_size>  0) {
>> +        aligned_bios_size =
>> +            (bios_size + TARGET_PAGE_SIZE - 1)&  TARGET_PAGE_MASK;
>> +
>> +        ret = load_image_targphys(filename, 0x00000000, bios_size);
>> +        if (ret<  0 || ret>  prom_size) {
>> +            fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
>> +            exit(1);
>> +        }
>> +    }
>> +    else if (kernel_filename == NULL) {
>> +        fprintf(stderr,"Can't read bios image %s\n", filename);
>> +        exit(1);
>> +    }
>> +
>> +    /* Can directly load an application. */
>> +    if (kernel_filename != NULL) {
>> +        long     kernel_size;
>> +        uint64_t entry;
>
> uint32_t
>

load_elf expects an uint32_t.

>> +
>> +        kernel_size = load_elf(kernel_filename, NULL, NULL,&entry, NULL, NULL,
>> +                               1 /* big endian */, ELF_MACHINE, 0);
>> +        if (kernel_size<  0) {
>> +            fprintf(stderr, "qemu: could not load kernel '%s'\n",
>> +                    kernel_filename);
>> +            exit(1);
>> +        }
>> +        if (bios_size<= 0) {
>> +            /* If there is no bios/monitor, start the application.  */
>> +            env->pc = entry;
>> +            env->npc = entry + 4;
>> +            reset_info->entry = entry;
>> +        }
>> +    }
>> +
>> +    /* Allocate timers */
>> +    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
>> +
>> +    /* Allocate uart */
>> +    if (serial_hds[0]) {
>> +        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
>> +    }
>> +}
>> +
>> +QEMUMachine leon3_generic_machine = {
>> +    .name     = "leon3_generic",
>> +    .desc     = "Leon-3 generic",
>> +    .init     = leon3_generic_hw_init,
>> +    .use_scsi = 0,
>> +};
>> +
>> +static void leon3_machine_init(void)
>> +{
>> +    qemu_register_machine(&leon3_generic_machine);
>> +}
>> +
>> +machine_init(leon3_machine_init);
>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>> index 7e0d17c..7795be4 100644
>> --- a/target-sparc/cpu.h
>> +++ b/target-sparc/cpu.h
>> @@ -251,20 +251,21 @@ typedef struct sparc_def_t {
>>      uint32_t maxtl;
>>   } sparc_def_t;
>>
>> -#define CPU_FEATURE_FLOAT    (1<<  0)
>> -#define CPU_FEATURE_FLOAT128 (1<<  1)
>> -#define CPU_FEATURE_SWAP     (1<<  2)
>> -#define CPU_FEATURE_MUL      (1<<  3)
>> -#define CPU_FEATURE_DIV      (1<<  4)
>> -#define CPU_FEATURE_FLUSH    (1<<  5)
>> -#define CPU_FEATURE_FSQRT    (1<<  6)
>> -#define CPU_FEATURE_FMUL     (1<<  7)
>> -#define CPU_FEATURE_VIS1     (1<<  8)
>> -#define CPU_FEATURE_VIS2     (1<<  9)
>> -#define CPU_FEATURE_FSMULD   (1<<  10)
>> -#define CPU_FEATURE_HYPV     (1<<  11)
>> -#define CPU_FEATURE_CMT      (1<<  12)
>> -#define CPU_FEATURE_GL       (1<<  13)
>> +#define CPU_FEATURE_FLOAT        (1<<  0)
>> +#define CPU_FEATURE_FLOAT128     (1<<  1)
>> +#define CPU_FEATURE_SWAP         (1<<  2)
>> +#define CPU_FEATURE_MUL          (1<<  3)
>> +#define CPU_FEATURE_DIV          (1<<  4)
>> +#define CPU_FEATURE_FLUSH        (1<<  5)
>> +#define CPU_FEATURE_FSQRT        (1<<  6)
>> +#define CPU_FEATURE_FMUL         (1<<  7)
>> +#define CPU_FEATURE_VIS1         (1<<  8)
>> +#define CPU_FEATURE_VIS2         (1<<  9)
>> +#define CPU_FEATURE_FSMULD       (1<<  10)
>> +#define CPU_FEATURE_HYPV         (1<<  11)
>> +#define CPU_FEATURE_CMT          (1<<  12)
>> +#define CPU_FEATURE_GL           (1<<  13)
>> +#define CPU_FEATURE_TA0_SHUTDOWN (1<<  14) /* Shutdown on "ta 0x0" */
>>   #ifndef TARGET_SPARC64
>>   #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>>                                CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
>> @@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
>>   #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
>>   #endif
>>      sparc_def_t *def;
>> +
>> +    void *irq_manager;
>> +    void (*qemu_irq_ack) (void *irq_manager, int intno);
>> +
>> +    /* Leon3 cache control */
>> +    uint32_t cache_control;
>>   } CPUSPARCState;
>>
>>   #ifndef NO_CPU_IO_DEFS
>> @@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
>>   int cpu_cwp_dec(CPUState *env1, int cwp);
>>   void cpu_set_cwp(CPUState *env1, int new_cwp);
>>
>> +void     leon3_cache_control_st(target_ulong addr, uint64_t val, int size);
>> +uint64_t leon3_cache_control_ld(target_ulong addr, int size);
>> +void     leon3_cache_control_int(void);
>
> Is there any need to export these?
>

The last one needs to be exported, the others can be forward declaration 
in op_helper.c.

>> +
>>   /* sun4m.c, sun4u.c */
>>   void cpu_check_irqs(CPUSPARCState *env);
>>
>> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
>> index e84c312..49bdb58 100644
>> --- a/target-sparc/helper.c
>> +++ b/target-sparc/helper.c
>> @@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
>>      env->pc = 0;
>>      env->npc = env->pc + 4;
>>   #endif
>> +    env->cache_control = 0;
>>   }
>>
>>   static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
>> @@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
>>          .mmu_sfsr_mask = 0xffffffff,
>>          .mmu_trcr_mask = 0xffffffff,
>>          .nwindows = 8,
>> -        .features = CPU_DEFAULT_FEATURES,
>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>      },
>>      {
>>          .name = "LEON3",
>>          .iu_version = 0xf3000000,
>>          .fpu_version = 4<<  17, /* FPU version 4 (Meiko) */
>>          .mmu_version = 0xf3000000,
>> -        .mmu_bm = 0x00004000,
>> +        .mmu_bm = 0x00000000,
>>          .mmu_ctpr_mask = 0x007ffff0,
>>          .mmu_cxr_mask = 0x0000003f,
>>          .mmu_sfsr_mask = 0xffffffff,
>>          .mmu_trcr_mask = 0xffffffff,
>>          .nwindows = 8,
>> -        .features = CPU_DEFAULT_FEATURES,
>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>      },
>>   #endif
>>   };
>> diff --git a/target-sparc/helper.h b/target-sparc/helper.h
>> index 6f103e7..004eaaa 100644
>> --- a/target-sparc/helper.h
>> +++ b/target-sparc/helper.h
>> @@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
>>   DEF_HELPER_0(fcmpeq_fcc3, void)
>>   #endif
>>   DEF_HELPER_1(raise_exception, void, int)
>> +DEF_HELPER_0(shutdown, void)
>>   #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
>>   #define F_HELPER_DQ_0_0(name)                   \
>>      F_HELPER_0_0(name ## d);                    \
>> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
>> index be3c1e0..0390aec 100644
>> --- a/target-sparc/op_helper.c
>> +++ b/target-sparc/op_helper.c
>> @@ -1,6 +1,7 @@
>>   #include "exec.h"
>>   #include "host-utils.h"
>>   #include "helper.h"
>> +#include "sysemu.h"
>>
>>   //#define DEBUG_MMU
>>   //#define DEBUG_MXCC
>> @@ -9,6 +10,7 @@
>>   //#define DEBUG_ASI
>>   //#define DEBUG_PCALL
>>   //#define DEBUG_PSTATE
>> +//#define DEBUG_CACHE_CONTROL
>>
>>   #ifdef DEBUG_MMU
>>   #define DPRINTF_MMU(fmt, ...)                                   \
>> @@ -36,6 +38,13 @@
>>   #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
>>   #endif
>>
>> +#ifdef DEBUG_CACHE_CONTROL
>> +#define DPRINTF_CACHE_CONTROL(fmt, ...)                                   \
>> +    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
>> +#else
>> +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
>> +#endif
>> +
>>   #ifdef TARGET_SPARC64
>>   #ifndef TARGET_ABI32
>>   #define AM_CHECK(env1) ((env1)->pstate&  PS_AM)
>> @@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
>>      raise_exception(tt);
>>   }
>>
>> +void helper_shutdown(void)
>> +{
>> +    qemu_system_shutdown_request();
>> +}
>> +
>>   void helper_check_align(target_ulong addr, uint32_t align)
>>   {
>>      if (addr&  align) {
>> @@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
>>
>>      helper_check_align(addr, size - 1);
>>      switch (asi) {
>> -    case 2: /* SuperSparc MXCC registers */
>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>          switch (addr) {
>> +        case 0x00:          /* Leon3 Cache Control */
>> +        case 0x08:          /* Leon3 Instruction Cache config */
>> +        case 0x0C:          /* Leon3 Date Cache config */
>> +            ret = leon3_cache_control_ld(addr, size);
>> +            break;
>>          case 0x01c00a00: /* MXCC control register */
>>              if (size == 8)
>>                  ret = env->mxccregs[3];
>> @@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
>>   {
>>      helper_check_align(addr, size - 1);
>>      switch(asi) {
>> -    case 2: /* SuperSparc MXCC registers */
>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>          switch (addr) {
>> +        case 0x00:          /* Leon3 Cache Control */
>> +        case 0x08:          /* Leon3 Instruction Cache config */
>> +        case 0x0C:          /* Leon3 Date Cache config */
>> +            leon3_cache_control_st(addr, val, size);
>> +            break;
>> +
>>          case 0x01c00000: /* MXCC stream data register 0 */
>>              if (size == 8)
>>                  env->mxccdata[0] = val;
>> @@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
>>      env->pc = env->tbr;
>>      env->npc = env->pc + 4;
>>      env->exception_index = -1;
>> +
>> +#if !defined(CONFIG_USER_ONLY)
>> +    /* IRQ acknowledgment */
>> +    if ((intno&  ~15) == TT_EXTINT&&  env->qemu_irq_ack != NULL) {
>> +        env->qemu_irq_ack(env->irq_manager, intno);
>> +    }
>> +#endif
>>   }
>>   #endif
>>
>> @@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t limit)
>>   #endif
>>   }
>>   #endif
>> +
>> +/* Leon3 cache control */
>> +
>> +/* Cache control: emulate the behavior of cache control registers but without
>> +   any effect on the emulated CPU */
>> +
>> +#define CACHE_STATE_MASK 0x3
>> +#define CACHE_DISABLED   0x0
>> +#define CACHE_FROZEN     0x1
>> +#define CACHE_ENABLED    0x3
>> +
>> +/* Cache Control register fields */
>> +
>> +#define CACHE_CTRL_IF (1<<    4)  /* Instruction Cache Freeze on Interrupt */
>> +#define CACHE_CTRL_DF (1<<    5)  /* Data Cache Freeze on Interrupt */
>> +#define CACHE_CTRL_DP (1<<  14)  /* Data cache flush pending */
>> +#define CACHE_CTRL_IP (1<<  15)  /* Instruction cache flush pending */
>> +#define CACHE_CTRL_IB (1<<  16)  /* Instruction burst fetch */
>> +#define CACHE_CTRL_FI (1<<  21)  /* Flush Instruction cache (Write only) */
>> +#define CACHE_CTRL_FD (1<<  22)  /* Flush Data cache (Write only) */
>> +#define CACHE_CTRL_DS (1<<  23)  /* Data cache snoop enable */
>
> These should be at the top of the file.
>

I just want to put all the cache control code together, it's easier to read.

-- 
Fabien Chouteau

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual.
  2011-01-17 11:43     ` Fabien Chouteau
@ 2011-01-17 19:45       ` Blue Swirl
  0 siblings, 0 replies; 18+ messages in thread
From: Blue Swirl @ 2011-01-17 19:45 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 17, 2011 at 11:43 AM, Fabien Chouteau <chouteau@adacore.com> wrote:
> On 01/04/2011 07:46 PM, Blue Swirl wrote:
>>
>> On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau<chouteau@adacore.com>
>>  wrote:+}
>>>
>>> +static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t
>>> addr)
>>> +{
>>> +    GPTimerUnit *unit  = opaque;
>>> +    uint32_t     value = 0;
>>> +
>>> +    addr&= 0xff;
>>
>> Not needed.
>>
>
> When io-memory starts at 0x8000300 and its size is 48 bytes, Qemu gives me
> address like this one (for example):
>
> 0x320

Sorry, I was confused. This part is OK (except for the spacing).

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3.
  2011-01-17 16:01             ` Fabien Chouteau
@ 2011-01-17 19:55               ` Blue Swirl
  0 siblings, 0 replies; 18+ messages in thread
From: Blue Swirl @ 2011-01-17 19:55 UTC (permalink / raw)
  To: Fabien Chouteau; +Cc: qemu-devel

On Mon, Jan 17, 2011 at 4:01 PM, Fabien Chouteau <chouteau@adacore.com> wrote:
> On 01/04/2011 07:56 PM, Blue Swirl wrote:
>>
>> On Mon, Jan 3, 2011 at 2:07 PM, Fabien Chouteau<chouteau@adacore.com>
>>  wrote:
>>>
>>> diff --git a/hw/leon3.c b/hw/leon3.c
>>> new file mode 100644
>>> index 0000000..d5fe863
>>> --- /dev/null
>>> +++ b/hw/leon3.c
>>> @@ -0,0 +1,202 @@
>>> +/*
>>> + * QEMU Leon3 System Emulator
>>> + *
>>> + * Copyright (c) 2010-2011 AdaCore
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>> a copy
>>> + * of this software and associated documentation files (the "Software"),
>>> to deal
>>> + * in the Software without restriction, including without limitation the
>>> rights
>>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or
>>> sell
>>> + * copies of the Software, and to permit persons to whom the Software is
>>> + * furnished to do so, subject to the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice shall be
>>> included in
>>> + * all copies or substantial portions of the Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>> EXPRESS OR
>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>> MERCHANTABILITY,
>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>>> SHALL
>>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>>> OTHER
>>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>>> ARISING FROM,
>>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>>> DEALINGS IN
>>> + * THE SOFTWARE.
>>> + */
>>> +#include "hw.h"
>>> +#include "qemu-timer.h"
>>> +#include "qemu-char.h"
>>> +#include "sysemu.h"
>>> +#include "boards.h"
>>> +#include "loader.h"
>>> +#include "elf.h"
>>> +
>>> +#include "grlib.h"
>>> +
>>> +//#define DEBUG_LEON3
>>> +
>>> +#ifdef DEBUG_LEON3
>>> +#define DPRINTF(fmt, ...)                                       \
>>> +    do { printf("Leon3: " fmt , ## __VA_ARGS__); } while (0)
>>> +#else
>>> +#define DPRINTF(fmt, ...)
>>> +#endif
>>> +
>>> +/* Default system clock.  */
>>> +#define CPU_CLK (40 * 1000 * 1000)
>>> +
>>> +#define PROM_FILENAME        "u-boot.bin"
>>> +
>>> +#define MAX_PILS 16
>>> +
>>> +typedef struct ResetData {
>>> +    CPUState *env;
>>> +    uint64_t  entry;            /* save kernel entry in case of reset */
>>
>> uint32_t should be enough.
>>
>>> +} ResetData;
>>> +
>>> +static void main_cpu_reset(void *opaque)
>>> +{
>>> +    ResetData *s = (ResetData *)opaque;
>>> +    assert(s != NULL);
>>> +    CPUState *env = s->env;
>>> +    assert(env != NULL);
>>
>> These asserts won't ever trigger.
>>
>>> +
>>> +    cpu_reset(env);
>>> +
>>> +    env->halted = 0;
>>> +    env->pc     = s->entry;
>>> +    env->npc    = s->entry + 4;
>>> +}
>>> +
>>> +static void leon3_irq_ack(void *irq_manager, int intno)
>>> +{
>>> +    grlib_irqmp_ack((DeviceState *)irq_manager, intno);
>>> +    leon3_cache_control_int();
>>> +}
>>> +
>>> +static void leon3_generic_hw_init(ram_addr_t  ram_size,
>>> +                                  const char *boot_device,
>>> +                                  const char *kernel_filename,
>>> +                                  const char *kernel_cmdline,
>>> +                                  const char *initrd_filename,
>>> +                                  const char *cpu_model)
>>> +{
>>> +    CPUState   *env;
>>> +    ram_addr_t  ram_offset, prom_offset;
>>> +    int         ret;
>>> +    char       *filename;
>>> +    qemu_irq   *cpu_irqs = NULL;
>>> +    int         bios_size;
>>> +    int         prom_size;
>>> +    int         aligned_bios_size;
>>> +    ResetData  *reset_info;
>>> +
>>> +    /* Init CPU */
>>> +    if (!cpu_model) {
>>> +        cpu_model = "LEON3";
>>> +    }
>>> +
>>> +    env = cpu_init(cpu_model);
>>> +    if (!env) {
>>> +        fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
>>> +        exit(1);
>>> +    }
>>> +
>>> +    cpu_sparc_set_id(env, 0);
>>> +
>>> +    /* Reset data */
>>> +    reset_info        = qemu_mallocz(sizeof(ResetData));
>>> +    reset_info->env   = env;
>>> +    qemu_register_reset(main_cpu_reset, reset_info);
>>> +
>>> +    /* Allocate IRQ manager */
>>> +    grlib_irqmp_create(0x80000200, env,&cpu_irqs, MAX_PILS);
>>> +
>>> +    env->qemu_irq_ack = leon3_irq_ack;
>>> +
>>> +    /* Allocate RAM */
>>> +    if ((uint64_t)ram_size>  (1UL<<  30)) {
>>> +        fprintf(stderr,
>>> +                "qemu: Too much memory for this machine: %d, maximum
>>> 1G\n",
>>> +                (unsigned int)(ram_size / (1024 * 1024)));
>>> +        exit(1);
>>> +    }
>>> +
>>> +    ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
>>> +    cpu_register_physical_memory(0x40000000, ram_size, ram_offset |
>>> IO_MEM_RAM);
>>> +
>>> +    /* Allocate BIOS */
>>> +    prom_size = 8 * 1024 * 1024; /* 8Mb */
>>> +    prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
>>> +    cpu_register_physical_memory(0x00000000, prom_size,
>>> +                                 prom_offset | IO_MEM_ROM);
>>> +
>>> +    /* Load boot prom */
>>> +    if (bios_name == NULL) {
>>> +        bios_name = PROM_FILENAME;
>>> +    }
>>> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>> +
>>> +    bios_size = get_image_size(filename);
>>> +
>>> +    if (bios_size>  prom_size) {
>>> +        fprintf(stderr, "qemu: could not load prom '%s': file too big
>>> \n",
>>> +                filename);
>>> +        exit(1);
>>> +    }
>>> +
>>> +    if (bios_size>  0) {
>>> +        aligned_bios_size =
>>> +            (bios_size + TARGET_PAGE_SIZE - 1)&  TARGET_PAGE_MASK;
>>> +
>>> +        ret = load_image_targphys(filename, 0x00000000, bios_size);
>>> +        if (ret<  0 || ret>  prom_size) {
>>> +            fprintf(stderr, "qemu: could not load prom '%s'\n",
>>> filename);
>>> +            exit(1);
>>> +        }
>>> +    }
>>> +    else if (kernel_filename == NULL) {
>>> +        fprintf(stderr,"Can't read bios image %s\n", filename);
>>> +        exit(1);
>>> +    }
>>> +
>>> +    /* Can directly load an application. */
>>> +    if (kernel_filename != NULL) {
>>> +        long     kernel_size;
>>> +        uint64_t entry;
>>
>> uint32_t
>>
>
> load_elf expects an uint32_t.

I think you mean uint64_t. It's OK then.

>>> +
>>> +        kernel_size = load_elf(kernel_filename, NULL, NULL,&entry, NULL,
>>> NULL,
>>> +                               1 /* big endian */, ELF_MACHINE, 0);
>>> +        if (kernel_size<  0) {
>>> +            fprintf(stderr, "qemu: could not load kernel '%s'\n",
>>> +                    kernel_filename);
>>> +            exit(1);
>>> +        }
>>> +        if (bios_size<= 0) {
>>> +            /* If there is no bios/monitor, start the application.  */
>>> +            env->pc = entry;
>>> +            env->npc = entry + 4;
>>> +            reset_info->entry = entry;
>>> +        }
>>> +    }
>>> +
>>> +    /* Allocate timers */
>>> +    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
>>> +
>>> +    /* Allocate uart */
>>> +    if (serial_hds[0]) {
>>> +        grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
>>> +    }
>>> +}
>>> +
>>> +QEMUMachine leon3_generic_machine = {
>>> +    .name     = "leon3_generic",
>>> +    .desc     = "Leon-3 generic",
>>> +    .init     = leon3_generic_hw_init,
>>> +    .use_scsi = 0,
>>> +};
>>> +
>>> +static void leon3_machine_init(void)
>>> +{
>>> +    qemu_register_machine(&leon3_generic_machine);
>>> +}
>>> +
>>> +machine_init(leon3_machine_init);
>>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>>> index 7e0d17c..7795be4 100644
>>> --- a/target-sparc/cpu.h
>>> +++ b/target-sparc/cpu.h
>>> @@ -251,20 +251,21 @@ typedef struct sparc_def_t {
>>>     uint32_t maxtl;
>>>  } sparc_def_t;
>>>
>>> -#define CPU_FEATURE_FLOAT    (1<<  0)
>>> -#define CPU_FEATURE_FLOAT128 (1<<  1)
>>> -#define CPU_FEATURE_SWAP     (1<<  2)
>>> -#define CPU_FEATURE_MUL      (1<<  3)
>>> -#define CPU_FEATURE_DIV      (1<<  4)
>>> -#define CPU_FEATURE_FLUSH    (1<<  5)
>>> -#define CPU_FEATURE_FSQRT    (1<<  6)
>>> -#define CPU_FEATURE_FMUL     (1<<  7)
>>> -#define CPU_FEATURE_VIS1     (1<<  8)
>>> -#define CPU_FEATURE_VIS2     (1<<  9)
>>> -#define CPU_FEATURE_FSMULD   (1<<  10)
>>> -#define CPU_FEATURE_HYPV     (1<<  11)
>>> -#define CPU_FEATURE_CMT      (1<<  12)
>>> -#define CPU_FEATURE_GL       (1<<  13)
>>> +#define CPU_FEATURE_FLOAT        (1<<  0)
>>> +#define CPU_FEATURE_FLOAT128     (1<<  1)
>>> +#define CPU_FEATURE_SWAP         (1<<  2)
>>> +#define CPU_FEATURE_MUL          (1<<  3)
>>> +#define CPU_FEATURE_DIV          (1<<  4)
>>> +#define CPU_FEATURE_FLUSH        (1<<  5)
>>> +#define CPU_FEATURE_FSQRT        (1<<  6)
>>> +#define CPU_FEATURE_FMUL         (1<<  7)
>>> +#define CPU_FEATURE_VIS1         (1<<  8)
>>> +#define CPU_FEATURE_VIS2         (1<<  9)
>>> +#define CPU_FEATURE_FSMULD       (1<<  10)
>>> +#define CPU_FEATURE_HYPV         (1<<  11)
>>> +#define CPU_FEATURE_CMT          (1<<  12)
>>> +#define CPU_FEATURE_GL           (1<<  13)
>>> +#define CPU_FEATURE_TA0_SHUTDOWN (1<<  14) /* Shutdown on "ta 0x0" */
>>>  #ifndef TARGET_SPARC64
>>>  #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
>>>                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
>>> @@ -436,6 +437,12 @@ typedef struct CPUSPARCState {
>>>  #define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
>>>  #endif
>>>     sparc_def_t *def;
>>> +
>>> +    void *irq_manager;
>>> +    void (*qemu_irq_ack) (void *irq_manager, int intno);
>>> +
>>> +    /* Leon3 cache control */
>>> +    uint32_t cache_control;
>>>  } CPUSPARCState;
>>>
>>>  #ifndef NO_CPU_IO_DEFS
>>> @@ -471,6 +478,10 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
>>>  int cpu_cwp_dec(CPUState *env1, int cwp);
>>>  void cpu_set_cwp(CPUState *env1, int new_cwp);
>>>
>>> +void     leon3_cache_control_st(target_ulong addr, uint64_t val, int
>>> size);
>>> +uint64_t leon3_cache_control_ld(target_ulong addr, int size);
>>> +void     leon3_cache_control_int(void);
>>
>> Is there any need to export these?
>>
>
> The last one needs to be exported, the others can be forward declaration in
> op_helper.c.

Could you rearrange the code so that no forward declarations are needed?

>>> +
>>>  /* sun4m.c, sun4u.c */
>>>  void cpu_check_irqs(CPUSPARCState *env);
>>>
>>> diff --git a/target-sparc/helper.c b/target-sparc/helper.c
>>> index e84c312..49bdb58 100644
>>> --- a/target-sparc/helper.c
>>> +++ b/target-sparc/helper.c
>>> @@ -784,6 +784,7 @@ void cpu_reset(CPUSPARCState *env)
>>>     env->pc = 0;
>>>     env->npc = env->pc + 4;
>>>  #endif
>>> +    env->cache_control = 0;
>>>  }
>>>
>>>  static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
>>> @@ -1288,20 +1289,20 @@ static const sparc_def_t sparc_defs[] = {
>>>         .mmu_sfsr_mask = 0xffffffff,
>>>         .mmu_trcr_mask = 0xffffffff,
>>>         .nwindows = 8,
>>> -        .features = CPU_DEFAULT_FEATURES,
>>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>>     },
>>>     {
>>>         .name = "LEON3",
>>>         .iu_version = 0xf3000000,
>>>         .fpu_version = 4<<  17, /* FPU version 4 (Meiko) */
>>>         .mmu_version = 0xf3000000,
>>> -        .mmu_bm = 0x00004000,
>>> +        .mmu_bm = 0x00000000,
>>>         .mmu_ctpr_mask = 0x007ffff0,
>>>         .mmu_cxr_mask = 0x0000003f,
>>>         .mmu_sfsr_mask = 0xffffffff,
>>>         .mmu_trcr_mask = 0xffffffff,
>>>         .nwindows = 8,
>>> -        .features = CPU_DEFAULT_FEATURES,
>>> +        .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
>>>     },
>>>  #endif
>>>  };
>>> diff --git a/target-sparc/helper.h b/target-sparc/helper.h
>>> index 6f103e7..004eaaa 100644
>>> --- a/target-sparc/helper.h
>>> +++ b/target-sparc/helper.h
>>> @@ -83,6 +83,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
>>>  DEF_HELPER_0(fcmpeq_fcc3, void)
>>>  #endif
>>>  DEF_HELPER_1(raise_exception, void, int)
>>> +DEF_HELPER_0(shutdown, void)
>>>  #define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
>>>  #define F_HELPER_DQ_0_0(name)                   \
>>>     F_HELPER_0_0(name ## d);                    \
>>> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
>>> index be3c1e0..0390aec 100644
>>> --- a/target-sparc/op_helper.c
>>> +++ b/target-sparc/op_helper.c
>>> @@ -1,6 +1,7 @@
>>>  #include "exec.h"
>>>  #include "host-utils.h"
>>>  #include "helper.h"
>>> +#include "sysemu.h"
>>>
>>>  //#define DEBUG_MMU
>>>  //#define DEBUG_MXCC
>>> @@ -9,6 +10,7 @@
>>>  //#define DEBUG_ASI
>>>  //#define DEBUG_PCALL
>>>  //#define DEBUG_PSTATE
>>> +//#define DEBUG_CACHE_CONTROL
>>>
>>>  #ifdef DEBUG_MMU
>>>  #define DPRINTF_MMU(fmt, ...)                                   \
>>> @@ -36,6 +38,13 @@
>>>  #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
>>>  #endif
>>>
>>> +#ifdef DEBUG_CACHE_CONTROL
>>> +#define DPRINTF_CACHE_CONTROL(fmt, ...)
>>>   \
>>> +    do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
>>> +#else
>>> +#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
>>> +#endif
>>> +
>>>  #ifdef TARGET_SPARC64
>>>  #ifndef TARGET_ABI32
>>>  #define AM_CHECK(env1) ((env1)->pstate&  PS_AM)
>>> @@ -294,6 +303,11 @@ void HELPER(raise_exception)(int tt)
>>>     raise_exception(tt);
>>>  }
>>>
>>> +void helper_shutdown(void)
>>> +{
>>> +    qemu_system_shutdown_request();
>>> +}
>>> +
>>>  void helper_check_align(target_ulong addr, uint32_t align)
>>>  {
>>>     if (addr&  align) {
>>> @@ -1609,8 +1623,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi,
>>> int size, int sign)
>>>
>>>     helper_check_align(addr, size - 1);
>>>     switch (asi) {
>>> -    case 2: /* SuperSparc MXCC registers */
>>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>>         switch (addr) {
>>> +        case 0x00:          /* Leon3 Cache Control */
>>> +        case 0x08:          /* Leon3 Instruction Cache config */
>>> +        case 0x0C:          /* Leon3 Date Cache config */
>>> +            ret = leon3_cache_control_ld(addr, size);
>>> +            break;
>>>         case 0x01c00a00: /* MXCC control register */
>>>             if (size == 8)
>>>                 ret = env->mxccregs[3];
>>> @@ -1838,8 +1857,14 @@ void helper_st_asi(target_ulong addr, uint64_t
>>> val, int asi, int size)
>>>  {
>>>     helper_check_align(addr, size - 1);
>>>     switch(asi) {
>>> -    case 2: /* SuperSparc MXCC registers */
>>> +    case 2: /* SuperSparc MXCC registers and Leon3 cache control */
>>>         switch (addr) {
>>> +        case 0x00:          /* Leon3 Cache Control */
>>> +        case 0x08:          /* Leon3 Instruction Cache config */
>>> +        case 0x0C:          /* Leon3 Date Cache config */
>>> +            leon3_cache_control_st(addr, val, size);
>>> +            break;
>>> +
>>>         case 0x01c00000: /* MXCC stream data register 0 */
>>>             if (size == 8)
>>>                 env->mxccdata[0] = val;
>>> @@ -4135,6 +4160,13 @@ void do_interrupt(CPUState *env)
>>>     env->pc = env->tbr;
>>>     env->npc = env->pc + 4;
>>>     env->exception_index = -1;
>>> +
>>> +#if !defined(CONFIG_USER_ONLY)
>>> +    /* IRQ acknowledgment */
>>> +    if ((intno&  ~15) == TT_EXTINT&&  env->qemu_irq_ack != NULL) {
>>> +        env->qemu_irq_ack(env->irq_manager, intno);
>>> +    }
>>> +#endif
>>>  }
>>>  #endif
>>>
>>> @@ -4329,3 +4361,118 @@ void helper_tick_set_limit(void *opaque, uint64_t
>>> limit)
>>>  #endif
>>>  }
>>>  #endif
>>> +
>>> +/* Leon3 cache control */
>>> +
>>> +/* Cache control: emulate the behavior of cache control registers but
>>> without
>>> +   any effect on the emulated CPU */
>>> +
>>> +#define CACHE_STATE_MASK 0x3
>>> +#define CACHE_DISABLED   0x0
>>> +#define CACHE_FROZEN     0x1
>>> +#define CACHE_ENABLED    0x3
>>> +
>>> +/* Cache Control register fields */
>>> +
>>> +#define CACHE_CTRL_IF (1<<    4)  /* Instruction Cache Freeze on
>>> Interrupt */
>>> +#define CACHE_CTRL_DF (1<<    5)  /* Data Cache Freeze on Interrupt */
>>> +#define CACHE_CTRL_DP (1<<  14)  /* Data cache flush pending */
>>> +#define CACHE_CTRL_IP (1<<  15)  /* Instruction cache flush pending */
>>> +#define CACHE_CTRL_IB (1<<  16)  /* Instruction burst fetch */
>>> +#define CACHE_CTRL_FI (1<<  21)  /* Flush Instruction cache (Write only)
>>> */
>>> +#define CACHE_CTRL_FD (1<<  22)  /* Flush Data cache (Write only) */
>>> +#define CACHE_CTRL_DS (1<<  23)  /* Data cache snoop enable */
>>
>> These should be at the top of the file.
>>
>
> I just want to put all the cache control code together, it's easier to read.

The actual numerical values are not helpful for understanding the
code. The comments may be, though that may be a sign that the names
could be more self-explanatory.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2011-01-17 19:57 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-03 14:06 [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3 Fabien Chouteau
2011-01-03 14:07 ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer as defined in GRLIB IP Core User's Manual Fabien Chouteau
2011-01-03 14:07   ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Fabien Chouteau
2011-01-03 14:07     ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART " Fabien Chouteau
2011-01-03 14:07       ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Fabien Chouteau
2011-01-03 14:07         ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Fabien Chouteau
2011-01-03 14:07           ` [Qemu-devel] [PATCH v2 6/6] SPARCV8 asr17 register support Fabien Chouteau
2011-01-04 18:31             ` Blue Swirl
2011-01-04 18:56           ` [Qemu-devel] [PATCH v2 5/6] Emulation of Leon3 Blue Swirl
2011-01-17 16:01             ` Fabien Chouteau
2011-01-17 19:55               ` Blue Swirl
2011-01-04 19:04         ` [Qemu-devel] [PATCH v2 4/6] Header file for the GRLIB components Blue Swirl
2011-01-04 18:38       ` [Qemu-devel] [PATCH v2 3/6] Emulation of GRLIB APB UART as defined in GRLIB IP Core User's Manual Blue Swirl
2011-01-04 19:02     ` [Qemu-devel] [PATCH v2 2/6] Emulation of GRLIB IRQMP " Blue Swirl
2011-01-04 18:46   ` [Qemu-devel] [PATCH v2 1/6] Emulation of GRLIB GPTimer " Blue Swirl
2011-01-17 11:43     ` Fabien Chouteau
2011-01-17 19:45       ` Blue Swirl
2011-01-04 21:02 ` [Qemu-devel] [PATCH v2 0/6] [RFC] New SPARC machine: Leon3 Andreas Färber

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.