リビジョン | 87ecccea7e71715f63f1f36fbe23aaa73adf3b8a (tree) |
---|---|
日時 | 2022-01-30 23:33:48 |
作者 | Yoshinori Sato <ysato@user...> |
コミッター | Yoshinori Sato |
hw/char/renesas_sci: Add fifo buffer to backend interface.
SCI does not have a fifo, it is necessary to send and receive
But, qemu's chardev backend does not have a buffer,
By buffering the received data with the FIFO, continuous
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
@@ -69,32 +69,63 @@ REG8(SEMR, 7) | ||
69 | 69 | FIELD(SEMR, ACS0, 0, 1) |
70 | 70 | FIELD(SEMR, ABCS, 4, 1) |
71 | 71 | |
72 | -static int can_receive(void *opaque) | |
72 | +enum { | |
73 | + RXFIFO_DEPTH = 16, | |
74 | +}; | |
75 | + | |
76 | +static void set_next_event(RSCIState *sci, int evt, int64_t expire) | |
73 | 77 | { |
74 | - RSCIState *sci = RSCI(opaque); | |
75 | - if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { | |
76 | - return 0; | |
78 | + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
79 | + | |
80 | + if (expire > 0) { | |
81 | + timer_mod(&sci->timer[evt], now + expire); | |
77 | 82 | } else { |
78 | - return FIELD_EX8(sci->scr, SCR, RE); | |
83 | + timer_del(&sci->timer[evt]); | |
79 | 84 | } |
80 | 85 | } |
81 | 86 | |
82 | -static void receive(void *opaque, const uint8_t *buf, int size) | |
87 | +static int can_receive(void *opaque) | |
83 | 88 | { |
84 | 89 | RSCIState *sci = RSCI(opaque); |
85 | - sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime; | |
86 | - if (FIELD_EX8(sci->ssr, SSR, RDRF) || size > 1) { | |
90 | + return FIELD_EX8(sci->scr, SCR, RE) ? fifo8_num_free(&sci->rxfifo) : 0; | |
91 | +} | |
92 | + | |
93 | +static void sci_rx_event(void *opaque) | |
94 | +{ | |
95 | + RSCIState *sci = RSCI(opaque); | |
96 | + uint32_t rd; | |
97 | + | |
98 | + if (fifo8_is_empty(&sci->rxfifo)) { | |
99 | + /* receiver idle state */ | |
100 | + set_next_event(sci, RXTIMER, 0); | |
101 | + return; | |
102 | + } | |
103 | + rd = fifo8_pop(&sci->rxfifo); | |
104 | + if (FIELD_EX8(sci->ssr, SSR, RDRF)) { | |
105 | + /* Don't receive last byte */ | |
87 | 106 | sci->ssr = FIELD_DP8(sci->ssr, SSR, ORER, 1); |
88 | 107 | if (FIELD_EX8(sci->scr, SCR, RIE)) { |
89 | 108 | qemu_set_irq(sci->irq[ERI], 1); |
90 | 109 | } |
91 | 110 | } else { |
92 | - sci->rdr = buf[0]; | |
111 | + sci->rdr = rd; | |
93 | 112 | sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 1); |
94 | 113 | if (FIELD_EX8(sci->scr, SCR, RIE)) { |
95 | 114 | qemu_irq_pulse(sci->irq[RXI]); |
96 | 115 | } |
97 | 116 | } |
117 | + set_next_event(sci, RXTIMER, sci->trtime); | |
118 | +} | |
119 | + | |
120 | +static void receive(void *opaque, const uint8_t *buf, int size) | |
121 | +{ | |
122 | + RSCIState *sci = RSCI(opaque); | |
123 | + fifo8_push_all(&sci->rxfifo, buf, size); | |
124 | + | |
125 | + if (!timer_pending(&sci->timer[RXTIMER])) { | |
126 | + /* reciever idle state, start rx */ | |
127 | + sci_rx_event(sci); | |
128 | + } | |
98 | 129 | } |
99 | 130 | |
100 | 131 | static void send_byte(RSCIState *sci) |
@@ -102,22 +133,26 @@ static void send_byte(RSCIState *sci) | ||
102 | 133 | if (qemu_chr_fe_backend_connected(&sci->chr)) { |
103 | 134 | qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1); |
104 | 135 | } |
105 | - timer_mod(&sci->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime); | |
136 | + set_next_event(sci, TXTIMER, sci->trtime); | |
106 | 137 | sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 0); |
107 | 138 | sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); |
108 | 139 | qemu_set_irq(sci->irq[TEI], 0); |
109 | - if (FIELD_EX8(sci->scr, SCR, TIE)) { | |
140 | + if (FIELD_EX8(sci->scr, SCR, TE) && FIELD_EX8(sci->scr, SCR, TIE)) { | |
110 | 141 | qemu_irq_pulse(sci->irq[TXI]); |
111 | 142 | } |
112 | 143 | } |
113 | 144 | |
114 | -static void txend(void *opaque) | |
145 | +static void sci_tx_event(void *opaque) | |
115 | 146 | { |
116 | 147 | RSCIState *sci = RSCI(opaque); |
117 | - if (!FIELD_EX8(sci->ssr, SSR, TDRE)) { | |
148 | + | |
149 | + if (FIELD_EX8(sci->ssr, SSR, TDRE) == 0) { | |
150 | + /* next tx ready */ | |
118 | 151 | send_byte(sci); |
119 | 152 | } else { |
153 | + /* no next tx */ | |
120 | 154 | sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); |
155 | + set_next_event(sci, TXTIMER, 0); | |
121 | 156 | if (FIELD_EX8(sci->scr, SCR, TEIE)) { |
122 | 157 | qemu_set_irq(sci->irq[TEI], 1); |
123 | 158 | } |
@@ -126,15 +161,15 @@ static void txend(void *opaque) | ||
126 | 161 | |
127 | 162 | static void update_trtime(RSCIState *sci) |
128 | 163 | { |
164 | + int64_t baseclk = NANOSECONDS_PER_SECOND / sci->input_freq; | |
165 | + baseclk *= 64 - 32 * FIELD_EX8(sci->semr, SEMR, ABCS); | |
166 | + baseclk *= 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS)); | |
167 | + baseclk *= sci->brr + 1; | |
129 | 168 | /* char per bits */ |
130 | 169 | sci->trtime = 8 - FIELD_EX8(sci->smr, SMR, CHR); |
131 | 170 | sci->trtime += FIELD_EX8(sci->smr, SMR, PE); |
132 | 171 | sci->trtime += FIELD_EX8(sci->smr, SMR, STOP) + 1; |
133 | - /* x bit transmit time (32 * divrate * brr) / base freq */ | |
134 | - sci->trtime *= 32 * sci->brr; | |
135 | - sci->trtime *= 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS)); | |
136 | - sci->trtime *= NANOSECONDS_PER_SECOND; | |
137 | - sci->trtime /= sci->input_freq; | |
172 | + sci->trtime *= baseclk; | |
138 | 173 | } |
139 | 174 | |
140 | 175 | static bool sci_is_tr_enabled(RSCIState *sci) |
@@ -151,23 +186,37 @@ static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) | ||
151 | 186 | if (!sci_is_tr_enabled(sci)) { |
152 | 187 | sci->smr = val; |
153 | 188 | update_trtime(sci); |
189 | + } else { | |
190 | + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Register 0x%" | |
191 | + HWADDR_PRIX " write protected.\n", offset); | |
154 | 192 | } |
155 | 193 | break; |
156 | 194 | case A_BRR: |
157 | 195 | if (!sci_is_tr_enabled(sci)) { |
158 | 196 | sci->brr = val; |
159 | 197 | update_trtime(sci); |
198 | + } else { | |
199 | + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Register 0x%" | |
200 | + HWADDR_PRIX " write protected.\n", offset); | |
160 | 201 | } |
161 | 202 | break; |
162 | 203 | case A_SCR: |
163 | - sci->scr = val; | |
164 | - if (FIELD_EX8(sci->scr, SCR, TE)) { | |
165 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); | |
166 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); | |
167 | - if (FIELD_EX8(sci->scr, SCR, TIE)) { | |
168 | - qemu_irq_pulse(sci->irq[TXI]); | |
204 | + if (FIELD_EX8(sci->scr, SCR, TE) != FIELD_EX8(val, SCR, TE)) { | |
205 | + if (FIELD_EX8(val, SCR, TE)) { | |
206 | + /* Disable -> Enable to reset TX*/ | |
207 | + sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1); | |
208 | + sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); | |
209 | + if (FIELD_EX8(val, SCR, TIE)) { | |
210 | + qemu_irq_pulse(sci->irq[TXI]); | |
211 | + } | |
212 | + } else { | |
213 | + /* disable TX clock */ | |
214 | + set_next_event(sci, TXTIMER, 0); | |
215 | + sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0); | |
216 | + sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1); | |
169 | 217 | } |
170 | 218 | } |
219 | + sci->scr = val; | |
171 | 220 | if (!FIELD_EX8(sci->scr, SCR, TEIE)) { |
172 | 221 | qemu_set_irq(sci->irq[TEI], 0); |
173 | 222 | } |
@@ -177,10 +226,14 @@ static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) | ||
177 | 226 | break; |
178 | 227 | case A_TDR: |
179 | 228 | sci->tdr = val; |
180 | - if (FIELD_EX8(sci->ssr, SSR, TEND)) { | |
181 | - send_byte(sci); | |
229 | + if (FIELD_EX8(sci->scr, SCR, TE)) { | |
230 | + if (FIELD_EX8(sci->ssr, SSR, TEND)) { | |
231 | + send_byte(sci); | |
232 | + } else { | |
233 | + sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0); | |
234 | + } | |
182 | 235 | } else { |
183 | - sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0); | |
236 | + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Transmit disabled.\n"); | |
184 | 237 | } |
185 | 238 | break; |
186 | 239 | case A_SSR: |
@@ -224,6 +277,9 @@ static uint64_t sci_read(void *opaque, hwaddr offset, unsigned size) | ||
224 | 277 | sci->read_ssr = sci->ssr; |
225 | 278 | return sci->ssr; |
226 | 279 | case A_RDR: |
280 | + if (!FIELD_EX8(sci->scr, SCR, RE)) { | |
281 | + qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Receive disabled.\n"); | |
282 | + } | |
227 | 283 | sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 0); |
228 | 284 | return sci->rdr; |
229 | 285 | case A_SCMR: |
@@ -255,7 +311,7 @@ static void rsci_reset(DeviceState *dev) | ||
255 | 311 | sci->ssr = 0x84; |
256 | 312 | sci->scmr = 0x00; |
257 | 313 | sci->semr = 0x00; |
258 | - sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
314 | + update_trtime(sci); | |
259 | 315 | } |
260 | 316 | |
261 | 317 | static void sci_event(void *opaque, QEMUChrEvent event) |
@@ -263,6 +319,7 @@ static void sci_event(void *opaque, QEMUChrEvent event) | ||
263 | 319 | RSCIState *sci = RSCI(opaque); |
264 | 320 | if (event == CHR_EVENT_BREAK) { |
265 | 321 | sci->ssr = FIELD_DP8(sci->ssr, SSR, FER, 1); |
322 | + sci->rdr = 0; | |
266 | 323 | if (FIELD_EX8(sci->scr, SCR, RIE)) { |
267 | 324 | qemu_set_irq(sci->irq[ERI], 1); |
268 | 325 | } |
@@ -295,16 +352,19 @@ static void rsci_init(Object *obj) | ||
295 | 352 | for (i = 0; i < SCI_NR_IRQ; i++) { |
296 | 353 | sysbus_init_irq(d, &sci->irq[i]); |
297 | 354 | } |
298 | - timer_init_ns(&sci->timer, QEMU_CLOCK_VIRTUAL, txend, sci); | |
355 | + timer_init_ns(&sci->timer[TXTIMER], | |
356 | + QEMU_CLOCK_VIRTUAL, sci_tx_event, sci); | |
357 | + timer_init_ns(&sci->timer[RXTIMER], | |
358 | + QEMU_CLOCK_VIRTUAL, sci_rx_event, sci); | |
359 | + fifo8_create(&sci->rxfifo, RXFIFO_DEPTH); | |
299 | 360 | } |
300 | 361 | |
301 | 362 | static const VMStateDescription vmstate_rsci = { |
302 | 363 | .name = "renesas-sci", |
303 | - .version_id = 1, | |
364 | + .version_id = 2, | |
304 | 365 | .minimum_version_id = 1, |
305 | 366 | .fields = (VMStateField[]) { |
306 | 367 | VMSTATE_INT64(trtime, RSCIState), |
307 | - VMSTATE_INT64(rx_next, RSCIState), | |
308 | 368 | VMSTATE_UINT8(smr, RSCIState), |
309 | 369 | VMSTATE_UINT8(brr, RSCIState), |
310 | 370 | VMSTATE_UINT8(scr, RSCIState), |
@@ -314,7 +374,7 @@ static const VMStateDescription vmstate_rsci = { | ||
314 | 374 | VMSTATE_UINT8(scmr, RSCIState), |
315 | 375 | VMSTATE_UINT8(semr, RSCIState), |
316 | 376 | VMSTATE_UINT8(read_ssr, RSCIState), |
317 | - VMSTATE_TIMER(timer, RSCIState), | |
377 | + VMSTATE_TIMER_ARRAY(timer, RSCIState, NR_TIMER), | |
318 | 378 | VMSTATE_END_OF_LIST() |
319 | 379 | } |
320 | 380 | }; |
@@ -12,6 +12,7 @@ | ||
12 | 12 | #include "chardev/char-fe.h" |
13 | 13 | #include "hw/sysbus.h" |
14 | 14 | #include "qom/object.h" |
15 | +#include "qemu/fifo8.h" | |
15 | 16 | |
16 | 17 | #define TYPE_RENESAS_SCI "renesas-sci" |
17 | 18 | typedef struct RSCIState RSCIState; |
@@ -26,13 +27,18 @@ enum { | ||
26 | 27 | SCI_NR_IRQ = 4 |
27 | 28 | }; |
28 | 29 | |
30 | +enum { | |
31 | + TXTIMER = 0, | |
32 | + RXTIMER = 1, | |
33 | + NR_TIMER = 2, | |
34 | +}; | |
35 | + | |
29 | 36 | struct RSCIState { |
30 | 37 | /*< private >*/ |
31 | 38 | SysBusDevice parent_obj; |
32 | 39 | /*< public >*/ |
33 | 40 | |
34 | 41 | MemoryRegion memory; |
35 | - QEMUTimer timer; | |
36 | 42 | CharBackend chr; |
37 | 43 | qemu_irq irq[SCI_NR_IRQ]; |
38 | 44 |
@@ -47,8 +53,9 @@ struct RSCIState { | ||
47 | 53 | |
48 | 54 | uint8_t read_ssr; |
49 | 55 | int64_t trtime; |
50 | - int64_t rx_next; | |
51 | 56 | uint64_t input_freq; |
57 | + Fifo8 rxfifo; | |
58 | + QEMUTimer timer[NR_TIMER]; | |
52 | 59 | }; |
53 | 60 | |
54 | 61 | #endif |