periph.serial: add AsyncSerialPeripheral
[lambdasoc.git] / lambdasoc / periph / serial.py
1 from nmigen import *
2 from nmigen.lib.fifo import SyncFIFO
3
4 from nmigen_stdio.serial import AsyncSerial
5
6 from . import Peripheral
7
8
9 __all__ = ["AsyncSerialPeripheral"]
10
11
12 class AsyncSerialPeripheral(Peripheral, Elaboratable):
13 """Asynchronous serial transceiver peripheral.
14
15 See :class:`nmigen_stdio.serial.AsyncSerial` for details.
16
17 CSR registers
18 -------------
19 divisor : read/write
20 Clock divisor.
21 rx_data : read-only
22 Receiver data.
23 rx_rdy : read-only
24 Receiver ready. The receiver FIFO is non-empty.
25 rx_err : read-only
26 Receiver error flags. See :class:`nmigen_stdio.serial.AsyncSerialRX` for layout.
27 tx_data : write-only
28 Transmitter data.
29 tx_rdy : read-only
30 Transmitter ready. The transmitter FIFO is non-full.
31
32 Events
33 ------
34 rx_rdy : level-triggered
35 Receiver ready. The receiver FIFO is non-empty.
36 rx_err : edge-triggered (rising)
37 Receiver error. Error cause is available in the ``rx_err`` register.
38 tx_mty : edge-triggered (rising)
39 Transmitter empty. The transmitter FIFO is empty.
40
41 Parameters
42 ----------
43 rx_depth : int
44 Depth of the receiver FIFO.
45 tx_depth : int
46 Depth of the transmitter FIFO.
47 divisor : int
48 Clock divisor reset value. Should be set to ``int(clk_frequency // baudrate)``.
49 divisor_bits : int
50 Optional. Clock divisor width. If omitted, ``bits_for(divisor)`` is used instead.
51 data_bits : int
52 Data width.
53 parity : ``"none"``, ``"mark"``, ``"space"``, ``"even"``, ``"odd"``
54 Parity mode.
55 pins : :class:`Record`
56 Optional. UART pins. See :class:`nmigen_boards.resources.UARTResource`.
57
58 Attributes
59 ----------
60 bus : :class:`nmigen_soc.wishbone.Interface`
61 Wishbone bus interface.
62 irq : :class:`IRQLine`
63 Interrupt request line.
64 """
65 def __init__(self, *, rx_depth=16, tx_depth=16, **kwargs):
66 super().__init__()
67
68 self._phy = AsyncSerial(**kwargs)
69 self._rx_fifo = SyncFIFO(width=self._phy.rx.data.width, depth=rx_depth)
70 self._tx_fifo = SyncFIFO(width=self._phy.tx.data.width, depth=tx_depth)
71
72 bank = self.csr_bank()
73 self._divisor = bank.csr(self._phy.divisor.width, "rw")
74 self._rx_data = bank.csr(self._phy.rx.data.width, "r")
75 self._rx_rdy = bank.csr(1, "r")
76 self._rx_err = bank.csr(len(self._phy.rx.err), "r")
77 self._tx_data = bank.csr(self._phy.tx.data.width, "w")
78 self._tx_rdy = bank.csr(1, "r")
79
80 self._rx_rdy_ev = self.event(mode="level")
81 self._rx_err_ev = self.event(mode="rise")
82 self._tx_mty_ev = self.event(mode="rise")
83
84 self._bridge = self.bridge(data_width=32, granularity=8, alignment=2)
85 self.bus = self._bridge.bus
86 self.irq = self._bridge.irq
87
88 def elaborate(self, platform):
89 m = Module()
90 m.submodules.bridge = self._bridge
91
92 m.submodules.phy = self._phy
93 m.submodules.rx_fifo = self._rx_fifo
94 m.submodules.tx_fifo = self._tx_fifo
95
96 m.d.comb += self._divisor.r_data.eq(self._phy.divisor)
97 with m.If(self._divisor.w_stb):
98 m.d.sync += self._phy.divisor.eq(self._divisor.w_data)
99
100 m.d.comb += [
101 self._rx_data.r_data.eq(self._rx_fifo.r_data),
102 self._rx_fifo.r_en.eq(self._rx_data.r_stb),
103 self._rx_rdy.r_data.eq(self._rx_fifo.r_rdy),
104
105 self._rx_fifo.w_data.eq(self._phy.rx.data),
106 self._rx_fifo.w_en.eq(self._phy.rx.rdy),
107 self._phy.rx.ack.eq(self._rx_fifo.w_rdy),
108 self._rx_err.r_data.eq(self._phy.rx.err),
109
110 self._tx_fifo.w_en.eq(self._tx_data.w_stb),
111 self._tx_fifo.w_data.eq(self._tx_data.w_data),
112 self._tx_rdy.r_data.eq(self._tx_fifo.w_rdy),
113
114 self._phy.tx.data.eq(self._tx_fifo.r_data),
115 self._phy.tx.ack.eq(self._tx_fifo.r_rdy),
116 self._tx_fifo.r_en.eq(self._phy.tx.rdy),
117
118 self._rx_rdy_ev.stb.eq(self._rx_fifo.r_rdy),
119 self._rx_err_ev.stb.eq(self._phy.rx.err.any()),
120 self._tx_mty_ev.stb.eq(~self._tx_fifo.r_rdy),
121 ]
122
123 return m