From: Yoshinori Sato <ysato@users.sourceforge.jp>
To: qemu-devel@nongnu.org
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Subject: [PATCH 1/2] hw/char/renesas_sci: Add fifo buffer to backend interface.
Date: Mon, 31 Jan 2022 18:42:45 +0900 [thread overview]
Message-ID: <20220131094246.772550-1-ysato@users.sourceforge.jp> (raw)
SCI does not have a fifo, it is necessary to send and receive
at a bit rate speed.
But, qemu's chardev backend does not have a buffer,
so it sends received data continuously.
By buffering the received data with the FIFO, continuous
received data can be received.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
include/hw/char/renesas_sci.h | 11 ++-
hw/char/renesas_sci.c | 124 +++++++++++++++++++++++++---------
2 files changed, 101 insertions(+), 34 deletions(-)
diff --git a/include/hw/char/renesas_sci.h b/include/hw/char/renesas_sci.h
index a4764e3eee..017711867a 100644
--- a/include/hw/char/renesas_sci.h
+++ b/include/hw/char/renesas_sci.h
@@ -12,6 +12,7 @@
#include "chardev/char-fe.h"
#include "hw/sysbus.h"
#include "qom/object.h"
+#include "qemu/fifo8.h"
#define TYPE_RENESAS_SCI "renesas-sci"
typedef struct RSCIState RSCIState;
@@ -26,13 +27,18 @@ enum {
SCI_NR_IRQ = 4
};
+enum {
+ TXTIMER = 0,
+ RXTIMER = 1,
+ NR_TIMER = 2,
+};
+
struct RSCIState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion memory;
- QEMUTimer timer;
CharBackend chr;
qemu_irq irq[SCI_NR_IRQ];
@@ -47,8 +53,9 @@ struct RSCIState {
uint8_t read_ssr;
int64_t trtime;
- int64_t rx_next;
uint64_t input_freq;
+ Fifo8 rxfifo;
+ QEMUTimer timer[NR_TIMER];
};
#endif
diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c
index 1c63467290..e6513a24b6 100644
--- a/hw/char/renesas_sci.c
+++ b/hw/char/renesas_sci.c
@@ -69,32 +69,63 @@ REG8(SEMR, 7)
FIELD(SEMR, ACS0, 0, 1)
FIELD(SEMR, ABCS, 4, 1)
-static int can_receive(void *opaque)
+enum {
+ RXFIFO_DEPTH = 16,
+};
+
+static void set_next_event(RSCIState *sci, int evt, int64_t expire)
{
- RSCIState *sci = RSCI(opaque);
- if (sci->rx_next > qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
- return 0;
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ if (expire > 0) {
+ timer_mod(&sci->timer[evt], now + expire);
} else {
- return FIELD_EX8(sci->scr, SCR, RE);
+ timer_del(&sci->timer[evt]);
}
}
-static void receive(void *opaque, const uint8_t *buf, int size)
+static int can_receive(void *opaque)
{
RSCIState *sci = RSCI(opaque);
- sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime;
- if (FIELD_EX8(sci->ssr, SSR, RDRF) || size > 1) {
+ return FIELD_EX8(sci->scr, SCR, RE) ? fifo8_num_free(&sci->rxfifo) : 0;
+}
+
+static void sci_rx_event(void *opaque)
+{
+ RSCIState *sci = RSCI(opaque);
+ uint32_t rd;
+
+ if (fifo8_is_empty(&sci->rxfifo)) {
+ /* receiver idle state */
+ set_next_event(sci, RXTIMER, 0);
+ return;
+ }
+ rd = fifo8_pop(&sci->rxfifo);
+ if (FIELD_EX8(sci->ssr, SSR, RDRF)) {
+ /* Don't receive last byte */
sci->ssr = FIELD_DP8(sci->ssr, SSR, ORER, 1);
if (FIELD_EX8(sci->scr, SCR, RIE)) {
qemu_set_irq(sci->irq[ERI], 1);
}
} else {
- sci->rdr = buf[0];
+ sci->rdr = rd;
sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 1);
if (FIELD_EX8(sci->scr, SCR, RIE)) {
qemu_irq_pulse(sci->irq[RXI]);
}
}
+ set_next_event(sci, RXTIMER, sci->trtime);
+}
+
+static void receive(void *opaque, const uint8_t *buf, int size)
+{
+ RSCIState *sci = RSCI(opaque);
+ fifo8_push_all(&sci->rxfifo, buf, size);
+
+ if (!timer_pending(&sci->timer[RXTIMER])) {
+ /* reciever idle state, start rx */
+ sci_rx_event(sci);
+ }
}
static void send_byte(RSCIState *sci)
@@ -102,22 +133,26 @@ static void send_byte(RSCIState *sci)
if (qemu_chr_fe_backend_connected(&sci->chr)) {
qemu_chr_fe_write_all(&sci->chr, &sci->tdr, 1);
}
- timer_mod(&sci->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + sci->trtime);
+ set_next_event(sci, TXTIMER, sci->trtime);
sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 0);
sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1);
qemu_set_irq(sci->irq[TEI], 0);
- if (FIELD_EX8(sci->scr, SCR, TIE)) {
+ if (FIELD_EX8(sci->scr, SCR, TE) && FIELD_EX8(sci->scr, SCR, TIE)) {
qemu_irq_pulse(sci->irq[TXI]);
}
}
-static void txend(void *opaque)
+static void sci_tx_event(void *opaque)
{
RSCIState *sci = RSCI(opaque);
- if (!FIELD_EX8(sci->ssr, SSR, TDRE)) {
+
+ if (FIELD_EX8(sci->ssr, SSR, TDRE) == 0) {
+ /* next tx ready */
send_byte(sci);
} else {
+ /* no next tx */
sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1);
+ set_next_event(sci, TXTIMER, 0);
if (FIELD_EX8(sci->scr, SCR, TEIE)) {
qemu_set_irq(sci->irq[TEI], 1);
}
@@ -126,15 +161,15 @@ static void txend(void *opaque)
static void update_trtime(RSCIState *sci)
{
+ int64_t baseclk = NANOSECONDS_PER_SECOND / sci->input_freq;
+ baseclk *= 64 - 32 * FIELD_EX8(sci->semr, SEMR, ABCS);
+ baseclk *= 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS));
+ baseclk *= sci->brr + 1;
/* char per bits */
sci->trtime = 8 - FIELD_EX8(sci->smr, SMR, CHR);
sci->trtime += FIELD_EX8(sci->smr, SMR, PE);
sci->trtime += FIELD_EX8(sci->smr, SMR, STOP) + 1;
- /* x bit transmit time (32 * divrate * brr) / base freq */
- sci->trtime *= 32 * sci->brr;
- sci->trtime *= 1 << (2 * FIELD_EX8(sci->smr, SMR, CKS));
- sci->trtime *= NANOSECONDS_PER_SECOND;
- sci->trtime /= sci->input_freq;
+ sci->trtime *= baseclk;
}
static bool sci_is_tr_enabled(RSCIState *sci)
@@ -151,23 +186,37 @@ static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
if (!sci_is_tr_enabled(sci)) {
sci->smr = val;
update_trtime(sci);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Register 0x%"
+ HWADDR_PRIX " write protected.\n", offset);
}
break;
case A_BRR:
if (!sci_is_tr_enabled(sci)) {
sci->brr = val;
update_trtime(sci);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Register 0x%"
+ HWADDR_PRIX " write protected.\n", offset);
}
break;
case A_SCR:
- sci->scr = val;
- if (FIELD_EX8(sci->scr, SCR, TE)) {
- sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1);
- sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1);
- if (FIELD_EX8(sci->scr, SCR, TIE)) {
- qemu_irq_pulse(sci->irq[TXI]);
+ if (FIELD_EX8(sci->scr, SCR, TE) != FIELD_EX8(val, SCR, TE)) {
+ if (FIELD_EX8(val, SCR, TE)) {
+ /* Disable -> Enable to reset TX*/
+ sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 1);
+ sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1);
+ if (FIELD_EX8(val, SCR, TIE)) {
+ qemu_irq_pulse(sci->irq[TXI]);
+ }
+ } else {
+ /* disable TX clock */
+ set_next_event(sci, TXTIMER, 0);
+ sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0);
+ sci->ssr = FIELD_DP8(sci->ssr, SSR, TEND, 1);
}
}
+ sci->scr = val;
if (!FIELD_EX8(sci->scr, SCR, TEIE)) {
qemu_set_irq(sci->irq[TEI], 0);
}
@@ -177,10 +226,14 @@ static void sci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
break;
case A_TDR:
sci->tdr = val;
- if (FIELD_EX8(sci->ssr, SSR, TEND)) {
- send_byte(sci);
+ if (FIELD_EX8(sci->scr, SCR, TE)) {
+ if (FIELD_EX8(sci->ssr, SSR, TEND)) {
+ send_byte(sci);
+ } else {
+ sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0);
+ }
} else {
- sci->ssr = FIELD_DP8(sci->ssr, SSR, TDRE, 0);
+ qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Transmit disabled.\n");
}
break;
case A_SSR:
@@ -224,6 +277,9 @@ static uint64_t sci_read(void *opaque, hwaddr offset, unsigned size)
sci->read_ssr = sci->ssr;
return sci->ssr;
case A_RDR:
+ if (!FIELD_EX8(sci->scr, SCR, RE)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "reneas_sci: Receive disabled.\n");
+ }
sci->ssr = FIELD_DP8(sci->ssr, SSR, RDRF, 0);
return sci->rdr;
case A_SCMR:
@@ -255,7 +311,7 @@ static void rsci_reset(DeviceState *dev)
sci->ssr = 0x84;
sci->scmr = 0x00;
sci->semr = 0x00;
- sci->rx_next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ update_trtime(sci);
}
static void sci_event(void *opaque, QEMUChrEvent event)
@@ -263,6 +319,7 @@ static void sci_event(void *opaque, QEMUChrEvent event)
RSCIState *sci = RSCI(opaque);
if (event == CHR_EVENT_BREAK) {
sci->ssr = FIELD_DP8(sci->ssr, SSR, FER, 1);
+ sci->rdr = 0;
if (FIELD_EX8(sci->scr, SCR, RIE)) {
qemu_set_irq(sci->irq[ERI], 1);
}
@@ -295,16 +352,19 @@ static void rsci_init(Object *obj)
for (i = 0; i < SCI_NR_IRQ; i++) {
sysbus_init_irq(d, &sci->irq[i]);
}
- timer_init_ns(&sci->timer, QEMU_CLOCK_VIRTUAL, txend, sci);
+ timer_init_ns(&sci->timer[TXTIMER],
+ QEMU_CLOCK_VIRTUAL, sci_tx_event, sci);
+ timer_init_ns(&sci->timer[RXTIMER],
+ QEMU_CLOCK_VIRTUAL, sci_rx_event, sci);
+ fifo8_create(&sci->rxfifo, RXFIFO_DEPTH);
}
static const VMStateDescription vmstate_rsci = {
.name = "renesas-sci",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT64(trtime, RSCIState),
- VMSTATE_INT64(rx_next, RSCIState),
VMSTATE_UINT8(smr, RSCIState),
VMSTATE_UINT8(brr, RSCIState),
VMSTATE_UINT8(scr, RSCIState),
@@ -314,7 +374,7 @@ static const VMStateDescription vmstate_rsci = {
VMSTATE_UINT8(scmr, RSCIState),
VMSTATE_UINT8(semr, RSCIState),
VMSTATE_UINT8(read_ssr, RSCIState),
- VMSTATE_TIMER(timer, RSCIState),
+ VMSTATE_TIMER_ARRAY(timer, RSCIState, NR_TIMER),
VMSTATE_END_OF_LIST()
}
};
--
2.30.2
next reply other threads:[~2022-01-31 9:44 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-31 9:42 Yoshinori Sato [this message]
2022-01-31 9:42 ` [PATCH 2/2] test/avocado: Update machibe_rx_gdbsim tests Yoshinori Sato
2022-02-01 6:48 ` [PATCH 1/2] hw/char/renesas_sci: Add fifo buffer to backend interface Thomas Huth
2022-02-01 15:52 ` Yoshinori Sato
2022-02-01 18:54 ` Peter Maydell
2022-02-03 13:38 ` Yoshinori Sato
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=20220131094246.772550-1-ysato@users.sourceforge.jp \
--to=ysato@users.sourceforge.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.