Revision 63242a00 hw/sh_serial.c
b/hw/sh_serial.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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); |
Also available in: Unified diff