Commit 63242a007a1898f504837bb7c3c97ce90ae0c8e4
1 parent
f24f381b
SH4: Serial controller improvement
Add receive character feature to SH4 SCIF. SH4-SCI feature implementation work is left. (Shin-ichiro KAWASAKI) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5221 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
79 additions
and
5 deletions
hw/sh_serial.c
... | ... | @@ -37,6 +37,8 @@ |
37 | 37 | #define SH_SERIAL_FLAG_BRK (1 << 3) |
38 | 38 | #define SH_SERIAL_FLAG_DR (1 << 4) |
39 | 39 | |
40 | +#define SH_RX_FIFO_LENGTH (16) | |
41 | + | |
40 | 42 | typedef struct { |
41 | 43 | uint8_t smr; |
42 | 44 | uint8_t brr; |
... | ... | @@ -46,13 +48,16 @@ typedef struct { |
46 | 48 | uint16_t fcr; |
47 | 49 | uint8_t sptr; |
48 | 50 | |
49 | - uint8_t rx_fifo[16]; /* frdr / rdr */ | |
51 | + uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */ | |
50 | 52 | uint8_t rx_cnt; |
53 | + uint8_t rx_tail; | |
54 | + uint8_t rx_head; | |
51 | 55 | |
52 | 56 | target_phys_addr_t base; |
53 | 57 | int freq; |
54 | 58 | int feat; |
55 | 59 | int flags; |
60 | + int rtrg; | |
56 | 61 | |
57 | 62 | CharDriverState *chr; |
58 | 63 | |
... | ... | @@ -63,6 +68,14 @@ typedef struct { |
63 | 68 | struct intc_source *bri; |
64 | 69 | } sh_serial_state; |
65 | 70 | |
71 | +static void sh_serial_clear_fifo(sh_serial_state * s) | |
72 | +{ | |
73 | + memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); | |
74 | + s->rx_cnt = 0; | |
75 | + s->rx_head = 0; | |
76 | + s->rx_tail = 0; | |
77 | +} | |
78 | + | |
66 | 79 | static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) |
67 | 80 | { |
68 | 81 | sh_serial_state *s = opaque; |
... | ... | @@ -80,6 +93,7 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) |
80 | 93 | s->brr = val; |
81 | 94 | return; |
82 | 95 | case 0x08: /* SCR */ |
96 | + /* TODO : For SH7751, SCIF mask should be 0xfb. */ | |
83 | 97 | s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); |
84 | 98 | if (!(val & (1 << 5))) |
85 | 99 | s->flags |= SH_SERIAL_FLAG_TEND; |
... | ... | @@ -89,6 +103,9 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) |
89 | 103 | else if (!(val & (1 << 7)) && s->txi->asserted) |
90 | 104 | sh_intc_toggle_source(s->txi, 0, -1); |
91 | 105 | } |
106 | + if (!(val & (1 << 6)) && s->rxi->asserted) { | |
107 | + sh_intc_toggle_source(s->rxi, 0, -1); | |
108 | + } | |
92 | 109 | return; |
93 | 110 | case 0x0c: /* FTDR / TDR */ |
94 | 111 | if (s->chr) { |
... | ... | @@ -117,12 +134,37 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) |
117 | 134 | s->flags &= ~SH_SERIAL_FLAG_RDF; |
118 | 135 | if (!(val & (1 << 0))) |
119 | 136 | s->flags &= ~SH_SERIAL_FLAG_DR; |
137 | + | |
138 | + if (!(val & (1 << 1)) || !(val & (1 << 0))) { | |
139 | + if (s->rxi && s->rxi->asserted) { | |
140 | + sh_intc_toggle_source(s->rxi, 0, -1); | |
141 | + } | |
142 | + } | |
120 | 143 | return; |
121 | 144 | case 0x18: /* FCR */ |
122 | 145 | s->fcr = val; |
146 | + switch ((val >> 6) & 3) { | |
147 | + case 0: | |
148 | + s->rtrg = 1; | |
149 | + break; | |
150 | + case 1: | |
151 | + s->rtrg = 4; | |
152 | + break; | |
153 | + case 2: | |
154 | + s->rtrg = 8; | |
155 | + break; | |
156 | + case 3: | |
157 | + s->rtrg = 14; | |
158 | + break; | |
159 | + } | |
160 | + if (val & (1 << 1)) { | |
161 | + sh_serial_clear_fifo(s); | |
162 | + s->sr &= ~(1 << 1); | |
163 | + } | |
164 | + | |
123 | 165 | return; |
124 | 166 | case 0x20: /* SPTR */ |
125 | - s->sptr = val; | |
167 | + s->sptr = val & 0xf3; | |
126 | 168 | return; |
127 | 169 | case 0x24: /* LSR */ |
128 | 170 | return; |
... | ... | @@ -190,10 +232,20 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) |
190 | 232 | if (s->flags & SH_SERIAL_FLAG_DR) |
191 | 233 | ret |= (1 << 0); |
192 | 234 | |
193 | - if (s->scr & (1 << 5)) | |
235 | + if (s->scr & (1 << 5)) | |
194 | 236 | s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; |
195 | 237 | |
196 | 238 | break; |
239 | + case 0x14: | |
240 | + if (s->rx_cnt > 0) { | |
241 | + ret = s->rx_fifo[s->rx_tail++]; | |
242 | + s->rx_cnt--; | |
243 | + if (s->rx_tail == SH_RX_FIFO_LENGTH) | |
244 | + s->rx_tail = 0; | |
245 | + if (s->rx_cnt < s->rtrg) | |
246 | + s->flags &= ~SH_SERIAL_FLAG_RDF; | |
247 | + } | |
248 | + break; | |
197 | 249 | #if 0 |
198 | 250 | case 0x18: |
199 | 251 | ret = s->fcr; |
... | ... | @@ -219,6 +271,9 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) |
219 | 271 | case 0x10: |
220 | 272 | ret = 0; |
221 | 273 | break; |
274 | + case 0x14: | |
275 | + ret = s->rx_fifo[0]; | |
276 | + break; | |
222 | 277 | case 0x1c: |
223 | 278 | ret = s->sptr; |
224 | 279 | break; |
... | ... | @@ -240,15 +295,33 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) |
240 | 295 | |
241 | 296 | static int sh_serial_can_receive(sh_serial_state *s) |
242 | 297 | { |
243 | - return 0; | |
298 | + return s->scr & (1 << 4); | |
244 | 299 | } |
245 | 300 | |
246 | 301 | static void sh_serial_receive_byte(sh_serial_state *s, int ch) |
247 | 302 | { |
303 | + if (s->feat & SH_SERIAL_FEAT_SCIF) { | |
304 | + if (s->rx_cnt < SH_RX_FIFO_LENGTH) { | |
305 | + s->rx_fifo[s->rx_head++] = ch; | |
306 | + if (s->rx_head == SH_RX_FIFO_LENGTH) | |
307 | + s->rx_head = 0; | |
308 | + s->rx_cnt++; | |
309 | + if (s->rx_cnt >= s->rtrg) { | |
310 | + s->flags |= SH_SERIAL_FLAG_RDF; | |
311 | + if (s->scr & (1 << 6) && s->rxi) { | |
312 | + sh_intc_toggle_source(s->rxi, 0, 1); | |
313 | + } | |
314 | + } | |
315 | + } | |
316 | + } else { | |
317 | + s->rx_fifo[0] = ch; | |
318 | + } | |
248 | 319 | } |
249 | 320 | |
250 | 321 | static void sh_serial_receive_break(sh_serial_state *s) |
251 | 322 | { |
323 | + if (s->feat & SH_SERIAL_FEAT_SCIF) | |
324 | + s->sr |= (1 << 4); | |
252 | 325 | } |
253 | 326 | |
254 | 327 | static int sh_serial_can_receive1(void *opaque) |
... | ... | @@ -313,6 +386,7 @@ void sh_serial_init (target_phys_addr_t base, int feat, |
313 | 386 | s->base = base; |
314 | 387 | s->feat = feat; |
315 | 388 | s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; |
389 | + s->rtrg = 1; | |
316 | 390 | |
317 | 391 | s->smr = 0; |
318 | 392 | s->brr = 0xff; |
... | ... | @@ -326,7 +400,7 @@ void sh_serial_init (target_phys_addr_t base, int feat, |
326 | 400 | s->dr = 0xff; |
327 | 401 | } |
328 | 402 | |
329 | - s->rx_cnt = 0; | |
403 | + sh_serial_clear_fifo(s); | |
330 | 404 | |
331 | 405 | s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, |
332 | 406 | sh_serial_writefn, s); | ... | ... |