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,6 +37,8 @@
37 #define SH_SERIAL_FLAG_BRK (1 << 3) 37 #define SH_SERIAL_FLAG_BRK (1 << 3)
38 #define SH_SERIAL_FLAG_DR (1 << 4) 38 #define SH_SERIAL_FLAG_DR (1 << 4)
39 39
  40 +#define SH_RX_FIFO_LENGTH (16)
  41 +
40 typedef struct { 42 typedef struct {
41 uint8_t smr; 43 uint8_t smr;
42 uint8_t brr; 44 uint8_t brr;
@@ -46,13 +48,16 @@ typedef struct { @@ -46,13 +48,16 @@ typedef struct {
46 uint16_t fcr; 48 uint16_t fcr;
47 uint8_t sptr; 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 uint8_t rx_cnt; 52 uint8_t rx_cnt;
  53 + uint8_t rx_tail;
  54 + uint8_t rx_head;
51 55
52 target_phys_addr_t base; 56 target_phys_addr_t base;
53 int freq; 57 int freq;
54 int feat; 58 int feat;
55 int flags; 59 int flags;
  60 + int rtrg;
56 61
57 CharDriverState *chr; 62 CharDriverState *chr;
58 63
@@ -63,6 +68,14 @@ typedef struct { @@ -63,6 +68,14 @@ typedef struct {
63 struct intc_source *bri; 68 struct intc_source *bri;
64 } sh_serial_state; 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 static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) 79 static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
67 { 80 {
68 sh_serial_state *s = opaque; 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,6 +93,7 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
80 s->brr = val; 93 s->brr = val;
81 return; 94 return;
82 case 0x08: /* SCR */ 95 case 0x08: /* SCR */
  96 + /* TODO : For SH7751, SCIF mask should be 0xfb. */
83 s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); 97 s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
84 if (!(val & (1 << 5))) 98 if (!(val & (1 << 5)))
85 s->flags |= SH_SERIAL_FLAG_TEND; 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,6 +103,9 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
89 else if (!(val & (1 << 7)) && s->txi->asserted) 103 else if (!(val & (1 << 7)) && s->txi->asserted)
90 sh_intc_toggle_source(s->txi, 0, -1); 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 return; 109 return;
93 case 0x0c: /* FTDR / TDR */ 110 case 0x0c: /* FTDR / TDR */
94 if (s->chr) { 111 if (s->chr) {
@@ -117,12 +134,37 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) @@ -117,12 +134,37 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
117 s->flags &= ~SH_SERIAL_FLAG_RDF; 134 s->flags &= ~SH_SERIAL_FLAG_RDF;
118 if (!(val & (1 << 0))) 135 if (!(val & (1 << 0)))
119 s->flags &= ~SH_SERIAL_FLAG_DR; 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 return; 143 return;
121 case 0x18: /* FCR */ 144 case 0x18: /* FCR */
122 s->fcr = val; 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 return; 165 return;
124 case 0x20: /* SPTR */ 166 case 0x20: /* SPTR */
125 - s->sptr = val; 167 + s->sptr = val & 0xf3;
126 return; 168 return;
127 case 0x24: /* LSR */ 169 case 0x24: /* LSR */
128 return; 170 return;
@@ -190,10 +232,20 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) @@ -190,10 +232,20 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
190 if (s->flags & SH_SERIAL_FLAG_DR) 232 if (s->flags & SH_SERIAL_FLAG_DR)
191 ret |= (1 << 0); 233 ret |= (1 << 0);
192 234
193 - if (s->scr & (1 << 5)) 235 + if (s->scr & (1 << 5))
194 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; 236 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
195 237
196 break; 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 #if 0 249 #if 0
198 case 0x18: 250 case 0x18:
199 ret = s->fcr; 251 ret = s->fcr;
@@ -219,6 +271,9 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) @@ -219,6 +271,9 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
219 case 0x10: 271 case 0x10:
220 ret = 0; 272 ret = 0;
221 break; 273 break;
  274 + case 0x14:
  275 + ret = s->rx_fifo[0];
  276 + break;
222 case 0x1c: 277 case 0x1c:
223 ret = s->sptr; 278 ret = s->sptr;
224 break; 279 break;
@@ -240,15 +295,33 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) @@ -240,15 +295,33 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
240 295
241 static int sh_serial_can_receive(sh_serial_state *s) 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 static void sh_serial_receive_byte(sh_serial_state *s, int ch) 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 static void sh_serial_receive_break(sh_serial_state *s) 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 static int sh_serial_can_receive1(void *opaque) 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,6 +386,7 @@ void sh_serial_init (target_phys_addr_t base, int feat,
313 s->base = base; 386 s->base = base;
314 s->feat = feat; 387 s->feat = feat;
315 s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; 388 s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
  389 + s->rtrg = 1;
316 390
317 s->smr = 0; 391 s->smr = 0;
318 s->brr = 0xff; 392 s->brr = 0xff;
@@ -326,7 +400,7 @@ void sh_serial_init (target_phys_addr_t base, int feat, @@ -326,7 +400,7 @@ void sh_serial_init (target_phys_addr_t base, int feat,
326 s->dr = 0xff; 400 s->dr = 0xff;
327 } 401 }
328 402
329 - s->rx_cnt = 0; 403 + sh_serial_clear_fifo(s);
330 404
331 s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, 405 s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
332 sh_serial_writefn, s); 406 sh_serial_writefn, s);