• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Keine Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revision970aca826c113c917a5d16cba00c0135e12cdefc (tree)
Zeit2019-06-16 22:31:41
AutorYoshinori Sato <ysato@user...>
CommiterYoshinori Sato

Log Message

hw/timer: RX62N internal timer modules

renesas_tmr: 8bit timer modules.
renesas_cmt: 16bit compare match timer modules.
This part use many renesas's CPU.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20190607091116.49044-7-ysato@users.sourceforge.jp>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Ändern Zusammenfassung

Diff

--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -61,3 +61,9 @@ config CMSDK_APB_TIMER
6161 config CMSDK_APB_DUALTIMER
6262 bool
6363 select PTIMER
64+
65+config RENESAS_TMR8
66+ bool
67+
68+config RENESAS_CMT
69+ bool
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -40,6 +40,9 @@ obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
4040
4141 obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
4242
43+obj-$(CONFIG_RENESAS_TMR8) += renesas_tmr.o
44+obj-$(CONFIG_RENESAS_CMT) += renesas_cmt.o
45+
4346 common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
4447 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
4548
--- /dev/null
+++ b/hw/timer/renesas_cmt.c
@@ -0,0 +1,275 @@
1+/*
2+ * Renesas 16bit Compare-match timer
3+ *
4+ * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
5+ * (Rev.1.40 R01UH0033EJ0140)
6+ *
7+ * Copyright (c) 2019 Yoshinori Sato
8+ *
9+ * This program is free software; you can redistribute it and/or modify it
10+ * under the terms and conditions of the GNU General Public License,
11+ * version 2 or later, as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope it will be useful, but WITHOUT
14+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16+ * more details.
17+ *
18+ * You should have received a copy of the GNU General Public License along with
19+ * this program. If not, see <http://www.gnu.org/licenses/>.
20+ */
21+
22+#include "qemu/osdep.h"
23+#include "qemu-common.h"
24+#include "qemu/log.h"
25+#include "qapi/error.h"
26+#include "qemu/timer.h"
27+#include "cpu.h"
28+#include "hw/hw.h"
29+#include "hw/sysbus.h"
30+#include "hw/registerfields.h"
31+#include "hw/timer/renesas_cmt.h"
32+#include "qemu/error-report.h"
33+
34+/*
35+ * +0 CMSTR - common control
36+ * +2 CMCR - ch0
37+ * +4 CMCNT - ch0
38+ * +6 CMCOR - ch0
39+ * +8 CMCR - ch1
40+ * +10 CMCNT - ch1
41+ * +12 CMCOR - ch1
42+ * If we think that the address of CH 0 has an offset of +2,
43+ * we can treat it with the same address as CH 1, so define it like that.
44+ */
45+REG16(CMSTR, 0)
46+ FIELD(CMSTR, STR0, 0, 1)
47+ FIELD(CMSTR, STR1, 1, 1)
48+ FIELD(CMSTR, STR, 0, 2)
49+/* This addeess is channel offset */
50+REG16(CMCR, 0)
51+ FIELD(CMCR, CKS, 0, 2)
52+ FIELD(CMCR, CMIE, 6, 1)
53+REG16(CMCNT, 2)
54+REG16(CMCOR, 4)
55+
56+static void update_events(RCMTState *cmt, int ch)
57+{
58+ int64_t next_time;
59+
60+ if ((cmt->cmstr & (1 << ch)) == 0) {
61+ /* count disable, so not happened next event. */
62+ return ;
63+ }
64+ next_time = cmt->cmcor[ch] - cmt->cmcnt[ch];
65+ next_time *= NANOSECONDS_PER_SECOND;
66+ next_time /= cmt->input_freq;
67+ /*
68+ * CKS -> div rate
69+ * 0 -> 8 (1 << 3)
70+ * 1 -> 32 (1 << 5)
71+ * 2 -> 128 (1 << 7)
72+ * 3 -> 512 (1 << 9)
73+ */
74+ next_time *= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
75+ next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
76+ timer_mod(cmt->timer[ch], next_time);
77+}
78+
79+static int64_t read_cmcnt(RCMTState *cmt, int ch)
80+{
81+ int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
82+
83+ if (cmt->cmstr & (1 << ch)) {
84+ delta = (now - cmt->tick[ch]);
85+ delta /= NANOSECONDS_PER_SECOND;
86+ delta /= cmt->input_freq;
87+ delta /= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2);
88+ cmt->tick[ch] = now;
89+ return cmt->cmcnt[ch] + delta;
90+ } else {
91+ return cmt->cmcnt[ch];
92+ }
93+}
94+
95+static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size)
96+{
97+ hwaddr offset = addr & 0x0f;
98+ RCMTState *cmt = opaque;
99+ int ch = offset / 0x08;
100+ uint64_t ret;
101+
102+ if (offset == A_CMSTR) {
103+ ret = 0;
104+ ret = FIELD_DP16(ret, CMSTR, STR,
105+ FIELD_EX16(cmt->cmstr, CMSTR, STR));
106+ return ret;
107+ } else {
108+ offset &= 0x07;
109+ if (ch == 0) {
110+ offset -= 0x02;
111+ }
112+ switch (offset) {
113+ case A_CMCR:
114+ ret = 0;
115+ ret = FIELD_DP16(ret, CMCR, CKS,
116+ FIELD_EX16(cmt->cmstr, CMCR, CKS));
117+ ret = FIELD_DP16(ret, CMCR, CMIE,
118+ FIELD_EX16(cmt->cmstr, CMCR, CMIE));
119+ return ret;
120+ case A_CMCNT:
121+ return read_cmcnt(cmt, ch);
122+ case A_CMCOR:
123+ return cmt->cmcor[ch];
124+ }
125+ }
126+ qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%"
127+ HWADDR_PRIX " not implemented\n", offset);
128+ return UINT64_MAX;
129+}
130+
131+static void start_stop(RCMTState *cmt, int ch, int st)
132+{
133+ if (st) {
134+ update_events(cmt, ch);
135+ } else {
136+ timer_del(cmt->timer[ch]);
137+ }
138+}
139+
140+static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
141+{
142+ hwaddr offset = addr & 0x0f;
143+ RCMTState *cmt = opaque;
144+ int ch = offset / 0x08;
145+
146+ if (offset == A_CMSTR) {
147+ cmt->cmstr = FIELD_EX16(val, CMSTR, STR);
148+ start_stop(cmt, 0, FIELD_EX16(cmt->cmstr, CMSTR, STR0));
149+ start_stop(cmt, 1, FIELD_EX16(cmt->cmstr, CMSTR, STR1));
150+ } else {
151+ offset &= 0x07;
152+ if (ch == 0) {
153+ offset -= 0x02;
154+ }
155+ switch (offset) {
156+ case A_CMCR:
157+ cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CKS,
158+ FIELD_EX16(val, CMCR, CKS));
159+ cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE,
160+ FIELD_EX16(val, CMCR, CMIE));
161+ break;
162+ case 2:
163+ cmt->cmcnt[ch] = val;
164+ break;
165+ case 4:
166+ cmt->cmcor[ch] = val;
167+ break;
168+ default:
169+ qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register -0x%" HWADDR_PRIX
170+ " not implemented\n", offset);
171+ return;
172+ }
173+ if (FIELD_EX16(cmt->cmstr, CMSTR, STR) & (1 << ch)) {
174+ update_events(cmt, ch);
175+ }
176+ }
177+}
178+
179+static const MemoryRegionOps cmt_ops = {
180+ .write = cmt_write,
181+ .read = cmt_read,
182+ .endianness = DEVICE_NATIVE_ENDIAN,
183+ .impl = {
184+ .min_access_size = 2,
185+ .max_access_size = 2,
186+ },
187+};
188+
189+static void timer_events(RCMTState *cmt, int ch)
190+{
191+ cmt->cmcnt[ch] = 0;
192+ cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
193+ update_events(cmt, ch);
194+ if (FIELD_EX16(cmt->cmcr[ch], CMCR, CMIE)) {
195+ qemu_irq_pulse(cmt->cmi[ch]);
196+ }
197+}
198+
199+static void timer_event0(void *opaque)
200+{
201+ RCMTState *cmt = opaque;
202+
203+ timer_events(cmt, 0);
204+}
205+
206+static void timer_event1(void *opaque)
207+{
208+ RCMTState *cmt = opaque;
209+
210+ timer_events(cmt, 1);
211+}
212+
213+static void rcmt_reset(DeviceState *dev)
214+{
215+ RCMTState *cmt = RCMT(dev);
216+ cmt->cmstr = 0;
217+ cmt->cmcr[0] = cmt->cmcr[1] = 0;
218+ cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
219+ cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
220+}
221+
222+static void rcmt_init(Object *obj)
223+{
224+ SysBusDevice *d = SYS_BUS_DEVICE(obj);
225+ RCMTState *cmt = RCMT(obj);
226+ int i;
227+
228+ memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
229+ cmt, "renesas-cmt", 0x10);
230+ sysbus_init_mmio(d, &cmt->memory);
231+
232+ for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) {
233+ sysbus_init_irq(d, &cmt->cmi[i]);
234+ }
235+ cmt->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, cmt);
236+ cmt->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, cmt);
237+}
238+
239+static const VMStateDescription vmstate_rcmt = {
240+ .name = "rx-cmt",
241+ .version_id = 1,
242+ .minimum_version_id = 1,
243+ .fields = (VMStateField[]) {
244+ VMSTATE_END_OF_LIST()
245+ }
246+};
247+
248+static Property rcmt_properties[] = {
249+ DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0),
250+ DEFINE_PROP_END_OF_LIST(),
251+};
252+
253+static void rcmt_class_init(ObjectClass *klass, void *data)
254+{
255+ DeviceClass *dc = DEVICE_CLASS(klass);
256+
257+ dc->props = rcmt_properties;
258+ dc->vmsd = &vmstate_rcmt;
259+ dc->reset = rcmt_reset;
260+}
261+
262+static const TypeInfo rcmt_info = {
263+ .name = TYPE_RENESAS_CMT,
264+ .parent = TYPE_SYS_BUS_DEVICE,
265+ .instance_size = sizeof(RCMTState),
266+ .instance_init = rcmt_init,
267+ .class_init = rcmt_class_init,
268+};
269+
270+static void rcmt_register_types(void)
271+{
272+ type_register_static(&rcmt_info);
273+}
274+
275+type_init(rcmt_register_types)
--- /dev/null
+++ b/hw/timer/renesas_tmr.c
@@ -0,0 +1,455 @@
1+/*
2+ * Renesas 8bit timer
3+ *
4+ * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
5+ * (Rev.1.40 R01UH0033EJ0140)
6+ *
7+ * Copyright (c) 2019 Yoshinori Sato
8+ *
9+ * This program is free software; you can redistribute it and/or modify it
10+ * under the terms and conditions of the GNU General Public License,
11+ * version 2 or later, as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope it will be useful, but WITHOUT
14+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16+ * more details.
17+ *
18+ * You should have received a copy of the GNU General Public License along with
19+ * this program. If not, see <http://www.gnu.org/licenses/>.
20+ */
21+
22+#include "qemu/osdep.h"
23+#include "qemu-common.h"
24+#include "qemu/log.h"
25+#include "qapi/error.h"
26+#include "qemu/timer.h"
27+#include "qemu/bitops.h"
28+#include "cpu.h"
29+#include "hw/hw.h"
30+#include "hw/sysbus.h"
31+#include "hw/registerfields.h"
32+#include "hw/timer/renesas_tmr.h"
33+#include "qemu/error-report.h"
34+
35+REG8(TCR, 0)
36+ FIELD(TCR, CCLR, 3, 2)
37+ FIELD(TCR, OVIE, 5, 1)
38+ FIELD(TCR, CMIEA, 6, 1)
39+ FIELD(TCR, CMIEB, 7, 1)
40+REG8(TCSR, 2)
41+ FIELD(TCSR, OSA, 0, 2)
42+ FIELD(TCSR, OSB, 2, 2)
43+ FIELD(TCSR, ADTE, 4, 2)
44+REG8(TCORA, 4)
45+REG8(TCORB, 6)
46+REG8(TCNT, 8)
47+REG8(TCCR, 10)
48+ FIELD(TCCR, CKS, 0, 3)
49+ FIELD(TCCR, CSS, 3, 2)
50+ FIELD(TCCR, TMRIS, 7, 1)
51+
52+#define INTERNAL 0x01
53+#define CASCADING 0x03
54+#define CCLR_A 0x01
55+#define CCLR_B 0x02
56+
57+static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192};
58+
59+#define concat_reg(reg) ((reg[0] << 8) | reg[1])
60+static void update_events(RTMRState *tmr, int ch)
61+{
62+ uint16_t diff[TMR_NR_EVENTS], min;
63+ int64_t next_time;
64+ int i, event;
65+
66+ if (tmr->tccr[ch] == 0) {
67+ return ;
68+ }
69+ if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) {
70+ /* external clock mode */
71+ /* event not happened */
72+ return ;
73+ }
74+ if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CASCADING) {
75+ /* cascading mode */
76+ if (ch == 1) {
77+ tmr->next[ch] = none;
78+ return ;
79+ }
80+ diff[cmia] = concat_reg(tmr->tcora) - concat_reg(tmr->tcnt);
81+ diff[cmib] = concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt);
82+ diff[ovi] = 0x10000 - concat_reg(tmr->tcnt);
83+ } else {
84+ /* separate mode */
85+ diff[cmia] = tmr->tcora[ch] - tmr->tcnt[ch];
86+ diff[cmib] = tmr->tcorb[ch] - tmr->tcnt[ch];
87+ diff[ovi] = 0x100 - tmr->tcnt[ch];
88+ }
89+ /* Search for the most recently occurring event. */
90+ for (event = 0, min = diff[0], i = 1; i < none; i++) {
91+ if (min > diff[i]) {
92+ event = i;
93+ min = diff[i];
94+ }
95+ }
96+ tmr->next[ch] = event;
97+ next_time = diff[event];
98+ next_time *= clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)];
99+ next_time *= NANOSECONDS_PER_SECOND;
100+ next_time /= tmr->input_freq;
101+ next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
102+ timer_mod(tmr->timer[ch], next_time);
103+}
104+
105+
106+static inline int elapsed_time(RTMRState *tmr, int ch, int64_t delta)
107+{
108+ int divrate = clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)];
109+ int et;
110+
111+ tmr->div_round[ch] += delta;
112+ if (divrate > 0) {
113+ et = tmr->div_round[ch] / divrate;
114+ tmr->div_round[ch] %= divrate;
115+ } else {
116+ /* disble clock. so no update */
117+ et = 0;
118+ }
119+ return et;
120+}
121+static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch)
122+{
123+ int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
124+ int elapsed, ovf = 0;
125+ uint16_t tcnt[2];
126+ uint32_t ret;
127+
128+ delta = (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq;
129+ if (delta > 0) {
130+ tmr->tick = now;
131+
132+ if (FIELD_EX8(tmr->tccr[1], TCCR, CSS) == INTERNAL) {
133+ /* timer1 count update */
134+ elapsed = elapsed_time(tmr, 1, delta);
135+ if (elapsed >= 0x100) {
136+ ovf = elapsed >> 8;
137+ }
138+ tcnt[1] = tmr->tcnt[1] + (elapsed & 0xff);
139+ }
140+ switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) {
141+ case INTERNAL:
142+ elapsed = elapsed_time(tmr, 0, delta);
143+ tcnt[0] = tmr->tcnt[0] + elapsed;
144+ break;
145+ case CASCADING:
146+ if (ovf > 0) {
147+ tcnt[0] = tmr->tcnt[0] + ovf;
148+ }
149+ break;
150+ }
151+ } else {
152+ tcnt[0] = tmr->tcnt[0];
153+ tcnt[1] = tmr->tcnt[1];
154+ }
155+ if (size == 1) {
156+ return tcnt[ch];
157+ } else {
158+ ret = 0;
159+ ret = deposit32(ret, 0, 8, tcnt[1]);
160+ ret = deposit32(ret, 8, 8, tcnt[0]);
161+ return ret;
162+ }
163+}
164+
165+static inline uint8_t read_tccr(uint8_t r)
166+{
167+ uint8_t tccr = 0;
168+ tccr = FIELD_DP8(tccr, TCCR, TMRIS,
169+ FIELD_EX8(r, TCCR, TMRIS));
170+ tccr = FIELD_DP8(tccr, TCCR, CSS,
171+ FIELD_EX8(r, TCCR, CSS));
172+ tccr = FIELD_DP8(tccr, TCCR, CKS,
173+ FIELD_EX8(r, TCCR, CKS));
174+ return tccr;
175+}
176+
177+static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size)
178+{
179+ RTMRState *tmr = opaque;
180+ int ch = addr & 1;
181+ uint64_t ret;
182+
183+ if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) {
184+ qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%"
185+ HWADDR_PRIX "\n", addr);
186+ return UINT64_MAX;
187+ }
188+ switch (addr & 0x0e) {
189+ case A_TCR:
190+ ret = 0;
191+ ret = FIELD_DP8(ret, TCR, CCLR,
192+ FIELD_EX8(tmr->tcr[ch], TCR, CCLR));
193+ ret = FIELD_DP8(ret, TCR, OVIE,
194+ FIELD_EX8(tmr->tcr[ch], TCR, OVIE));
195+ ret = FIELD_DP8(ret, TCR, CMIEA,
196+ FIELD_EX8(tmr->tcr[ch], TCR, CMIEA));
197+ ret = FIELD_DP8(ret, TCR, CMIEB,
198+ FIELD_EX8(tmr->tcr[ch], TCR, CMIEB));
199+ return ret;
200+ case A_TCSR:
201+ ret = 0;
202+ ret = FIELD_DP8(ret, TCSR, OSA,
203+ FIELD_EX8(tmr->tcsr[ch], TCSR, OSA));
204+ ret = FIELD_DP8(ret, TCSR, OSB,
205+ FIELD_EX8(tmr->tcsr[ch], TCSR, OSB));
206+ switch (ch) {
207+ case 0:
208+ ret = FIELD_DP8(ret, TCSR, ADTE,
209+ FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE));
210+ break;
211+ case 1: /* CH1 ADTE unimplement always 1 */
212+ ret = FIELD_DP8(ret, TCSR, ADTE, 1);
213+ break;
214+ }
215+ return ret;
216+ case A_TCORA:
217+ if (size == 1) {
218+ return tmr->tcora[ch];
219+ } else if (ch == 0) {
220+ return concat_reg(tmr->tcora);
221+ }
222+ case A_TCORB:
223+ if (size == 1) {
224+ return tmr->tcorb[ch];
225+ } else {
226+ return concat_reg(tmr->tcorb);
227+ }
228+ case A_TCNT:
229+ return read_tcnt(tmr, size, ch);
230+ case A_TCCR:
231+ if (size == 1) {
232+ return read_tccr(tmr->tccr[ch]);
233+ } else {
234+ return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]);
235+ }
236+ default:
237+ qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX
238+ " not implemented\n", addr);
239+ break;
240+ }
241+ return UINT64_MAX;
242+}
243+
244+#define COUNT_WRITE(reg, val) \
245+ do { \
246+ if (size == 1) { \
247+ tmr->reg[ch] = val; \
248+ update_events(tmr, ch); \
249+ } else { \
250+ tmr->reg[0] = extract32(val, 8, 8); \
251+ tmr->reg[1] = extract32(val, 0, 8); \
252+ update_events(tmr, 0); \
253+ update_events(tmr, 1); \
254+ } \
255+ } while (0)
256+
257+static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
258+{
259+ RTMRState *tmr = opaque;
260+ int ch = addr & 1;
261+
262+ if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) {
263+ qemu_log_mask(LOG_GUEST_ERROR,
264+ "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX
265+ "\n", addr);
266+ return;
267+ }
268+ switch (addr & 0x0e) {
269+ case A_TCR:
270+ tmr->tcr[ch] = val;
271+ break;
272+ case A_TCSR:
273+ tmr->tcsr[ch] = val;
274+ break;
275+ case A_TCORA:
276+ COUNT_WRITE(tcora, val);
277+ break;
278+ case A_TCORB:
279+ COUNT_WRITE(tcorb, val);
280+ break;
281+ case A_TCNT:
282+ COUNT_WRITE(tcnt, val);
283+ break;
284+ case A_TCCR:
285+ COUNT_WRITE(tccr, val);
286+ break;
287+ default:
288+ qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX
289+ " not implemented\n", addr);
290+ break;
291+ }
292+}
293+
294+static const MemoryRegionOps tmr_ops = {
295+ .write = tmr_write,
296+ .read = tmr_read,
297+ .endianness = DEVICE_LITTLE_ENDIAN,
298+ .impl = {
299+ .min_access_size = 1,
300+ .max_access_size = 2,
301+ },
302+};
303+
304+static void timer_events(RTMRState *tmr, int ch);
305+
306+static uint16_t issue_event(RTMRState *tmr, int ch, int sz,
307+ uint16_t tcnt, uint16_t tcora, uint16_t tcorb)
308+{
309+ uint16_t ret = tcnt;
310+
311+ switch (tmr->next[ch]) {
312+ case none:
313+ break;
314+ case cmia:
315+ if (tcnt >= tcora) {
316+ if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_A) {
317+ ret = tcnt - tcora;
318+ }
319+ if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) {
320+ qemu_irq_pulse(tmr->cmia[ch]);
321+ }
322+ if (sz == 8 && ch == 0 &&
323+ FIELD_EX8(tmr->tccr[1], TCCR, CSS) == CASCADING) {
324+ tmr->tcnt[1]++;
325+ timer_events(tmr, 1);
326+ }
327+ }
328+ break;
329+ case cmib:
330+ if (tcnt >= tcorb) {
331+ if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_B) {
332+ ret = tcnt - tcorb;
333+ }
334+ if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) {
335+ qemu_irq_pulse(tmr->cmib[ch]);
336+ }
337+ }
338+ break;
339+ case ovi:
340+ if ((tcnt >= (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) {
341+ qemu_irq_pulse(tmr->ovi[ch]);
342+ }
343+ break;
344+ default:
345+ g_assert_not_reached();
346+ }
347+ return ret;
348+}
349+
350+static void timer_events(RTMRState *tmr, int ch)
351+{
352+ uint16_t tcnt;
353+ tmr->tcnt[ch] = read_tcnt(tmr, 1, ch);
354+ if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) != CASCADING) {
355+ tmr->tcnt[ch] = issue_event(tmr, ch, 8,
356+ tmr->tcnt[ch],
357+ tmr->tcora[ch], tmr->tcorb[ch]) & 0xff;
358+ } else {
359+ if (ch == 1) {
360+ return ;
361+ }
362+ tcnt = issue_event(tmr, ch, 16,
363+ concat_reg(tmr->tcnt),
364+ concat_reg(tmr->tcora),
365+ concat_reg(tmr->tcorb));
366+ tmr->tcnt[0] = (tcnt >> 8) & 0xff;
367+ tmr->tcnt[1] = tcnt & 0xff;
368+ }
369+ update_events(tmr, ch);
370+}
371+
372+static void timer_event0(void *opaque)
373+{
374+ RTMRState *tmr = opaque;
375+
376+ timer_events(tmr, 0);
377+}
378+
379+static void timer_event1(void *opaque)
380+{
381+ RTMRState *tmr = opaque;
382+
383+ timer_events(tmr, 1);
384+}
385+
386+static void rtmr_reset(DeviceState *dev)
387+{
388+ RTMRState *tmr = RTMR(dev);
389+ tmr->tcr[0] = tmr->tcr[1] = 0x00;
390+ tmr->tcsr[0] = 0x00;
391+ tmr->tcsr[1] = 0x10;
392+ tmr->tcnt[0] = tmr->tcnt[1] = 0x00;
393+ tmr->tcora[0] = tmr->tcora[1] = 0xff;
394+ tmr->tcorb[0] = tmr->tcorb[1] = 0xff;
395+ tmr->tccr[0] = tmr->tccr[1] = 0x00;
396+ tmr->next[0] = tmr->next[1] = none;
397+ tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
398+}
399+
400+static void rtmr_init(Object *obj)
401+{
402+ SysBusDevice *d = SYS_BUS_DEVICE(obj);
403+ RTMRState *tmr = RTMR(obj);
404+ int i;
405+
406+ memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops,
407+ tmr, "renesas-tmr", 0x10);
408+ sysbus_init_mmio(d, &tmr->memory);
409+
410+ for (i = 0; i < ARRAY_SIZE(tmr->ovi); i++) {
411+ sysbus_init_irq(d, &tmr->cmia[i]);
412+ sysbus_init_irq(d, &tmr->cmib[i]);
413+ sysbus_init_irq(d, &tmr->ovi[i]);
414+ }
415+ tmr->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, tmr);
416+ tmr->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, tmr);
417+}
418+
419+static const VMStateDescription vmstate_rtmr = {
420+ .name = "rx-tmr",
421+ .version_id = 1,
422+ .minimum_version_id = 1,
423+ .fields = (VMStateField[]) {
424+ VMSTATE_END_OF_LIST()
425+ }
426+};
427+
428+static Property rtmr_properties[] = {
429+ DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0),
430+ DEFINE_PROP_END_OF_LIST(),
431+};
432+
433+static void rtmr_class_init(ObjectClass *klass, void *data)
434+{
435+ DeviceClass *dc = DEVICE_CLASS(klass);
436+
437+ dc->props = rtmr_properties;
438+ dc->vmsd = &vmstate_rtmr;
439+ dc->reset = rtmr_reset;
440+}
441+
442+static const TypeInfo rtmr_info = {
443+ .name = TYPE_RENESAS_TMR,
444+ .parent = TYPE_SYS_BUS_DEVICE,
445+ .instance_size = sizeof(RTMRState),
446+ .instance_init = rtmr_init,
447+ .class_init = rtmr_class_init,
448+};
449+
450+static void rtmr_register_types(void)
451+{
452+ type_register_static(&rtmr_info);
453+}
454+
455+type_init(rtmr_register_types)
--- /dev/null
+++ b/include/hw/timer/renesas_cmt.h
@@ -0,0 +1,38 @@
1+/*
2+ * Renesas Compare-match timer Object
3+ *
4+ * Copyright (c) 2019 Yoshinori Sato
5+ *
6+ * This code is licensed under the GPL version 2 or later.
7+ *
8+ */
9+
10+#ifndef HW_RENESAS_CMT_H
11+#define HW_RENESAS_CMT_H
12+
13+#include "hw/sysbus.h"
14+
15+#define TYPE_RENESAS_CMT "renesas-cmt"
16+#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RENESAS_CMT)
17+
18+enum {
19+ CMT_CH = 2,
20+ CMT_NR_IRQ = 1 * CMT_CH,
21+};
22+
23+typedef struct RCMTState {
24+ SysBusDevice parent_obj;
25+
26+ uint64_t input_freq;
27+ MemoryRegion memory;
28+
29+ uint16_t cmstr;
30+ uint16_t cmcr[CMT_CH];
31+ uint16_t cmcnt[CMT_CH];
32+ uint16_t cmcor[CMT_CH];
33+ int64_t tick[CMT_CH];
34+ qemu_irq cmi[CMT_CH];
35+ QEMUTimer *timer[CMT_CH];
36+} RCMTState;
37+
38+#endif
--- /dev/null
+++ b/include/hw/timer/renesas_tmr.h
@@ -0,0 +1,53 @@
1+/*
2+ * Renesas 8bit timer Object
3+ *
4+ * Copyright (c) 2018 Yoshinori Sato
5+ *
6+ * This code is licensed under the GPL version 2 or later.
7+ *
8+ */
9+
10+#ifndef HW_RENESAS_TMR_H
11+#define HW_RENESAS_TMR_H
12+
13+#include "hw/sysbus.h"
14+
15+#define TYPE_RENESAS_TMR "renesas-tmr"
16+#define RTMR(obj) OBJECT_CHECK(RTMRState, (obj), TYPE_RENESAS_TMR)
17+
18+enum timer_event {
19+ cmia = 0,
20+ cmib = 1,
21+ ovi = 2,
22+ none = 3,
23+ TMR_NR_EVENTS = 4
24+};
25+
26+enum {
27+ TMR_CH = 2,
28+ TMR_NR_IRQ = 3 * TMR_CH,
29+};
30+
31+typedef struct RTMRState {
32+ SysBusDevice parent_obj;
33+
34+ uint64_t input_freq;
35+ MemoryRegion memory;
36+
37+ uint8_t tcnt[TMR_CH];
38+ uint8_t tcora[TMR_CH];
39+ uint8_t tcorb[TMR_CH];
40+ uint8_t tcr[TMR_CH];
41+ uint8_t tccr[TMR_CH];
42+ uint8_t tcor[TMR_CH];
43+ uint8_t tcsr[TMR_CH];
44+ int64_t tick;
45+ int64_t div_round[TMR_CH];
46+ enum timer_event next[TMR_CH];
47+ qemu_irq cmia[TMR_CH];
48+ qemu_irq cmib[TMR_CH];
49+ qemu_irq ovi[TMR_CH];
50+ QEMUTimer *timer[TMR_CH];
51+} RTMRState;
52+
53+#endif