Commit 63242a007a1898f504837bb7c3c97ce90ae0c8e4

Authored by aurel32
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);
... ...