Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/misoc
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 35250f5b110d
Choose a base ref
...
head repository: m-labs/misoc
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 84514cf8d58e
Choose a head ref
  • 3 commits
  • 2 files changed
  • 2 contributors

Commits on Jul 19, 2015

  1. uart.c: rx overflow fix and tx simplification

    * fixes the clearing of the rx ringbuffer on rx-overflow
    * removes tx_level and tx_cts by restricting the ringbuffer
      to at least one slot empty
    * agnostic of the details of the tx irq: works for uarts that
      generate tx interrupts on !tx-full or on tx-empty.
    * only rx_produce and tx_consume need to be volatile
    jordens authored and sbourdeauducq committed Jul 19, 2015
    Copy the full SHA
    097248b View commit details
  2. uart: support async phys

    jordens authored and sbourdeauducq committed Jul 19, 2015
    Copy the full SHA
    a501d7c View commit details
  3. Copy the full SHA
    84514cf View commit details
Showing with 50 additions and 50 deletions.
  1. +19 −16 misoclib/com/uart/__init__.py
  2. +31 −34 software/libbase/uart.c
35 changes: 19 additions & 16 deletions misoclib/com/uart/__init__.py
Original file line number Diff line number Diff line change
@@ -2,14 +2,14 @@
from migen.bank.description import *
from migen.bank.eventmanager import *
from migen.genlib.record import Record
from migen.flow.actor import Sink, Source
from migen.actorlib.fifo import SyncFIFO
from migen.actorlib.fifo import SyncFIFO, AsyncFIFO


class UART(Module, AutoCSR):
def __init__(self, phy,
tx_fifo_depth=16,
rx_fifo_depth=16):
rx_fifo_depth=16,
phy_cd="sys"):
self._rxtx = CSR(8)
self._txfull = CSRStatus()
self._rxempty = CSRStatus()
@@ -21,27 +21,30 @@ def __init__(self, phy,

# # #

tx_fifo = SyncFIFO([("data", 8)], tx_fifo_depth)
self.submodules += tx_fifo
if phy_cd == "sys":
tx_fifo = SyncFIFO([("data", 8)], tx_fifo_depth)
rx_fifo = SyncFIFO([("data", 8)], rx_fifo_depth)
# Generate TX IRQ when tx_fifo becomes empty
tx_irq = tx_fifo.source.stb
else:
tx_fifo = ClockDomainsRenamer({"write": "sys", "read": phy_cd})(
AsyncFIFO([("data", 8)], tx_fifo_depth))
rx_fifo = ClockDomainsRenamer({"write": phy_cd, "read": "sys"})(
AsyncFIFO([("data", 8)], rx_fifo_depth))
# Generate TX IRQ when tx_fifo becomes non-full
tx_irq = ~tx_fifo.sink.ack
self.submodules += tx_fifo, rx_fifo
self.comb += [
tx_fifo.sink.stb.eq(self._rxtx.re),
tx_fifo.sink.data.eq(self._rxtx.r),
self._txfull.status.eq(~tx_fifo.sink.ack),
Record.connect(tx_fifo.source, phy.sink)
]
Record.connect(tx_fifo.source, phy.sink),
self.ev.tx.trigger.eq(tx_irq),

rx_fifo = SyncFIFO([("data", 8)], rx_fifo_depth)
self.submodules += rx_fifo
self.comb += [
Record.connect(phy.source, rx_fifo.sink),
self._rxempty.status.eq(~rx_fifo.source.stb),
self._rxtx.w.eq(rx_fifo.source.data),
rx_fifo.source.ack.eq(self.ev.rx.clear)
]

self.comb += [
# Generate TX IRQ when tx_fifo becomes empty
self.ev.tx.trigger.eq(tx_fifo.source.stb),
rx_fifo.source.ack.eq(self.ev.rx.clear),
# Generate RX IRQ when rx_fifo becomes non-empty
self.ev.rx.trigger.eq(~rx_fifo.source.stb),
]
65 changes: 31 additions & 34 deletions software/libbase/uart.c
Original file line number Diff line number Diff line change
@@ -13,39 +13,37 @@

static char rx_buf[UART_RINGBUFFER_SIZE_RX];
static volatile unsigned int rx_produce;
static volatile unsigned int rx_consume;
static unsigned int rx_consume;

#define UART_RINGBUFFER_SIZE_TX 128
#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)

static char tx_buf[UART_RINGBUFFER_SIZE_TX];
static unsigned int tx_produce;
static unsigned int tx_consume;
static volatile int tx_cts;
static volatile int tx_level;
static volatile unsigned int tx_consume;

void uart_isr(void)
{
unsigned int stat;
unsigned int stat, rx_produce_next;

stat = uart_ev_pending_read();

if(stat & UART_EV_RX) {
while(!uart_rxempty_read()) {
rx_buf[rx_produce] = uart_rxtx_read();
rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
rx_produce_next = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
if(rx_produce_next != rx_consume) {
rx_buf[rx_produce] = uart_rxtx_read();
rx_produce = rx_produce_next;
}
uart_ev_pending_write(UART_EV_RX);
}
}

if(stat & UART_EV_TX) {
uart_ev_pending_write(UART_EV_TX);
if(tx_level == 0)
tx_cts = 1;
while(tx_level > 0 && !uart_txfull_read()) {
while((tx_consume != tx_produce) && !uart_txfull_read()) {
uart_rxtx_write(tx_buf[tx_consume]);
tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
tx_level--;
}
}
}
@@ -54,8 +52,13 @@ void uart_isr(void)
char uart_read(void)
{
char c;

while(rx_consume == rx_produce);

if(irq_getie()) {
while(rx_consume == rx_produce);
} else if (rx_consume == rx_produce) {
return 0;
}

c = rx_buf[rx_consume];
rx_consume = (rx_consume + 1) & UART_RINGBUFFER_MASK_RX;
return c;
@@ -69,45 +72,39 @@ int uart_read_nonblock(void)
void uart_write(char c)
{
unsigned int oldmask;

unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;

if(irq_getie()) {
while(tx_level == UART_RINGBUFFER_SIZE_TX);
while(tx_produce_next == tx_consume);
} else if(tx_produce_next == tx_consume) {
return;
}

oldmask = irq_getmask();
irq_setmask(0);

if(tx_cts) {
tx_cts = 0;
uart_rxtx_write(c);
} else {
oldmask = irq_getmask();
irq_setmask(oldmask & ~(1 << UART_INTERRUPT));
if((tx_consume != tx_produce) || uart_txfull_read()) {
tx_buf[tx_produce] = c;
tx_produce = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
tx_level++;
tx_produce = tx_produce_next;
} else {
uart_rxtx_write(c);
}
irq_setmask(oldmask);
}

void uart_init(void)
{
unsigned int mask;

rx_produce = 0;
rx_consume = 0;

tx_produce = 0;
tx_consume = 0;
tx_cts = 1;
tx_level = 0;

uart_ev_pending_write(uart_ev_pending_read());
uart_ev_enable_write(UART_EV_TX | UART_EV_RX);
mask = irq_getmask();
mask |= 1 << UART_INTERRUPT;
irq_setmask(mask);
irq_setmask(irq_getmask() | (1 << UART_INTERRUPT));
}

void uart_sync(void)
{
while(!tx_cts);
while(tx_consume != tx_produce);
}