Skip to content

Fixes for RX architecture #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 44 additions & 53 deletions hw/timer/renesas_cmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,69 +51,52 @@ REG16(CMCR, 0)
REG16(CMCNT, 2)
REG16(CMCOR, 4)

static void update_events(RCMTState *cmt, int ch)
{
int64_t next_time;
static uint16_t read_cmcnt(RCMTState *cmt, int ch) {
if (!(cmt->cmstr & (1 << ch))) {
return cmt->cmcnt[ch];
}
int64_t elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - cmt->tick[ch];
uint64_t ticks = (elapsed_ns * cmt->cmt_freq[ch]) / (NANOSECONDS_PER_SECOND);
uint32_t limit = cmt->cmcor[ch] + 1;
return (cmt->cmcnt[ch] + ticks) % limit;
}

if ((cmt->cmstr & (1 << ch)) == 0) {
/* count disable, so not happened next event. */
static void update_events(RCMTState *cmt, int ch) {
if (!(cmt->cmstr & (1 << ch))) {
return;
}
next_time = cmt->cmcor[ch] - cmt->cmcnt[ch];
next_time *= NANOSECONDS_PER_SECOND;
next_time /= cmt->input_freq;
/*
* CKS -> div rate
* 0 -> 8 (1 << 3)
* 1 -> 32 (1 << 5)
* 2 -> 128 (1 << 7)
* 3 -> 512 (1 << 9)
*/
next_time *= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
timer_mod(&cmt->timer[ch], next_time);
}
uint16_t current = read_cmcnt(cmt, ch);
uint32_t remain = (cmt->cmcor[ch] + 1) - current;
if (remain == 0) {
remain = cmt->cmcor[ch] + 1;
}
int64_t next_time = (int64_t)remain * NANOSECONDS_PER_SECOND / cmt->cmt_freq[ch];

static int64_t read_cmcnt(RCMTState *cmt, int ch)
{
int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
int64_t fire_time = now + next_time;

if (cmt->cmstr & (1 << ch)) {
delta = (now - cmt->tick[ch]);
delta /= NANOSECONDS_PER_SECOND;
delta /= cmt->input_freq;
delta /= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
cmt->tick[ch] = now;
return cmt->cmcnt[ch] + delta;
} else {
return cmt->cmcnt[ch];
if (fire_time <= now) {
fire_time = now + 1;
}

timer_mod(&cmt->timer[ch], fire_time);
}

static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
{
RCMTState *cmt = opaque;
int ch = offset / 0x08;
uint64_t ret;

if (offset == A_CMSTR) {
ret = 0;
ret = FIELD_DP16(ret, CMSTR, STR,
FIELD_EX16(cmt->cmstr, CMSTR, STR));
return ret;
return FIELD_EX16(cmt->cmstr, CMSTR, STR);
} else {
offset &= 0x07;
if (ch == 0) {
offset -= 0x02;
}
switch (offset) {
case A_CMCR:
ret = 0;
ret = FIELD_DP16(ret, CMCR, CKS,
FIELD_EX16(cmt->cmstr, CMCR, CKS));
ret = FIELD_DP16(ret, CMCR, CMIE,
FIELD_EX16(cmt->cmstr, CMCR, CMIE));
return ret;
return cmt->cmcr[ch];
case A_CMCNT:
return read_cmcnt(cmt, ch);
case A_CMCOR:
Expand All @@ -123,12 +106,13 @@ static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size)
qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " "
"not implemented\n",
offset);
return UINT64_MAX;
return UINT16_MAX;
}

static void start_stop(RCMTState *cmt, int ch, int st)
{
if (st) {
static void start_stop(RCMTState *cmt, int ch, int enable) {
if (enable) {
cmt->cmcnt[ch] = 0;
cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
update_events(cmt, ch);
} else {
timer_del(&cmt->timer[ch]);
Expand All @@ -155,9 +139,13 @@ static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
FIELD_EX16(val, CMCR, CKS));
cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE,
FIELD_EX16(val, CMCR, CMIE));
cmt->cmt_freq[ch] =
cmt->input_freq / (8u << (2 * FIELD_EX16(cmt->cmcr[ch], CMCR, CKS)));
update_events(cmt, ch);
break;
case 2:
cmt->cmcnt[ch] = val;
cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
break;
case 4:
cmt->cmcor[ch] = val;
Expand Down Expand Up @@ -216,26 +204,29 @@ static void rcmt_reset(DeviceState *dev)
{
RCMTState *cmt = RCMT(dev);
cmt->cmstr = 0;
cmt->cmcr[0] = cmt->cmcr[1] = 0;
cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
for (int i = 0; i < CMT_CH; i++) {
cmt->cmcr[i] = 0;
cmt->cmcnt[i] = 0;
cmt->cmcor[i] = 0xFFFF;
cmt->tick[i] = 0;
}
}

static void rcmt_init(Object *obj)
{
SysBusDevice *d = SYS_BUS_DEVICE(obj);
RCMTState *cmt = RCMT(obj);
int i;

memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
cmt, "renesas-cmt", 0x10);
sysbus_init_mmio(d, &cmt->memory);

for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) {
for (int i = 0; i < CMT_CH; i++) {
sysbus_init_irq(d, &cmt->cmi[i]);
cmt->cmt_freq[i] = cmt->input_freq >> 3;
timer_init_ns(&cmt->timer[i], QEMU_CLOCK_VIRTUAL,
(i == 0 ? timer_event0 : timer_event1), cmt);
}
timer_init_ns(&cmt->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, cmt);
timer_init_ns(&cmt->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, cmt);
}

static const VMStateDescription vmstate_rcmt = {
Expand Down
1 change: 1 addition & 0 deletions include/hw/timer/renesas_cmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct RCMTState {
/*< public >*/

uint64_t input_freq;
uint64_t cmt_freq[CMT_CH];
MemoryRegion memory;

uint16_t cmstr;
Expand Down
10 changes: 9 additions & 1 deletion target/rx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "hw/loader.h"
#include "fpu/softfloat.h"
#include "tcg/debug-assert.h"
#include "system/reset.h"

static void rx_cpu_set_pc(CPUState *cs, vaddr value)
{
Expand Down Expand Up @@ -129,6 +130,13 @@ static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
return oc;
}

static void rx_cpu_reset(void *opaque)
{
RXCPU *cpu = opaque;

cpu_reset(CPU(cpu));
}

static void rx_cpu_realize(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
Expand All @@ -142,7 +150,7 @@ static void rx_cpu_realize(DeviceState *dev, Error **errp)
}

qemu_init_vcpu(cs);
cpu_reset(cs);
qemu_register_reset(rx_cpu_reset, RX_CPU(cs));

rcc->parent_realize(dev, errp);
}
Expand Down
5 changes: 2 additions & 3 deletions target/rx/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ void rx_cpu_do_interrupt(CPUState *cs)
uint32_t save_psw;

env->in_sleep = 0;

if (env->psw_u) {
env->usp = env->regs[0];
} else {
env->isp = env->regs[0];
}
save_psw = rx_cpu_pack_psw(env);
env->psw_pm = env->psw_i = env->psw_u = 0;
int32_t vec = cs->exception_index;

if (do_irq) {
if (do_irq && vec < 0) {
if (do_irq & CPU_INTERRUPT_FIR) {
env->bpc = env->pc;
env->bpsw = save_psw;
Expand All @@ -79,7 +79,6 @@ void rx_cpu_do_interrupt(CPUState *cs)
"interrupt 0x%02x raised\n", env->ack_irq);
}
} else {
uint32_t vec = cs->exception_index;
const char *expname = "unknown exception";

env->isp -= 4;
Expand Down