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