From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [4300] ETRAX serial port:
Date: Fri, 02 May 2008 22:21:56 +0000 [thread overview]
Message-ID: <E1Js3dc-0002wl-BL@cvs.savannah.gnu.org> (raw)
Revision: 4300
http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4300
Author: edgar_igl
Date: 2008-05-02 22:21:55 +0000 (Fri, 02 May 2008)
Log Message:
-----------
ETRAX serial port:
* Simulate basic interrupt driven serial io.
* Connect to qemu char dev.
Modified Paths:
--------------
trunk/hw/etraxfs_ser.c
Modified: trunk/hw/etraxfs_ser.c
===================================================================
--- trunk/hw/etraxfs_ser.c 2008-05-02 22:16:17 UTC (rev 4299)
+++ trunk/hw/etraxfs_ser.c 2008-05-02 22:21:55 UTC (rev 4300)
@@ -25,21 +25,68 @@
#include <stdio.h>
#include <ctype.h>
#include "hw.h"
+#include "qemu-char.h"
#define D(x)
-#define RW_TR_DMA_EN 0x04
-#define RW_DOUT 0x1c
-#define RW_STAT_DIN 0x20
-#define R_STAT_DIN 0x24
+#define RW_TR_CTRL 0x00
+#define RW_TR_DMA_EN 0x04
+#define RW_REC_CTRL 0x08
+#define RW_DOUT 0x1c
+#define RS_STAT_DIN 0x20
+#define R_STAT_DIN 0x24
+#define RW_INTR_MASK 0x2c
+#define RW_ACK_INTR 0x30
+#define R_INTR 0x34
+#define R_MASKED_INTR 0x38
-static uint32_t ser_readb (void *opaque, target_phys_addr_t addr)
+#define STAT_DAV 16
+#define STAT_TR_IDLE 22
+#define STAT_TR_RDY 24
+
+struct etrax_serial_t
{
- D(CPUState *env = opaque);
- D(printf ("%s %x pc=%x\n", __func__, addr, env->pc));
- return 0;
+ CPUState *env;
+ CharDriverState *chr;
+ qemu_irq *irq;
+
+ target_phys_addr_t base;
+
+ int pending_tx;
+
+ /* Control registers. */
+ uint32_t rw_tr_ctrl;
+ uint32_t rw_tr_dma_en;
+ uint32_t rw_rec_ctrl;
+ uint32_t rs_stat_din;
+ uint32_t r_stat_din;
+ uint32_t rw_intr_mask;
+ uint32_t rw_ack_intr;
+ uint32_t r_intr;
+ uint32_t r_masked_intr;
+};
+
+static void ser_update_irq(struct etrax_serial_t *s)
+{
+ uint32_t o_irq = s->r_masked_intr;
+
+ s->r_intr &= ~(s->rw_ack_intr);
+ s->r_masked_intr = s->r_intr & s->rw_intr_mask;
+
+ if (o_irq != s->r_masked_intr) {
+ D(printf("irq_mask=%x r_intr=%x rmi=%x airq=%x \n",
+ s->rw_intr_mask, s->r_intr,
+ s->r_masked_intr, s->rw_ack_intr));
+ if (s->r_masked_intr)
+ qemu_irq_raise(s->irq[0]);
+ else
+ qemu_irq_lower(s->irq[0]);
+ }
+ s->rw_ack_intr = 0;
}
-static uint32_t ser_readw (void *opaque, target_phys_addr_t addr)
+
+
+static uint32_t ser_readb (void *opaque, target_phys_addr_t addr)
{
D(CPUState *env = opaque);
D(printf ("%s %x pc=%x\n", __func__, addr, env->pc));
@@ -48,17 +95,41 @@
static uint32_t ser_readl (void *opaque, target_phys_addr_t addr)
{
- D(CPUState *env = opaque);
+ struct etrax_serial_t *s = opaque;
+ D(CPUState *env = s->env);
uint32_t r = 0;
switch (addr & 0xfff)
{
+ case RW_TR_CTRL:
+ r = s->rw_tr_ctrl;
+ break;
case RW_TR_DMA_EN:
+ r = s->rw_tr_dma_en;
break;
+ case RS_STAT_DIN:
+ r = s->rs_stat_din;
+ /* clear dav. */
+ s->rs_stat_din &= ~(1 << STAT_DAV);
+ break;
case R_STAT_DIN:
- r |= 1 << 24; /* set tr_rdy. */
- r |= 1 << 22; /* set tr_idle. */
+ r = s->rs_stat_din;
break;
+ case RW_ACK_INTR:
+ D(printf("load rw_ack_intr=%x\n", s->rw_ack_intr));
+ r = s->rw_ack_intr;
+ break;
+ case RW_INTR_MASK:
+ r = s->rw_intr_mask;
+ break;
+ case R_INTR:
+ D(printf("load r_intr=%x\n", s->r_intr));
+ r = s->r_intr;
+ break;
+ case R_MASKED_INTR:
+ D(printf("load r_maked_intr=%x\n", s->r_masked_intr));
+ r = s->r_masked_intr;
+ break;
default:
D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
@@ -70,53 +141,117 @@
static void
ser_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
- D(CPUState *env = opaque);
+ D(struct etrax_serial_t *s = opaque);
+ D(CPUState *env = s->env);
D(printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc));
}
static void
-ser_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- D(CPUState *env = opaque);
- D(printf ("%s %x %x pc=%x\n", __func__, addr, value, env->pc));
-}
-static void
ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
- D(CPUState *env = opaque);
+ struct etrax_serial_t *s = opaque;
+ unsigned char ch = value;
+ D(CPUState *env = s->env);
switch (addr & 0xfff)
{
+ case RW_TR_CTRL:
+ D(printf("rw_tr_ctrl=%x\n", value));
+ s->rw_tr_ctrl = value;
+ break;
case RW_TR_DMA_EN:
+ D(printf("rw_tr_dma_en=%x\n", value));
+ s->rw_tr_dma_en = value;
break;
case RW_DOUT:
- if (isprint(value) || isspace(value))
- putchar(value);
- else
- putchar('.');
- fflush(stdout);
+ qemu_chr_write(s->chr, &ch, 1);
+ s->r_intr |= 1;
+ s->pending_tx = 1;
break;
+ case RW_ACK_INTR:
+ D(printf("rw_ack_intr=%x\n", value));
+ s->rw_ack_intr = value;
+ if (s->pending_tx && (s->rw_ack_intr & 1)) {
+ s->r_intr |= 1;
+ s->pending_tx = 0;
+ s->rw_ack_intr &= ~1;
+ }
+ break;
+ case RW_INTR_MASK:
+ D(printf("r_intr_mask=%x\n", value));
+ s->rw_intr_mask = value;
+ break;
default:
D(printf ("%s %x %x pc=%x\n",
__func__, addr, value, env->pc));
break;
}
+ ser_update_irq(s);
}
static CPUReadMemoryFunc *ser_read[] = {
&ser_readb,
- &ser_readw,
+ &ser_readb,
&ser_readl,
};
static CPUWriteMemoryFunc *ser_write[] = {
&ser_writeb,
- &ser_writew,
+ &ser_writeb,
&ser_writel,
};
-void etraxfs_ser_init(CPUState *env, qemu_irq *irqs, target_phys_addr_t base)
+static void serial_receive(void *opaque, const uint8_t *buf, int size)
{
+ struct etrax_serial_t *s = opaque;
+
+ s->r_intr |= 8;
+ s->rs_stat_din &= ~0xff;
+ s->rs_stat_din |= (buf[0] & 0xff);
+ s->rs_stat_din |= (1 << STAT_DAV); /* dav. */
+ ser_update_irq(s);
+}
+
+static int serial_can_receive(void *opaque)
+{
+ struct etrax_serial_t *s = opaque;
+ int r;
+
+ /* Is the receiver enabled? */
+ r = s->rw_rec_ctrl & 1;
+
+ /* Pending rx data? */
+ r |= !(s->r_intr & 8);
+ return r;
+}
+
+static void serial_event(void *opaque, int event)
+{
+
+}
+
+void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr,
+ target_phys_addr_t base)
+{
+ struct etrax_serial_t *s;
int ser_regs;
- ser_regs = cpu_register_io_memory(0, ser_read, ser_write, env);
+
+ s = qemu_mallocz(sizeof *s);
+ if (!s)
+ return;
+
+ s->env = env;
+ s->irq = irq;
+ s->base = base;
+
+ s->chr = chr;
+
+ /* transmitter begins ready and idle. */
+ s->rs_stat_din |= (1 << STAT_TR_RDY);
+ s->rs_stat_din |= (1 << STAT_TR_IDLE);
+
+ qemu_chr_add_handlers(chr, serial_can_receive, serial_receive,
+ serial_event, s);
+
+ ser_regs = cpu_register_io_memory(0, ser_read, ser_write, s);
cpu_register_physical_memory (base, 0x3c, ser_regs);
}
reply other threads:[~2008-05-02 22:21 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=E1Js3dc-0002wl-BL@cvs.savannah.gnu.org \
--to=edgar.iglesias@gmail.com \
--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.