• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

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

Commit MetaInfo

Revision310f892cf84c1effb0eb7a031e56ed19bbe4b3fb (tree)
Time2019-01-03 00:17:05
AuthorYoshinori Sato <ysato@user...>
CommiterYoshinori Sato

Log Message

New SCI emulation

Change Summary

Incremental Difference

--- a/hw/char/renesas_sci.c
+++ b/hw/char/renesas_sci.c
@@ -1,493 +1,265 @@
11 /*
2- * QEMU SCI/SCIF serial port emulation
2+ * Renesas Serial Communication Interface
33 *
4- * Copyright (c) 2007 Magnus Damm
4+ * Copyright (c) 2018 Yoshinori Sato
55 *
6- * Based on serial.c - QEMU 16450 UART emulation
7- * Copyright (c) 2003-2004 Fabrice Bellard
6+ * This code is licensed under the GPL version 2 or later.
87 *
9- * Permission is hereby granted, free of charge, to any person obtaining a copy
10- * of this software and associated documentation files (the "Software"), to deal
11- * in the Software without restriction, including without limitation the rights
12- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13- * copies of the Software, and to permit persons to whom the Software is
14- * furnished to do so, subject to the following conditions:
15- *
16- * The above copyright notice and this permission notice shall be included in
17- * all copies or substantial portions of the Software.
18- *
19- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25- * THE SOFTWARE.
268 */
9+
2710 #include "qemu/osdep.h"
11+#include "qemu-common.h"
12+#include "cpu.h"
2813 #include "hw/hw.h"
14+#include "hw/sysbus.h"
2915 #include "hw/char/renesas_sci.h"
30-#include "qapi/error.h"
31-#include "qemu/timer.h"
32-
33-//#define DEBUG_SERIAL
34-
35-#define SH_SERIAL_FLAG_TEND (1 << 0)
36-#define SH_SERIAL_FLAG_TDE (1 << 1)
37-#define SH_SERIAL_FLAG_RDF (1 << 2)
38-#define SH_SERIAL_FLAG_BRK (1 << 3)
39-#define SH_SERIAL_FLAG_DR (1 << 4)
40-
41-#define SH_RX_FIFO_LENGTH (16)
42-
43-typedef struct {
44- MemoryRegion iomem;
45- MemoryRegion iomem_p4;
46- MemoryRegion iomem_a7;
47- uint8_t smr;
48- uint8_t brr;
49- uint8_t scr;
50- uint8_t dr; /* ftdr / tdr */
51- uint8_t sr; /* fsr / ssr */
52- uint16_t fcr;
53- uint8_t sptr;
54-
55- uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
56- uint8_t rx_cnt;
57- uint8_t rx_tail;
58- uint8_t rx_head;
59-
60- int freq;
61- int feat;
62- int flags;
63- int rtrg;
64-
65- CharBackend chr;
66- QEMUTimer *fifo_timeout_timer;
67- uint64_t etu; /* Elementary Time Unit (ns) */
16+#include "qemu/error-report.h"
6817
69- qemu_irq eri;
70- qemu_irq rxi;
71- qemu_irq txi;
72- qemu_irq tei;
73- qemu_irq bri;
74-} sh_serial_state;
18+#define freq_to_ns(freq) (1000000000LL / freq)
7519
76-static void sh_serial_clear_fifo(sh_serial_state * s)
20+static int can_receive(void *opaque)
7721 {
78- memset(s->rx_fifo, 0, SCIF_RX_FIFO_LENGTH);
79- s->rx_cnt = 0;
80- s->rx_head = 0;
81- s->rx_tail = 0;
22+ RSCIState *sci= RSCI(opaque);
23+ if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))
24+ return 0;
25+ else
26+ return sci->scr & 0x10;
8227 }
8328
84-static void sh_serial_write(void *opaque, hwaddr offs,
85- uint64_t val, unsigned size)
29+static void receive(void *opaque, const uint8_t *buf, int size)
8630 {
87- RenesasSCIState *s = opaque;
88- unsigned char ch;
89-
90- if (s->feat & RENESAS_SCI_FEAT_LONG)
91- offs >>= 2;
92-#ifdef DEBUG_SERIAL
93- printf("sh_serial: write offs=0x%02x val=0x%02x\n",
94- offs, val);
95-#endif
96- switch(offs) {
97- case 0x00: /* SMR */
98- s->smr = val & ((s->feat & RENESAS_SCI_FEAT_SCIF) ? 0x7b : 0xff);
99- return;
100- case 0x01: /* BRR */
101- s->brr = val;
102- return;
103- case 0x02: /* SCR */
104- /* TODO : For SH7751, SCIF mask should be 0xfb. */
105- s->scr = val & ((s->feat & RENESAS_SCI_FEAT_SCIF) ? 0xfa : 0xff);
106- if (!(val & (1 << 5)))
107- s->flags |= RENESAS_SCI_FLAG_TEND;
108- if (s->txi && (val & (1 << 7))) {
109- qemu_set_irq(s->txi, 1);
110- qemu_set_irq(s->txi, 0);
111- }
112- if (!(val & (1 << 6))) {
113- qemu_set_irq(s->rxi, 0);
114- }
115- return;
116- case 0x03: /* FTDR / TDR */
117- if (qemu_chr_fe_backend_connected(&s->chr)) {
118- ch = val;
119- /* XXX this blocks entire thread. Rewrite to use
120- * qemu_chr_fe_write and background I/O callbacks */
121- qemu_chr_fe_write_all(&s->chr, &ch, 1);
122- }
123- s->dr = val;
124- s->flags &= ~RENESAS_SCI_FLAG_TDE;
125- return;
126-#if 0
127- case 0x14: /* FRDR / RDR */
128- ret = 0;
129- break;
130-#endif
131- }
132- if (s->feat & RENESAS_SCI_FEAT_SCIF) {
133- switch(offs) {
134- case 0x4: /* FSR */
135- if (!(val & (1 << 6)))
136- s->flags &= ~RENESAS_SCI_FLAG_TEND;
137- if (!(val & (1 << 5)))
138- s->flags &= ~RENESAS_SCI_FLAG_TDE;
139- if (!(val & (1 << 4)))
140- s->flags &= ~RENESAS_SCI_FLAG_BRK;
141- if (!(val & (1 << 1)))
142- s->flags &= ~RENESAS_SCI_FLAG_RDF;
143- if (!(val & (1 << 0)))
144- s->flags &= ~RENESAS_SCI_FLAG_DR;
145-
146- if (!(val & (1 << 1)) || !(val & (1 << 0))) {
147- if (s->rxi) {
148- qemu_set_irq(s->rxi, 0);
149- }
150- }
151- return;
152- case 0x6: /* FCR */
153- s->fcr = val;
154- switch ((val >> 6) & 3) {
155- case 0:
156- s->rtrg = 1;
157- break;
158- case 1:
159- s->rtrg = 4;
160- break;
161- case 2:
162- s->rtrg = 8;
163- break;
164- case 3:
165- s->rtrg = 14;
166- break;
167- }
168- if (val & (1 << 1)) {
169- sh_serial_clear_fifo(s);
170- s->sr &= ~(1 << 1);
171- }
172-
173- return;
174- case 0x08: /* SPTR */
175- s->sptr = val & 0xf3;
176- return;
177- case 0x07: /* LSR */
178- return;
179- }
180- }
181- else {
182- switch(offs) {
183- case 0x4: /* SSR */
184- if (!(val & (1 << 2)))
185- s->flags &= ~RENESAS_SCI_FLAG_TEND;
186- if (!(val & (1 << 7)))
187- s->flags &= ~RENESAS_SCI_FLAG_TDE;
188- if (!(val & (1 << 6)))
189- s->flags &= ~RENESAS_SCI_FLAG_RDF;
190-
191- if (!(val & (1 << 6)) && s->rxi)
192- qemu_set_irq(s->rxi, 0);
193- if (!(val & (1 << 5)) && s->txi)
194- qemu_set_irq(s->txi, 0);
195- return;
196- case 0x7:
197- s->sptr = val & 0x8f;
198- return;
31+ RSCIState *sci= RSCI(opaque);
32+ sci->rdr = buf[0];
33+ if (sci->ssr & 0x40 || size > 1) {
34+ sci->ssr |= 0x20;
35+ if (sci->scr & 0x40)
36+ qemu_set_irq(sci->irq[ERI], 1);
37+ } else {
38+ sci->ssr |= 0x40;
39+ sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime;
40+ if (sci->scr & 0x40) {
41+ qemu_set_irq(sci->irq[RXI], 1);
42+ qemu_set_irq(sci->irq[RXI], 0);
19943 }
20044 }
201-
202- fprintf(stderr, "sh_serial: unsupported write to 0x%02"
203- HWADDR_PRIx "\n", offs);
204- abort();
20545 }
20646
207-static uint64_t sh_serial_read(void *opaque, hwaddr offs,
208- unsigned size)
47+static void send_byte(RSCIState *sci)
20948 {
210- RenesasSCIState *s = opaque;
211- uint32_t ret = ~0;
212-
213-#if 0
214- switch(offs) {
215- case 0x14:
216- ret = 0;
217- break;
218- }
219-#endif
220- if (s->feat & RENESAS_SCI_FEAT_LONG)
221- offs >>= 2;
222- if (s->feat & RENESAS_SCI_FEAT_SCIF) {
223- switch(offs) {
224- case 0x00: /* SMR */
225- ret = s->smr;
226- break;
227- case 0x02: /* SCR */
228- ret = s->scr;
229- break;
230- case 0x04: /* FSR */
231- ret = 0;
232- if (s->flags & RENESAS_SCI_FLAG_TEND)
233- ret |= (1 << 6);
234- if (s->flags & RENESAS_SCI_FLAG_TDE)
235- ret |= (1 << 5);
236- if (s->flags & RENESAS_SCI_FLAG_BRK)
237- ret |= (1 << 4);
238- if (s->flags & RENESAS_SCI_FLAG_RDF)
239- ret |= (1 << 1);
240- if (s->flags & RENESAS_SCI_FLAG_DR)
241- ret |= (1 << 0);
242-
243- if (s->scr & (1 << 5))
244- s->flags |= RENESAS_SCI_FLAG_TDE | RENESAS_SCI_FLAG_TEND;
245-
246- break;
247- case 0x05:
248- if (s->rx_cnt > 0) {
249- ret = s->rx_fifo[s->rx_tail++];
250- s->rx_cnt--;
251- if (s->rx_tail == SCIF_RX_FIFO_LENGTH)
252- s->rx_tail = 0;
253- if (s->rx_cnt < s->rtrg)
254- s->flags &= ~RENESAS_SCI_FLAG_RDF;
255- }
256- break;
257- case 0x06:
258- ret = s->fcr;
259- break;
260- case 0x07:
261- ret = s->rx_cnt;
262- break;
263- case 0x08:
264- ret = s->sptr;
265- break;
266- case 0x09:
267- ret = 0;
268- break;
269- }
49+ if (qemu_chr_fe_backend_connected(&sci->chr))
50+ qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1);
51+ timer_mod(sci->timer,
52+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime);
53+ sci->ssr &= ~0x04;
54+ sci->ssr |= 0x80;
55+ qemu_set_irq(sci->irq[TEI], 0);
56+ if (sci->scr & 0x80) {
57+ qemu_set_irq(sci->irq[TXI], 1);
58+ qemu_set_irq(sci->irq[TXI], 0);
27059 }
271- else {
272- switch(offs) {
273- case 0x00:
274- ret = s->smr;
275- break;
276- case 0x01:
277- ret = s->brr;
278- break;
279- case 0x02:
280- ret = s->scr;
281- break;
282- case 0x03:
283- ret = s->dr;
284- break;
285- case 0x04:
286- ret = 0;
287- if (s->flags & RENESAS_SCI_FLAG_TDE)
288- ret |= (1 << 7);
289- if (s->flags & RENESAS_SCI_FLAG_RDF)
290- ret |= (1 << 6);
291- if (s->flags & RENESAS_SCI_FLAG_OVF)
292- ret |= (1 << 5);
293- if (s->flags & RENESAS_SCI_FLAG_TEND)
294- ret |= (1 << 2);
295- if (s->scr & (1 << 5)) {
296- s->flags |= RENESAS_SCI_FLAG_TDE | RENESAS_SCI_FLAG_TEND;
297- }
298- break;
299- case 0x05:
300- ret = s->rx_fifo[0];
301- s->flags &= ~RENESAS_SCI_FLAG_RDF;
302- break;
303- case 0x07:
304- ret = s->sptr;
305- break;
306- }
307- }
308-#ifdef DEBUG_SERIAL
309- printf("sh_serial: read offs=0x%02x val=0x%x\n",
310- offs, ret);
311-#endif
312-
313- if (ret & ~((1 << 16) - 1)) {
314- fprintf(stderr, "sh_serial: unsupported read from 0x%02"
315- HWADDR_PRIx "\n", offs);
316- abort();
317- }
318-
319- return ret;
320-}
321-
322-static int sh_serial_can_receive(RenesasSCIState *s)
323-{
324- return s->scr & (1 << 4);
32560 }
32661
327-static void sh_serial_receive_break(RenesasSCIState *s)
62+static void txend(void *opaque)
32863 {
329- if (s->feat & RENESAS_SCI_FEAT_SCIF)
330- s->sr |= (1 << 4);
64+ RSCIState *sci= RSCI(opaque);
65+ if (sci->scr & 0x80 && (sci->ssr & 0x80) == 0)
66+ send_byte(sci);
67+ else {
68+ sci->ssr |= 0x04;
69+ if (sci->scr & 0x04)
70+ qemu_set_irq(sci->irq[TEI], 1);
71+ }
33172 }
33273
333-static int sh_serial_can_receive1(void *opaque)
74+static void update_trtime(RSCIState *sci)
33475 {
335- RenesasSCIState *s = opaque;
336- return sh_serial_can_receive(s);
76+ static const int div[] = {1,4,16,64};
77+ int w;
78+
79+ w = (sci->smr & 0x40)?7:8; /* CHR */
80+ w += (sci->smr >> 5) & 1; /* PE */
81+ w += (sci->smr & 0x08)?2:1; /* STOP */
82+ sci->trtime = w * freq_to_ns(sci->input_freq) *
83+ 32 * div[sci->smr & 0x03] * sci->brr;
33784 }
33885
339-static void sh_serial_timeout_int(void *opaque)
86+static void sci_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
34087 {
341- sh_serial_state *s = opaque;
342-
343- s->flags |= SH_SERIAL_FLAG_RDF;
344- if (s->scr & (1 << 6) && s->rxi) {
345- qemu_set_irq(s->rxi, 1);
88+ hwaddr offset = addr & 0x07;
89+ RSCIState *sci = RSCI(opaque);
90+ int error = 0;
91+
92+ switch(offset) {
93+ case 0: /* SMR */
94+ if ((sci->scr & 0x30) == 0) {
95+ sci->smr = val;
96+ update_trtime(sci);
97+ }
98+ break;
99+ case 1: /* BRR */
100+ if ((sci->scr & 0x30) == 0) {
101+ sci->brr = val;
102+ update_trtime(sci);
103+ }
104+ break;
105+ case 2: /* SCR */
106+ sci->scr = val;
107+ if ((sci->scr & 0x20) == 0)
108+ sci->ssr |= 0x84;
109+ if ((sci->scr & 0x04) == 0)
110+ qemu_set_irq(sci->irq[TEI], 0);
111+ if ((sci->scr & 0x40) == 0)
112+ qemu_set_irq(sci->irq[ERI], 0);
113+ break;
114+ case 3: /* TDR */
115+ sci->tdr = val;
116+ if (sci->ssr & 0x04)
117+ send_byte(sci);
118+ else
119+ sci->ssr &= ~0x80;
120+ break;
121+ case 4: /* SSR */
122+ sci->ssr &= ~0x38 | (val & 0x38);
123+ if (((sci->read_ssr & 0x38) ^ (sci->ssr & 0x38)) &&
124+ (sci->ssr & 0x38) == 0)
125+ qemu_set_irq(sci->irq[ERI], 0);
126+ break;
127+ case 5: /* RDR */
128+ error = 1; break;
129+ case 6: /* SCMR */
130+ sci->scmr = val; break;
131+ case 7: /* SEMR */
132+ sci->semr = val; break;
346133 }
134+
135+ if (error)
136+ error_report("rsci: unsupported write request to %08lx", addr);
347137 }
348138
349-static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
139+static uint64_t sci_read(void *opaque, hwaddr addr, unsigned size)
350140 {
351- RenesasSCIState *s = opaque;
352-
353- if (s->feat & RENESAS_SCI_FEAT_SCIF) {
354- int i;
355- for (i = 0; i < size; i++) {
356- if (s->rx_cnt < SCIF_RX_FIFO_LENGTH) {
357- s->rx_fifo[s->rx_head++] = buf[i];
358- if (s->rx_head == SCIF_RX_FIFO_LENGTH) {
359- s->rx_head = 0;
360- }
361- s->rx_cnt++;
362- if (s->rx_cnt >= s->rtrg) {
363- s->flags |= RENESAS_SCI_FLAG_RDF;
364- if (s->scr & (1 << 6) && s->rxi) {
365- timer_del(s->fifo_timeout_timer);
366- qemu_set_irq(s->rxi, 1);
367- }
368- } else {
369- timer_mod(s->fifo_timeout_timer,
370- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
371- }
372- }
373- }
374- } else {
375- if (!(s->flags & RENESAS_SCI_FLAG_RDF)) {
376- s->rx_fifo[0] = buf[0];
377- s->flags |= RENESAS_SCI_FLAG_RDF;
378- if (s->scr & (1 << 6) && s->rxi)
379- qemu_set_irq(s->rxi, 1);
380- } else
381- s->flags |= RENESAS_SCI_FLAG_OVF;
141+ hwaddr offset = addr & 0x07;
142+ RSCIState *sci = RSCI(opaque);
143+ int error = 0;
144+ switch(offset) {
145+ case 0: /* SMR */
146+ return sci->smr;
147+ case 1: /* BRR */
148+ return sci->brr;
149+ case 2: /* SCR */
150+ return sci->scr;
151+ case 3: /* TDR */
152+ return sci->tdr;
153+ case 4: /* SSR */
154+ sci->read_ssr = sci->ssr;
155+ return sci->ssr;
156+ case 5: /* RDR */
157+ sci->ssr &= ~0x40;
158+ return sci->rdr;
159+ case 6: /* SCMR */
160+ return sci->scmr;
161+ case 7: /* SEMR */
162+ return sci->semr;
382163 }
164+
165+ if (error)
166+ error_report("rsci: unsupported write request to %08lx", addr);
167+ return -1;
383168 }
384169
385-static void sh_serial_event(void *opaque, int event)
170+static const MemoryRegionOps sci_ops = {
171+ .write = sci_write,
172+ .read = sci_read,
173+ .endianness = DEVICE_NATIVE_ENDIAN,
174+ .impl = {
175+ .min_access_size = 1,
176+ .max_access_size = 1,
177+ },
178+};
179+
180+static void rsci_reset(DeviceState *dev)
386181 {
387- RenesasSCIState *s = opaque;
388- if (event == CHR_EVENT_BREAK)
389- sh_serial_receive_break(s);
182+ RSCIState *sci = RSCI(dev);
183+ sci->smr = sci->scr = 0x00;
184+ sci->brr = 0xff;
185+ sci->tdr = 0xff;
186+ sci->rdr = 0x00;
187+ sci->ssr = 0x84;
188+ sci->scmr = 0x00;
189+ sci->semr = 0x00;
190+ sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
390191 }
391192
392-static void sci_reset(DeviceState *dev)
193+static void sci_event(void *opaque, int event)
393194 {
394- RenesasSCIState *s = RenesasSCI(dev);
395-
396- s->flags = RENESAS_SCI_FLAG_TEND | RENESAS_SCI_FLAG_TDE;
397- s->rtrg = 1;
398-
399- s->smr = 0;
400- s->brr = 0xff;
401- s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
402- s->sptr = 0;
403-
404- if (s->feat & RENESAS_SCI_FEAT_SCIF) {
405- s->fcr = 0;
406- } else {
407- s->dr = 0xff;
408- }
409-
410- sh_serial_clear_fifo(s);
195+ RSCIState *sci = RSCI(opaque);
196+ if (event == CHR_EVENT_BREAK) {
197+ sci->ssr |= 0x10;
198+ if (sci->scr & 0x40)
199+ qemu_set_irq(sci->irq[ERI], 1);
200+ }
411201 }
412202
413-static const MemoryRegionOps sh_serial_ops = {
414- .read = sh_serial_read,
415- .write = sh_serial_write,
416- .endianness = DEVICE_NATIVE_ENDIAN,
417-};
418-
419-static void sci_realize(DeviceState *dev, Error **errp)
203+static void rsci_realize(DeviceState *dev, Error **errp)
420204 {
421- RenesasSCIState *s = RenesasSCI(dev);
422- SysBusDevice *d = SYS_BUS_DEVICE(dev);
423- uint32_t sz;
205+ RSCIState *sci = RSCI(dev);
424206
425- sz = 8;
426- if (s->feat & RENESAS_SCI_FEAT_LONG)
427- sz <<= 2;
428- if (s->feat & RENESAS_SCI_FEAT_SCIF)
429- sz += 0x08;
430-
431- memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s,
432- "sci", sz);
433- sysbus_init_mmio(d, &s->iomem);
434- if (s->feat & RENESAS_SCI_FEAT_ALIAS) {
435- memory_region_init_alias(&s->iomem_p4, NULL, "sci-p4", &s->iomem,
436- 0, sz);
437- sysbus_init_mmio(d, &s->iomem_p4);
438- memory_region_init_alias(&s->iomem_a7, NULL, "sci-a7", &s->iomem,
439- 0, sz);
440- sysbus_init_mmio(d, &s->iomem_a7);
441- }
442-
443- qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
444- sh_serial_receive1,
445- sh_serial_event, NULL, s, NULL, true);
207+ qemu_chr_fe_set_handlers(&sci->chr, can_receive, receive,
208+ sci_event, NULL, sci, NULL, true);
446209 }
447210
448-static void sci_init(Object *obj)
211+static void rsci_init(Object *obj)
449212 {
450213 SysBusDevice *d = SYS_BUS_DEVICE(obj);
451- RenesasSCIState *s = RenesasSCI(obj);
214+ RSCIState *sci = RSCI(obj);
215+ int i;
452216
453- sysbus_init_irq(d, &s->eri);
454- sysbus_init_irq(d, &s->rxi);
455- sysbus_init_irq(d, &s->txi);
456- sysbus_init_irq(d, &s->tei);
457- sysbus_init_irq(d, &s->bri);
217+ memory_region_init_io(&sci->memory, OBJECT(sci), &sci_ops,
218+ sci, "renesas-sci", 0x8);
219+ sysbus_init_mmio(d, &sci->memory);
220+
221+ for (i = 0; i < 4; i++) {
222+ sysbus_init_irq(d, &sci->irq[i]);
223+ }
224+ sci->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, txend, sci);
458225 }
459226
460-static Property sci_properties[] = {
461- DEFINE_PROP_UINT32("feat", RenesasSCIState, feat, 0),
462- DEFINE_PROP_CHR("chardev", RenesasSCIState, chr),
227+static const VMStateDescription vmstate_rcmt = {
228+ .name = "renesas-sci",
229+ .version_id = 1,
230+ .minimum_version_id = 1,
231+ .fields = (VMStateField[]) {
232+ VMSTATE_END_OF_LIST()
233+ }
234+};
235+
236+static Property rsci_properties[] = {
237+ DEFINE_PROP_UINT64("input-freq", RSCIState, input_freq, 0),
238+ DEFINE_PROP_CHR("chardev", RSCIState, chr),
463239 DEFINE_PROP_END_OF_LIST(),
464240 };
465241
466-static void sci_class_init(ObjectClass *klass, void *data)
242+static void rsci_class_init(ObjectClass *klass, void *data)
467243 {
468244 DeviceClass *dc = DEVICE_CLASS(klass);
469245
470- s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
471- sh_serial_timeout_int, s);
472- s->etu = NANOSECONDS_PER_SECOND / 9600;
473- s->eri = eri_source;
474- s->rxi = rxi_source;
475- s->txi = txi_source;
476- s->tei = tei_source;
477- s->bri = bri_source;
246+ dc->realize = rsci_realize;
247+ dc->props = rsci_properties;
248+ dc->vmsd = &vmstate_rcmt;
249+ dc->reset = rsci_reset;
478250 }
479251
480-static const TypeInfo sci_info = {
481- .name = TYPE_RENESASSCI,
252+static const TypeInfo rsci_info = {
253+ .name = TYPE_RSCI,
482254 .parent = TYPE_SYS_BUS_DEVICE,
483- .instance_size = sizeof(RenesasSCIState),
484- .instance_init = sci_init,
485- .class_init = sci_class_init,
255+ .instance_size = sizeof(RSCIState),
256+ .instance_init = rsci_init,
257+ .class_init = rsci_class_init,
486258 };
487259
488-static void sci_register_types(void)
260+static void rsci_register_types(void)
489261 {
490- type_register_static(&sci_info);
262+ type_register_static(&rsci_info);
491263 }
492264
493-type_init(sci_register_types)
265+type_init(rsci_register_types)
--- /dev/null
+++ b/hw/timer/renesas_cmt.c
@@ -0,0 +1,218 @@
1+/*
2+ * Renesas Compare-match timer
3+ *
4+ * Copyright (c) 2018 Yoshinori Sato
5+ *
6+ * This code is licensed under the GPL version 2 or later.
7+ *
8+ */
9+
10+#include "qemu/osdep.h"
11+#include "qemu-common.h"
12+#include "qemu/timer.h"
13+#include "cpu.h"
14+#include "hw/hw.h"
15+#include "hw/sysbus.h"
16+#include "hw/timer/renesas_cmt.h"
17+#include "qemu/error-report.h"
18+
19+#define freq_to_ns(freq) (1000000000LL / freq)
20+static const int clkdiv[] = {8,32,128,512};
21+
22+static void update_events(RCMTState *cmt, int ch)
23+{
24+ uint16_t diff;
25+
26+ if ((cmt->cmstr & (1 << ch))== 0)
27+ return ;
28+ diff = cmt->cmcor[ch] - cmt->cmcnt[ch];
29+ timer_mod(cmt->timer[ch],
30+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
31+ diff * freq_to_ns(cmt->input_freq) *
32+ clkdiv[cmt->cmcr[ch] & 3]);
33+}
34+
35+static uint64_t read_cmcnt(RCMTState *cmt, int ch)
36+{
37+ int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
38+
39+ if (cmt->cmstr & (1 << ch)) {
40+ delta = (now - cmt->tick[ch]) / freq_to_ns(cmt->input_freq);
41+ delta /= clkdiv[cmt->cmcr[ch] & 0x03];
42+ return cmt->cmcnt[ch] + delta;
43+ } else
44+ return cmt->cmcnt[ch];
45+}
46+
47+static uint64_t cmt_read(void *opaque, hwaddr addr, unsigned size)
48+{
49+ hwaddr offset = addr & 0x0f;
50+ RCMTState *cmt = opaque;
51+ int ch = offset / 0x08;
52+ int error = 1;
53+
54+ if (offset == 0) {
55+ return cmt->cmstr;
56+ error = 0;
57+ } else {
58+ offset &= 0x07;
59+ if (ch == 0)
60+ offset -= 0x02;
61+ error = 0;
62+ switch(offset) {
63+ case 0:
64+ return cmt->cmcr[ch];
65+ case 2:
66+ return read_cmcnt(cmt, ch);
67+ case 4:
68+ return cmt->cmcor[ch];
69+ default:
70+ error = 1;
71+ }
72+ }
73+ if (error)
74+ error_report("rcmt: unsupported read request to %08lx", addr);
75+ return 0xffffffffffffffffUL;
76+}
77+
78+static void start_stop(RCMTState *cmt, int ch, int st)
79+{
80+ if (st)
81+ update_events(cmt, ch);
82+ else
83+ timer_del(cmt->timer[ch]);
84+}
85+
86+static void cmt_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
87+{
88+ hwaddr offset = addr & 0x0f;
89+ RCMTState *cmt = opaque;
90+ int ch = offset / 0x08;
91+ int error = 1;
92+
93+ if (offset == 0) {
94+ cmt->cmstr = val;
95+ start_stop(cmt, 0, cmt->cmstr & 1);
96+ start_stop(cmt, 1, (cmt->cmstr >> 1) & 1);
97+ error = 0;
98+ } else {
99+ offset &= 0x07;
100+ if (ch == 0)
101+ offset -= 0x02;
102+ error = 0;
103+ switch(offset) {
104+ case 0:
105+ cmt->cmcr[ch] = val;
106+ break;
107+ case 2:
108+ cmt->cmcnt[ch] = val;
109+ break;
110+ case 4:
111+ cmt->cmcor[ch] = val;
112+ break;
113+ default:
114+ error = 1;
115+ }
116+ if (error == 0 && cmt->cmstr & (1 << ch))
117+ update_events(cmt, ch);
118+ }
119+ if (error)
120+ error_report("rcmt: unsupported write request to %08lx", addr);
121+}
122+
123+static const MemoryRegionOps cmt_ops = {
124+ .write = cmt_write,
125+ .read = cmt_read,
126+ .endianness = DEVICE_NATIVE_ENDIAN,
127+ .impl = {
128+ .min_access_size = 2,
129+ .max_access_size = 2,
130+ },
131+};
132+
133+static void timer_events(RCMTState *cmt, int ch)
134+{
135+ cmt->cmcnt[ch] = 0;
136+ cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
137+ update_events(cmt, ch);
138+ if (cmt->cmcr[ch] & 0x40)
139+ qemu_irq_pulse(cmt->cmi[ch]);
140+}
141+
142+static void timer_event0(void *opaque)
143+{
144+ RCMTState *cmt = opaque;
145+
146+ timer_events(cmt, 0);
147+}
148+
149+static void timer_event1(void *opaque)
150+{
151+ RCMTState *cmt = opaque;
152+
153+ timer_events(cmt, 1);
154+}
155+
156+static void rcmt_reset(DeviceState *dev)
157+{
158+ RCMTState *cmt = RCMT(dev);
159+ cmt->cmstr = 0;
160+ cmt->cmcr[0] = cmt->cmcr[1] = 0;
161+ cmt->cmcnt[0] = cmt->cmcnt[1] = 0;
162+ cmt->cmcor[0] = cmt->cmcor[1] = 0xffff;
163+}
164+
165+static void rcmt_init(Object *obj)
166+{
167+ SysBusDevice *d = SYS_BUS_DEVICE(obj);
168+ RCMTState *cmt = RCMT(obj);
169+ int i;
170+
171+ memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops,
172+ cmt, "renesas-cmt", 0x10);
173+ sysbus_init_mmio(d, &cmt->memory);
174+
175+ for (i = 0; i < 2; i++) {
176+ sysbus_init_irq(d, &cmt->cmi[i]);
177+ }
178+ cmt->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event0, cmt);
179+ cmt->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, timer_event1, cmt);
180+}
181+
182+static const VMStateDescription vmstate_rcmt = {
183+ .name = "rx-cmt",
184+ .version_id = 1,
185+ .minimum_version_id = 1,
186+ .fields = (VMStateField[]) {
187+ VMSTATE_END_OF_LIST()
188+ }
189+};
190+
191+static Property rcmt_properties[] = {
192+ DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0),
193+ DEFINE_PROP_END_OF_LIST(),
194+};
195+
196+static void rcmt_class_init(ObjectClass *klass, void *data)
197+{
198+ DeviceClass *dc = DEVICE_CLASS(klass);
199+
200+ dc->props = rcmt_properties;
201+ dc->vmsd = &vmstate_rcmt;
202+ dc->reset = rcmt_reset;
203+}
204+
205+static const TypeInfo rcmt_info = {
206+ .name = TYPE_RCMT,
207+ .parent = TYPE_SYS_BUS_DEVICE,
208+ .instance_size = sizeof(RCMTState),
209+ .instance_init = rcmt_init,
210+ .class_init = rcmt_class_init,
211+};
212+
213+static void rcmt_register_types(void)
214+{
215+ type_register_static(&rcmt_info);
216+}
217+
218+type_init(rcmt_register_types)
--- a/include/hw/char/renesas_sci.h
+++ b/include/hw/char/renesas_sci.h
@@ -1,77 +1,42 @@
11 /*
2- * QEMU SCI/SCIF serial port emulation
2+ * Renesas Serial Communication Interface
33 *
4- * Copyright (c) 2007 Magnus Damm
4+ * Copyright (c) 2018 Yoshinori Sato
55 *
6- * Based on serial.c - QEMU 16450 UART emulation
7- * Copyright (c) 2003-2004 Fabrice Bellard
6+ * This code is licensed under the GPL version 2 or later.
87 *
9- * Permission is hereby granted, free of charge, to any person obtaining a copy
10- * of this software and associated documentation files (the "Software"), to deal
11- * in the Software without restriction, including without limitation the rights
12- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13- * copies of the Software, and to permit persons to whom the Software is
14- * furnished to do so, subject to the following conditions:
15- *
16- * The above copyright notice and this permission notice shall be included in
17- * all copies or substantial portions of the Software.
18- *
19- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25- * THE SOFTWARE.
268 */
279
2810 #include "chardev/char-fe.h"
11+#include "qemu/timer.h"
2912 #include "hw/sysbus.h"
3013
31-#define RENESAS_SCI_FLAG_TEND (1 << 0)
32-#define RENESAS_SCI_FLAG_TDE (1 << 1)
33-#define RENESAS_SCI_FLAG_RDF (1 << 2)
34-#define RENESAS_SCI_FLAG_BRK (1 << 3)
35-#define RENESAS_SCI_FLAG_DR (1 << 4)
36-#define RENESAS_SCI_FLAG_OVF (1 << 5)
37-
38-#define SCIF_RX_FIFO_LENGTH (16)
39-
40-#define TYPE_RENESASSCI "renesas-sci"
41-#define RenesasSCI(obj) OBJECT_CHECK(RenesasSCIState, (obj), TYPE_RENESASSCI)
14+#define TYPE_RSCI "renesas-sci"
15+#define RSCI(obj) OBJECT_CHECK(RSCIState, (obj), TYPE_RSCI)
4216
43-#define RENESAS_SCI_FEAT_SCIF (1 << 0)
44-#define RENESAS_SCI_FEAT_LONG (1 << 1)
45-#define RENESAS_SCI_FEAT_ALIAS (1 << 2)
17+#define ERI 0
18+#define RXI 1
19+#define TXI 2
20+#define TEI 3
4621
4722 typedef struct {
4823 SysBusDevice parent_obj;
24+ MemoryRegion memory;
4925
50- MemoryRegion iomem;
51- MemoryRegion iomem_p4;
52- MemoryRegion iomem_a7;
5326 uint8_t smr;
5427 uint8_t brr;
5528 uint8_t scr;
56- uint8_t dr; /* ftdr / tdr */
57- uint8_t sr; /* fsr / ssr */
58- uint16_t fcr;
59- uint8_t sptr;
60-
61- uint8_t rx_fifo[SCIF_RX_FIFO_LENGTH]; /* frdr / rdr */
62- uint8_t rx_cnt;
63- uint8_t rx_tail;
64- uint8_t rx_head;
65-
66- uint32_t feat;
67- int flags;
68- int rtrg;
69-
29+ uint8_t tdr;
30+ uint8_t ssr;
31+ uint8_t rdr;
32+ uint8_t scmr;
33+ uint8_t semr;
34+
35+ uint8_t read_ssr;
36+ long long trtime;
37+ long long rx_next;
38+ QEMUTimer *timer;
7039 CharBackend chr;
71-
72- qemu_irq eri;
73- qemu_irq rxi;
74- qemu_irq txi;
75- qemu_irq tei;
76- qemu_irq bri;
77-} RenesasSCIState;
40+ uint64_t input_freq;
41+ qemu_irq irq[4];
42+} RSCIState;
--- /dev/null
+++ b/include/hw/timer/renesas_cmt.h
@@ -0,0 +1,33 @@
1+/*
2+ * Renesas Compare-match 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_CMT_H
11+#define HW_RENESAS_CMT_H
12+
13+#include "hw/sysbus.h"
14+
15+#define TYPE_RCMT "rcmt"
16+#define RCMT(obj) OBJECT_CHECK(RCMTState, (obj), TYPE_RCMT)
17+
18+typedef struct RCMTState {
19+ SysBusDevice parent_obj;
20+
21+ uint64_t input_freq;
22+ MemoryRegion memory;
23+
24+ uint16_t cmstr;
25+ uint16_t cmcr[2];
26+ uint16_t cmcnt[2];
27+ uint16_t cmcor[2];
28+ int64_t tick[2];
29+ qemu_irq cmi[2];
30+ QEMUTimer *timer[2];
31+} RCMTState;
32+
33+#endif