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