From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Kf6rO-0002Yf-58 for qemu-devel@nongnu.org; Mon, 15 Sep 2008 01:42:54 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Kf6rM-0002XD-CC for qemu-devel@nongnu.org; Mon, 15 Sep 2008 01:42:53 -0400 Received: from [199.232.76.173] (port=45606 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Kf6rL-0002Wx-OX for qemu-devel@nongnu.org; Mon, 15 Sep 2008 01:42:52 -0400 Received: from vsmtp02.dti.ne.jp ([202.216.231.137]:61753) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Kf6rL-0008S4-Dz for qemu-devel@nongnu.org; Mon, 15 Sep 2008 01:42:51 -0400 Received: from [192.168.1.21] (PPPa1372.e11.eacc.dti.ne.jp [124.255.91.108]) by vsmtp02.dti.ne.jp (3.11v) with ESMTP AUTH id m8F5gnba012867 for ; Mon, 15 Sep 2008 14:42:49 +0900 (JST) Message-ID: <48CDF5D5.6010506@juno.dti.ne.jp> Date: Mon, 15 Sep 2008 14:42:45 +0900 From: Shin-ichiro KAWASAKI MIME-Version: 1.0 References: <48C3E662.1010204@juno.dti.ne.jp> <20080914165648.GE22422@volta.aurel32.net> In-Reply-To: <20080914165648.GE22422@volta.aurel32.net> Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [PATCH] [RESEND] SH4 : Serial controller improvement Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Aurelien Jarno wrote: >> @@ -194,6 +224,15 @@ >> s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; >> >> break; >> + case 0x14: >> + if (s->rx_cnt > 0) { >> + ret = s->rx_fifo[0]; >> + s->rx_cnt--; >> + memmove(&s->rx_fifo[0], &s->rx_fifo[1], s->rx_cnt); > > I don't think moving the whole buffer each time a character is read is a > good idea. I would suggest to use a circular buffer instead. Have a look > at hw/serial.c how it is done. I see. I'm sending the patch with a circular buffer. Thanks for your comments! Regards, Shin-ichiro KAWASAKI Index: trunk/hw/sh_serial.c =================================================================== --- trunk/hw/sh_serial.c (revision 5219) +++ trunk/hw/sh_serial.c (working copy) @@ -37,6 +37,8 @@ #define SH_SERIAL_FLAG_BRK (1 << 3) #define SH_SERIAL_FLAG_DR (1 << 4) +#define SH_RX_FIFO_LENGTH (16) + typedef struct { uint8_t smr; uint8_t brr; @@ -46,13 +48,16 @@ uint16_t fcr; uint8_t sptr; - uint8_t rx_fifo[16]; /* frdr / rdr */ + uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */ uint8_t rx_cnt; + uint8_t rx_tail; + uint8_t rx_head; target_phys_addr_t base; int freq; int feat; int flags; + int rtrg; CharDriverState *chr; @@ -63,6 +68,14 @@ struct intc_source *bri; } sh_serial_state; +static void sh_serial_clear_fifo(sh_serial_state * s) +{ + memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); + s->rx_cnt = 0; + s->rx_head = 0; + s->rx_tail = 0; +} + static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) { sh_serial_state *s = opaque; @@ -80,6 +93,7 @@ s->brr = val; return; case 0x08: /* SCR */ + /* TODO : For SH7751, SCIF mask should be 0xfb. */ s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); if (!(val & (1 << 5))) s->flags |= SH_SERIAL_FLAG_TEND; @@ -89,6 +103,9 @@ else if (!(val & (1 << 7)) && s->txi->asserted) sh_intc_toggle_source(s->txi, 0, -1); } + if (!(val & (1 << 6)) && s->rxi->asserted) { + sh_intc_toggle_source(s->rxi, 0, -1); + } return; case 0x0c: /* FTDR / TDR */ if (s->chr) { @@ -117,12 +134,37 @@ s->flags &= ~SH_SERIAL_FLAG_RDF; if (!(val & (1 << 0))) s->flags &= ~SH_SERIAL_FLAG_DR; + + if (!(val & (1 << 1)) || !(val & (1 << 0))) { + if (s->rxi && s->rxi->asserted) { + sh_intc_toggle_source(s->rxi, 0, -1); + } + } return; case 0x18: /* FCR */ s->fcr = val; + switch ((val >> 6) & 3) { + case 0: + s->rtrg = 1; + break; + case 1: + s->rtrg = 4; + break; + case 2: + s->rtrg = 8; + break; + case 3: + s->rtrg = 14; + break; + } + if (val & (1 << 1)) { + sh_serial_clear_fifo(s); + s->sr &= ~(1 << 1); + } + return; case 0x20: /* SPTR */ - s->sptr = val; + s->sptr = val & 0xf3; return; case 0x24: /* LSR */ return; @@ -194,6 +236,16 @@ s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; break; + case 0x14: + if (s->rx_cnt > 0) { + ret = s->rx_fifo[s->rx_tail++]; + s->rx_cnt--; + if (s->rx_tail == SH_RX_FIFO_LENGTH) + s->rx_tail = 0; + if (s->rx_cnt < s->rtrg) + s->flags &= ~SH_SERIAL_FLAG_RDF; + } + break; #if 0 case 0x18: ret = s->fcr; @@ -219,6 +271,9 @@ case 0x10: ret = 0; break; + case 0x14: + ret = s->rx_fifo[0]; + break; case 0x1c: ret = s->sptr; break; @@ -240,15 +295,33 @@ static int sh_serial_can_receive(sh_serial_state *s) { - return 0; + return s->scr & (1 << 4); } static void sh_serial_receive_byte(sh_serial_state *s, int ch) { + if (s->feat & SH_SERIAL_FEAT_SCIF) { + if (s->rx_cnt < SH_RX_FIFO_LENGTH) { + s->rx_fifo[s->rx_head++] = ch; + if (s->rx_head == SH_RX_FIFO_LENGTH) + s->rx_head = 0; + s->rx_cnt++; + if (s->rx_cnt >= s->rtrg) { + s->flags |= SH_SERIAL_FLAG_RDF; + if (s->scr & (1 << 6) && s->rxi) { + sh_intc_toggle_source(s->rxi, 0, 1); + } + } + } + } else { + s->rx_fifo[0] = ch; + } } static void sh_serial_receive_break(sh_serial_state *s) { + if (s->feat & SH_SERIAL_FEAT_SCIF) + s->sr |= (1 << 4); } static int sh_serial_can_receive1(void *opaque) @@ -313,6 +386,7 @@ s->base = base; s->feat = feat; s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; + s->rtrg = 1; s->smr = 0; s->brr = 0xff; @@ -326,7 +400,7 @@ s->dr = 0xff; } - s->rx_cnt = 0; + sh_serial_clear_fifo(s); s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, sh_serial_writefn, s);