Revision | 310f892cf84c1effb0eb7a031e56ed19bbe4b3fb (tree) |
---|---|
Time | 2019-01-03 00:17:05 |
Author | Yoshinori Sato <ysato@user...> |
Commiter | Yoshinori Sato |
New SCI emulation
@@ -1,493 +1,265 @@ | ||
1 | 1 | /* |
2 | - * QEMU SCI/SCIF serial port emulation | |
2 | + * Renesas Serial Communication Interface | |
3 | 3 | * |
4 | - * Copyright (c) 2007 Magnus Damm | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | 5 | * |
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. | |
8 | 7 | * |
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. | |
26 | 8 | */ |
9 | + | |
27 | 10 | #include "qemu/osdep.h" |
11 | +#include "qemu-common.h" | |
12 | +#include "cpu.h" | |
28 | 13 | #include "hw/hw.h" |
14 | +#include "hw/sysbus.h" | |
29 | 15 | #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" | |
68 | 17 | |
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) | |
75 | 19 | |
76 | -static void sh_serial_clear_fifo(sh_serial_state * s) | |
20 | +static int can_receive(void *opaque) | |
77 | 21 | { |
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; | |
82 | 27 | } |
83 | 28 | |
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) | |
86 | 30 | { |
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); | |
199 | 43 | } |
200 | 44 | } |
201 | - | |
202 | - fprintf(stderr, "sh_serial: unsupported write to 0x%02" | |
203 | - HWADDR_PRIx "\n", offs); | |
204 | - abort(); | |
205 | 45 | } |
206 | 46 | |
207 | -static uint64_t sh_serial_read(void *opaque, hwaddr offs, | |
208 | - unsigned size) | |
47 | +static void send_byte(RSCIState *sci) | |
209 | 48 | { |
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); | |
270 | 59 | } |
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); | |
325 | 60 | } |
326 | 61 | |
327 | -static void sh_serial_receive_break(RenesasSCIState *s) | |
62 | +static void txend(void *opaque) | |
328 | 63 | { |
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 | + } | |
331 | 72 | } |
332 | 73 | |
333 | -static int sh_serial_can_receive1(void *opaque) | |
74 | +static void update_trtime(RSCIState *sci) | |
334 | 75 | { |
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; | |
337 | 84 | } |
338 | 85 | |
339 | -static void sh_serial_timeout_int(void *opaque) | |
86 | +static void sci_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) | |
340 | 87 | { |
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; | |
346 | 133 | } |
134 | + | |
135 | + if (error) | |
136 | + error_report("rsci: unsupported write request to %08lx", addr); | |
347 | 137 | } |
348 | 138 | |
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) | |
350 | 140 | { |
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; | |
382 | 163 | } |
164 | + | |
165 | + if (error) | |
166 | + error_report("rsci: unsupported write request to %08lx", addr); | |
167 | + return -1; | |
383 | 168 | } |
384 | 169 | |
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) | |
386 | 181 | { |
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); | |
390 | 191 | } |
391 | 192 | |
392 | -static void sci_reset(DeviceState *dev) | |
193 | +static void sci_event(void *opaque, int event) | |
393 | 194 | { |
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 | + } | |
411 | 201 | } |
412 | 202 | |
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) | |
420 | 204 | { |
421 | - RenesasSCIState *s = RenesasSCI(dev); | |
422 | - SysBusDevice *d = SYS_BUS_DEVICE(dev); | |
423 | - uint32_t sz; | |
205 | + RSCIState *sci = RSCI(dev); | |
424 | 206 | |
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); | |
446 | 209 | } |
447 | 210 | |
448 | -static void sci_init(Object *obj) | |
211 | +static void rsci_init(Object *obj) | |
449 | 212 | { |
450 | 213 | SysBusDevice *d = SYS_BUS_DEVICE(obj); |
451 | - RenesasSCIState *s = RenesasSCI(obj); | |
214 | + RSCIState *sci = RSCI(obj); | |
215 | + int i; | |
452 | 216 | |
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); | |
458 | 225 | } |
459 | 226 | |
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), | |
463 | 239 | DEFINE_PROP_END_OF_LIST(), |
464 | 240 | }; |
465 | 241 | |
466 | -static void sci_class_init(ObjectClass *klass, void *data) | |
242 | +static void rsci_class_init(ObjectClass *klass, void *data) | |
467 | 243 | { |
468 | 244 | DeviceClass *dc = DEVICE_CLASS(klass); |
469 | 245 | |
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; | |
478 | 250 | } |
479 | 251 | |
480 | -static const TypeInfo sci_info = { | |
481 | - .name = TYPE_RENESASSCI, | |
252 | +static const TypeInfo rsci_info = { | |
253 | + .name = TYPE_RSCI, | |
482 | 254 | .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, | |
486 | 258 | }; |
487 | 259 | |
488 | -static void sci_register_types(void) | |
260 | +static void rsci_register_types(void) | |
489 | 261 | { |
490 | - type_register_static(&sci_info); | |
262 | + type_register_static(&rsci_info); | |
491 | 263 | } |
492 | 264 | |
493 | -type_init(sci_register_types) | |
265 | +type_init(rsci_register_types) |
@@ -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) |
@@ -1,77 +1,42 @@ | ||
1 | 1 | /* |
2 | - * QEMU SCI/SCIF serial port emulation | |
2 | + * Renesas Serial Communication Interface | |
3 | 3 | * |
4 | - * Copyright (c) 2007 Magnus Damm | |
4 | + * Copyright (c) 2018 Yoshinori Sato | |
5 | 5 | * |
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. | |
8 | 7 | * |
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. | |
26 | 8 | */ |
27 | 9 | |
28 | 10 | #include "chardev/char-fe.h" |
11 | +#include "qemu/timer.h" | |
29 | 12 | #include "hw/sysbus.h" |
30 | 13 | |
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) | |
42 | 16 | |
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 | |
46 | 21 | |
47 | 22 | typedef struct { |
48 | 23 | SysBusDevice parent_obj; |
24 | + MemoryRegion memory; | |
49 | 25 | |
50 | - MemoryRegion iomem; | |
51 | - MemoryRegion iomem_p4; | |
52 | - MemoryRegion iomem_a7; | |
53 | 26 | uint8_t smr; |
54 | 27 | uint8_t brr; |
55 | 28 | 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; | |
70 | 39 | 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; |
@@ -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 |