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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.