#include "sun4m.h"
#include "qemu-timer.h"
#include "sysbus.h"
-
-//#define DEBUG_TIMER
-
-#ifdef DEBUG_TIMER
-#define DPRINTF(fmt, ...) \
- do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
+#include "trace.h"
/*
* Registers of hardware timer in sun4m.
qemu_irq irq;
ptimer_state *timer;
uint32_t count, counthigh, reached;
- uint64_t limit;
- // processor only
+ /* processor only */
uint32_t running;
+ uint64_t limit;
} CPUTimerState;
typedef struct SLAVIO_TIMERState {
SysBusDevice busdev;
uint32_t num_cpus;
- CPUTimerState cputimer[MAX_CPUS + 1];
uint32_t cputimer_mode;
+ CPUTimerState cputimer[MAX_CPUS + 1];
} SLAVIO_TIMERState;
typedef struct TimerContext {
#define TIMER_MAX_COUNT32 0x7ffffe00ULL
#define TIMER_REACHED 0x80000000
#define TIMER_PERIOD 500ULL // 500ns
-#define LIMIT_TO_PERIODS(l) ((l) >> 9)
-#define PERIODS_TO_LIMIT(l) ((l) << 9)
+#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
+#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
static int slavio_timer_is_user(TimerContext *tc)
{
} else {
limit = t->limit;
}
- if (t->timer) {
- count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
- } else {
- count = 0;
- }
- DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", t->limit, t->counthigh,
- t->count);
+ count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
+
+ trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
t->count = count & TIMER_COUNT_MASK32;
t->counthigh = count >> 32;
}
CPUTimerState *t = &s->cputimer[tc->timer_index];
slavio_timer_get_out(t);
- DPRINTF("callback: count %x%08x\n", t->counthigh, t->count);
- t->reached = TIMER_REACHED;
- if (!slavio_timer_is_user(tc)) {
+ trace_slavio_timer_irq(t->counthigh, t->count);
+ /* if limit is 0 (free-run), there will be no match */
+ if (t->limit != 0) {
+ t->reached = TIMER_REACHED;
+ }
+ /* there is no interrupt if user timer or free-run */
+ if (!slavio_timer_is_user(tc) && t->limit != 0) {
qemu_irq_raise(t->irq);
}
}
ret = s->cputimer_mode;
break;
default:
- DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr);
+ trace_slavio_timer_mem_readl_invalid(addr);
ret = 0;
break;
}
- DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
-
+ trace_slavio_timer_mem_readl(addr, ret);
return ret;
}
unsigned int timer_index = tc->timer_index;
CPUTimerState *t = &s->cputimer[timer_index];
- DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
+ trace_slavio_timer_mem_writel(addr, val);
saddr = addr >> 2;
switch (saddr) {
case TIMER_LIMIT:
t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
t->reached = 0;
count = ((uint64_t)t->counthigh << 32) | t->count;
- DPRINTF("processor %d user timer set to %016" PRIx64 "\n",
- timer_index, count);
- if (t->timer) {
- ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
- }
+ trace_slavio_timer_mem_writel_limit(timer_index, count);
+ ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
} else {
// set limit, reset counter
qemu_irq_lower(t->irq);
t->count = val & TIMER_MAX_COUNT64;
t->reached = 0;
count = ((uint64_t)t->counthigh) << 32 | t->count;
- DPRINTF("processor %d user timer set to %016" PRIx64 "\n",
- timer_index, count);
- if (t->timer) {
- ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
- }
- } else
- DPRINTF("not user timer\n");
+ trace_slavio_timer_mem_writel_limit(timer_index, count);
+ ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+ } else {
+ trace_slavio_timer_mem_writel_counter_invalid();
+ }
break;
case TIMER_COUNTER_NORST:
// set limit without resetting counter
t->limit = val & TIMER_MAX_COUNT32;
- if (t->timer) {
- if (t->limit == 0) { /* free-run */
- ptimer_set_limit(t->timer,
- LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
- } else {
- ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
- }
+ if (t->limit == 0) { /* free-run */
+ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
+ } else {
+ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
}
break;
case TIMER_STATUS:
if (slavio_timer_is_user(tc)) {
// start/stop user counter
if ((val & 1) && !t->running) {
- DPRINTF("processor %d user timer started\n",
- timer_index);
- if (t->timer) {
- ptimer_run(t->timer, 0);
- }
+ trace_slavio_timer_mem_writel_status_start(timer_index);
+ ptimer_run(t->timer, 0);
t->running = 1;
} else if (!(val & 1) && t->running) {
- DPRINTF("processor %d user timer stopped\n",
- timer_index);
- if (t->timer) {
- ptimer_stop(t->timer);
- }
+ trace_slavio_timer_mem_writel_status_stop(timer_index);
+ ptimer_stop(t->timer);
t->running = 0;
}
}
// set this processors user timer bit in config
// register
s->cputimer_mode |= processor;
- DPRINTF("processor %d changed from counter to user "
- "timer\n", timer_index);
+ trace_slavio_timer_mem_writel_mode_user(timer_index);
} else { // user timer -> counter
// stop the user timer if it is running
if (curr_timer->running) {
// clear this processors user timer bit in config
// register
s->cputimer_mode &= ~processor;
- DPRINTF("processor %d changed from user timer to "
- "counter\n", timer_index);
+ trace_slavio_timer_mem_writel_mode_counter(timer_index);
}
}
}
} else {
- DPRINTF("not system timer\n");
+ trace_slavio_timer_mem_writel_mode_invalid();
}
break;
default:
- DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
+ trace_slavio_timer_mem_writel_invalid(addr);
break;
}
}
-static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
+static CPUReadMemoryFunc * const slavio_timer_mem_read[3] = {
NULL,
NULL,
slavio_timer_mem_readl,
};
-static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
+static CPUWriteMemoryFunc * const slavio_timer_mem_write[3] = {
NULL,
NULL,
slavio_timer_mem_writel,
};
-static void slavio_timer_save(QEMUFile *f, void *opaque)
-{
- SLAVIO_TIMERState *s = opaque;
- unsigned int i;
- CPUTimerState *curr_timer;
-
- for (i = 0; i <= MAX_CPUS; i++) {
- curr_timer = &s->cputimer[i];
- qemu_put_be64s(f, &curr_timer->limit);
- qemu_put_be32s(f, &curr_timer->count);
- qemu_put_be32s(f, &curr_timer->counthigh);
- qemu_put_be32s(f, &curr_timer->reached);
- qemu_put_be32s(f, &curr_timer->running);
- if (curr_timer->timer) {
- qemu_put_ptimer(f, curr_timer->timer);
- }
+static const VMStateDescription vmstate_timer = {
+ .name ="timer",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .minimum_version_id_old = 3,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(limit, CPUTimerState),
+ VMSTATE_UINT32(count, CPUTimerState),
+ VMSTATE_UINT32(counthigh, CPUTimerState),
+ VMSTATE_UINT32(reached, CPUTimerState),
+ VMSTATE_UINT32(running, CPUTimerState),
+ VMSTATE_PTIMER(timer, CPUTimerState),
+ VMSTATE_END_OF_LIST()
}
-}
-
-static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
-{
- SLAVIO_TIMERState *s = opaque;
- unsigned int i;
- CPUTimerState *curr_timer;
-
- if (version_id != 3)
- return -EINVAL;
+};
- for (i = 0; i <= MAX_CPUS; i++) {
- curr_timer = &s->cputimer[i];
- qemu_get_be64s(f, &curr_timer->limit);
- qemu_get_be32s(f, &curr_timer->count);
- qemu_get_be32s(f, &curr_timer->counthigh);
- qemu_get_be32s(f, &curr_timer->reached);
- qemu_get_be32s(f, &curr_timer->running);
- if (curr_timer->timer) {
- qemu_get_ptimer(f, curr_timer->timer);
- }
+static const VMStateDescription vmstate_slavio_timer = {
+ .name ="slavio_timer",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .minimum_version_id_old = 3,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
+ vmstate_timer, CPUTimerState),
+ VMSTATE_END_OF_LIST()
}
+};
- return 0;
-}
-
-static void slavio_timer_reset(void *opaque)
+static void slavio_timer_reset(DeviceState *d)
{
- SLAVIO_TIMERState *s = opaque;
+ SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
unsigned int i;
CPUTimerState *curr_timer;
curr_timer->limit = 0;
curr_timer->count = 0;
curr_timer->reached = 0;
- if (i < s->num_cpus) {
+ if (i <= s->num_cpus) {
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
+ curr_timer->running = 1;
}
- curr_timer->running = 1;
}
s->cputimer_mode = 0;
}
-static void slavio_timer_init1(SysBusDevice *dev)
+static int slavio_timer_init1(SysBusDevice *dev)
{
int io;
SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
TimerContext *tc;
for (i = 0; i <= MAX_CPUS; i++) {
- tc = qemu_mallocz(sizeof(TimerContext));
+ tc = g_malloc0(sizeof(TimerContext));
tc->s = s;
tc->timer_index = i;
ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
io = cpu_register_io_memory(slavio_timer_mem_read,
- slavio_timer_mem_write, tc);
+ slavio_timer_mem_write, tc,
+ DEVICE_NATIVE_ENDIAN);
if (i == 0) {
sysbus_init_mmio(dev, SYS_TIMER_SIZE, io);
} else {
sysbus_init_irq(dev, &s->cputimer[i].irq);
}
- register_savevm("slavio_timer", -1, 3, slavio_timer_save,
- slavio_timer_load, s);
- qemu_register_reset(slavio_timer_reset, s);
- slavio_timer_reset(s);
+ return 0;
}
static SysBusDeviceInfo slavio_timer_info = {
.init = slavio_timer_init1,
.qdev.name = "slavio_timer",
.qdev.size = sizeof(SLAVIO_TIMERState),
+ .qdev.vmsd = &vmstate_slavio_timer,
+ .qdev.reset = slavio_timer_reset,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
DEFINE_PROP_END_OF_LIST(),