From: Shin-ichiro KAWASAKI <kawasaki@juno.dti.ne.jp>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] [RESEND] SH4 : Serial controller improvement
Date: Mon, 15 Sep 2008 14:42:45 +0900 [thread overview]
Message-ID: <48CDF5D5.6010506@juno.dti.ne.jp> (raw)
In-Reply-To: <20080914165648.GE22422@volta.aurel32.net>
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);
next prev parent reply other threads:[~2008-09-15 5:42 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-07 14:34 [Qemu-devel] [PATCH] SH4: Serial controller improvement and sleep op bug fix Shin-ichiro KAWASAKI
2008-09-14 16:56 ` Aurelien Jarno
2008-09-15 5:28 ` [PATCH] [RESEND] SH4 : sleep instruction bug fix (was Re: [Qemu-devel] [PATCH] SH4: Serial controller improvement and sleep op bug fix) Shin-ichiro KAWASAKI
2008-09-15 6:42 ` Aurelien Jarno
2008-09-15 5:42 ` Shin-ichiro KAWASAKI [this message]
2008-09-15 7:06 ` [Qemu-devel] [PATCH] [RESEND] SH4 : Serial controller improvement Aurelien Jarno
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48CDF5D5.6010506@juno.dti.ne.jp \
--to=kawasaki@juno.dti.ne.jp \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).