mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-29 21:33:53 -06:00
SH4: Serial controller improvement
Add receive character feature to SH4 SCIF. SH4-SCI feature implementation work is left. (Shin-ichiro KAWASAKI) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5221 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
f24f381b2d
commit
63242a007a
1 changed files with 79 additions and 5 deletions
|
@ -37,6 +37,8 @@
|
||||||
#define SH_SERIAL_FLAG_BRK (1 << 3)
|
#define SH_SERIAL_FLAG_BRK (1 << 3)
|
||||||
#define SH_SERIAL_FLAG_DR (1 << 4)
|
#define SH_SERIAL_FLAG_DR (1 << 4)
|
||||||
|
|
||||||
|
#define SH_RX_FIFO_LENGTH (16)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t smr;
|
uint8_t smr;
|
||||||
uint8_t brr;
|
uint8_t brr;
|
||||||
|
@ -46,13 +48,16 @@ typedef struct {
|
||||||
uint16_t fcr;
|
uint16_t fcr;
|
||||||
uint8_t sptr;
|
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_cnt;
|
||||||
|
uint8_t rx_tail;
|
||||||
|
uint8_t rx_head;
|
||||||
|
|
||||||
target_phys_addr_t base;
|
target_phys_addr_t base;
|
||||||
int freq;
|
int freq;
|
||||||
int feat;
|
int feat;
|
||||||
int flags;
|
int flags;
|
||||||
|
int rtrg;
|
||||||
|
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
|
|
||||||
|
@ -63,6 +68,14 @@ typedef struct {
|
||||||
struct intc_source *bri;
|
struct intc_source *bri;
|
||||||
} sh_serial_state;
|
} 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)
|
static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
|
||||||
{
|
{
|
||||||
sh_serial_state *s = opaque;
|
sh_serial_state *s = opaque;
|
||||||
|
@ -80,6 +93,7 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
|
||||||
s->brr = val;
|
s->brr = val;
|
||||||
return;
|
return;
|
||||||
case 0x08: /* SCR */
|
case 0x08: /* SCR */
|
||||||
|
/* TODO : For SH7751, SCIF mask should be 0xfb. */
|
||||||
s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
|
s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
|
||||||
if (!(val & (1 << 5)))
|
if (!(val & (1 << 5)))
|
||||||
s->flags |= SH_SERIAL_FLAG_TEND;
|
s->flags |= SH_SERIAL_FLAG_TEND;
|
||||||
|
@ -89,6 +103,9 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
|
||||||
else if (!(val & (1 << 7)) && s->txi->asserted)
|
else if (!(val & (1 << 7)) && s->txi->asserted)
|
||||||
sh_intc_toggle_source(s->txi, 0, -1);
|
sh_intc_toggle_source(s->txi, 0, -1);
|
||||||
}
|
}
|
||||||
|
if (!(val & (1 << 6)) && s->rxi->asserted) {
|
||||||
|
sh_intc_toggle_source(s->rxi, 0, -1);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case 0x0c: /* FTDR / TDR */
|
case 0x0c: /* FTDR / TDR */
|
||||||
if (s->chr) {
|
if (s->chr) {
|
||||||
|
@ -117,12 +134,37 @@ static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
|
||||||
s->flags &= ~SH_SERIAL_FLAG_RDF;
|
s->flags &= ~SH_SERIAL_FLAG_RDF;
|
||||||
if (!(val & (1 << 0)))
|
if (!(val & (1 << 0)))
|
||||||
s->flags &= ~SH_SERIAL_FLAG_DR;
|
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;
|
return;
|
||||||
case 0x18: /* FCR */
|
case 0x18: /* FCR */
|
||||||
s->fcr = val;
|
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;
|
return;
|
||||||
case 0x20: /* SPTR */
|
case 0x20: /* SPTR */
|
||||||
s->sptr = val;
|
s->sptr = val & 0xf3;
|
||||||
return;
|
return;
|
||||||
case 0x24: /* LSR */
|
case 0x24: /* LSR */
|
||||||
return;
|
return;
|
||||||
|
@ -190,9 +232,19 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
|
||||||
if (s->flags & SH_SERIAL_FLAG_DR)
|
if (s->flags & SH_SERIAL_FLAG_DR)
|
||||||
ret |= (1 << 0);
|
ret |= (1 << 0);
|
||||||
|
|
||||||
if (s->scr & (1 << 5))
|
if (s->scr & (1 << 5))
|
||||||
s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
|
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;
|
break;
|
||||||
#if 0
|
#if 0
|
||||||
case 0x18:
|
case 0x18:
|
||||||
|
@ -219,6 +271,9 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
|
||||||
case 0x10:
|
case 0x10:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
case 0x14:
|
||||||
|
ret = s->rx_fifo[0];
|
||||||
|
break;
|
||||||
case 0x1c:
|
case 0x1c:
|
||||||
ret = s->sptr;
|
ret = s->sptr;
|
||||||
break;
|
break;
|
||||||
|
@ -240,15 +295,33 @@ static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
|
||||||
|
|
||||||
static int sh_serial_can_receive(sh_serial_state *s)
|
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)
|
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)
|
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)
|
static int sh_serial_can_receive1(void *opaque)
|
||||||
|
@ -313,6 +386,7 @@ void sh_serial_init (target_phys_addr_t base, int feat,
|
||||||
s->base = base;
|
s->base = base;
|
||||||
s->feat = feat;
|
s->feat = feat;
|
||||||
s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
|
s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
|
||||||
|
s->rtrg = 1;
|
||||||
|
|
||||||
s->smr = 0;
|
s->smr = 0;
|
||||||
s->brr = 0xff;
|
s->brr = 0xff;
|
||||||
|
@ -326,7 +400,7 @@ void sh_serial_init (target_phys_addr_t base, int feat,
|
||||||
s->dr = 0xff;
|
s->dr = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->rx_cnt = 0;
|
sh_serial_clear_fifo(s);
|
||||||
|
|
||||||
s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
|
s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
|
||||||
sh_serial_writefn, s);
|
sh_serial_writefn, s);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue