com/uart: add tx and rx fifos.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 1 May 2015 13:58:10 +0000 (15:58 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 1 May 2015 13:59:26 +0000 (15:59 +0200)
Since ressource usage is low with default depth of 16 (implemented in RAM LUTs) we don't keep old behaviour.
Tested successfully with BIOS and flterm.

misoclib/com/uart/__init__.py
software/libbase/uart.c

index bc5c6cd455761e660d09c8167636b956bbbba728..16160ebb2d08005d899cf40d5da44895d77f1d99 100644 (file)
@@ -3,30 +3,45 @@ 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
 
 
 class UART(Module, AutoCSR):
-    def __init__(self, phy):
+    def __init__(self, phy,
+                 tx_fifo_depth=16,
+                 rx_fifo_depth=16):
         self._rxtx = CSR(8)
+        self._txfull = CSRStatus()
+        self._rxempty = CSRStatus()
 
         self.submodules.ev = EventManager()
-        self.ev.tx = EventSourcePulse()
-        self.ev.rx = EventSourcePulse()
+        self.ev.tx = EventSourceProcess()
+        self.ev.rx = EventSourceProcess()
         self.ev.finalize()
-        ###
-        self.sync += [
-            If(self._rxtx.re,
-                phy.sink.stb.eq(1),
-                phy.sink.data.eq(self._rxtx.r),
-            ).Elif(phy.sink.ack,
-                phy.sink.stb.eq(0)
-            ),
-            If(phy.source.stb,
-                self._rxtx.w.eq(phy.source.data)
-            )
+
+        # # #
+
+        tx_fifo = SyncFIFO([("data", 8)], tx_fifo_depth)
+        self.submodules += tx_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)
         ]
+
+        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 += [
-            self.ev.tx.trigger.eq(phy.sink.stb & phy.sink.ack),
-            self.ev.rx.trigger.eq(phy.source.stb & phy.source.ack),
-            phy.source.ack.eq(~self.ev.rx.pending)
+            # Generate TX IRQ when tx_fifo becomes empty
+            self.ev.tx.trigger.eq(tx_fifo.source.stb),
+            # Generate RX IRQ when rx_fifo becomes non-empty
+            self.ev.rx.trigger.eq(~rx_fifo.source.stb),
         ]
index 13dfe3b1f1ec264f033c72d8c518ce52a8bce4d0..30ea5ef32e57f3f234124d44f68fd8c0d5016fd1 100644 (file)
@@ -31,19 +31,22 @@ void uart_isr(void)
        stat = uart_ev_pending_read();
 
        if(stat & UART_EV_RX) {
-               rx_buf[rx_produce] = uart_rxtx_read();
-               rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
-               uart_ev_pending_write(UART_EV_RX);
+               while(!uart_rxempty_read()) {
+                       rx_buf[rx_produce] = uart_rxtx_read();
+                       rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
+                       uart_ev_pending_write(UART_EV_RX);
+               }
        }
 
        if(stat & UART_EV_TX) {
                uart_ev_pending_write(UART_EV_TX);
-               if(tx_level > 0) {
+               if(tx_level == 0)
+                       tx_cts = 1;
+               while(tx_level > 0 && !uart_txfull_read()) {
                        uart_rxtx_write(tx_buf[tx_consume]);
                        tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
                        tx_level--;
-               } else
-                       tx_cts = 1;
+               }
        }
 }