Skip to content

Commit 51ff31e

Browse files
gateware.uart: Create ExternalUART
The previous `UART` implementation required being connected to physical pins, but this change allows specifying an arbitrary `UARTBus` implementation for `UART`s that make no assumptions about what they're connected to.
1 parent 5c017ed commit 51ff31e

5 files changed

Lines changed: 40 additions & 26 deletions

File tree

software/glasgow/applet/interface/uart/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from glasgow.support.arepl import AsyncInteractiveConsole
1111
from glasgow.support.logging import dump_hex
1212
from glasgow.support.endpoint import ServerEndpoint
13-
from glasgow.gateware.uart import UART
13+
from glasgow.gateware.uart import ExternalUART
1414
from glasgow.abstract import AbstractAssembly, GlasgowPin
1515
from glasgow.applet import GlasgowAppletV2
1616

@@ -117,7 +117,8 @@ def elaborate(self, platform):
117117
# TODO: `uart.bit_cyc` is only used to set the width of the register; the actual initial
118118
# value is zero (same as `self.bit_cyc`); this is a footgun and should be fixed by rewriting
119119
# the UART to use lib.wiring
120-
m.submodules.uart = uart = UART(self.ports,
120+
m.submodules.uart = uart = ExternalUART(
121+
self.ports,
121122
bit_cyc=(1 << len(self.manual_cyc)) - 1,
122123
parity=self.parity)
123124
m.submodules.auto_baud = auto_baud = UARTAutoBaud()

software/glasgow/applet/interface/uart_analyzer/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from amaranth.lib.wiring import In, Out
1212

1313
from glasgow.gateware.ports import PortGroup
14-
from glasgow.gateware.uart import UART
14+
from glasgow.gateware.uart import ExternalUART
1515
from glasgow.gateware.stream import Queue
1616
from glasgow.abstract import AbstractAssembly, GlasgowPin, ClockDivisor
1717
from glasgow.applet import GlasgowAppletV2, GlasgowAppletError
@@ -51,8 +51,10 @@ def elaborate(self, platform):
5151

5252
channels = []
5353
for index, pin in enumerate(self._port):
54-
m.submodules[f"ch{index}"] = uart = UART(PortGroup(rx=pin),
55-
bit_cyc=(1 << len(self.periods[index])) - 1, parity=self._parity)
54+
m.submodules[f"ch{index}"] = uart = ExternalUART(
55+
PortGroup(rx=pin),
56+
bit_cyc=(1 << len(self.periods[index])) - 1,
57+
parity=self._parity)
5658
m.d.comb += uart.bit_cyc.eq(self.periods[index] + 1)
5759
channels.append(uart)
5860

software/glasgow/applet/program/m16c/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def __init__(self, ports, out_fifo, in_fifo, bit_cyc, reset, mode, max_bit_cyc):
8080
self.reset = reset
8181
self.mode = mode
8282

83-
self.uart = UART(ports, bit_cyc=max_bit_cyc)
83+
self.uart = ExternalUART(ports, bit_cyc=max_bit_cyc)
8484

8585
def elaborate(self, platform):
8686
m = Module()

software/glasgow/applet/sensor/pmsx003/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def __init__(self, ports, in_fifo, out_fifo):
2727

2828
def elaborate(self, platform):
2929
m = Module()
30-
m.submodules.uart = uart = UART(self.ports,
30+
m.submodules.uart = uart = ExternalUART(
31+
self.ports,
3132
bit_cyc=int(platform.default_clk_frequency // 9600))
3233
m.d.comb += [
3334
self.in_fifo.w_data.eq(uart.rx_data),

software/glasgow/gateware/uart.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from amaranth.lib.cdc import FFSynchronizer
44

55

6-
__all__ = ["UART"]
6+
__all__ = ["UART", "ExternalUART"]
77

88

99
class UARTBus(Elaboratable):
@@ -12,6 +12,7 @@ class UARTBus(Elaboratable):
1212
1313
Provides synchronization.
1414
"""
15+
1516
def __init__(self, ports):
1617
self.ports = ports
1718

@@ -90,7 +91,8 @@ class UART(Elaboratable):
9091
Transmit acknowledgement. If active when ``tx_rdy`` is active, ``tx_rdy`` is reset,
9192
``tx_data`` is sampled, and the transmit state machine starts transmitting a frame.
9293
"""
93-
def __init__(self, ports, bit_cyc, data_bits=8, parity="none", max_bit_cyc=None):
94+
95+
def __init__(self, bus, bit_cyc, data_bits=8, parity="none", max_bit_cyc=None):
9496
if max_bit_cyc is not None:
9597
self.max_bit_cyc = max_bit_cyc
9698
else:
@@ -102,18 +104,18 @@ def __init__(self, ports, bit_cyc, data_bits=8, parity="none", max_bit_cyc=None)
102104
self.bit_cyc = Signal(range(self.max_bit_cyc + 1), init=bit_cyc)
103105

104106
self.rx_data = Signal(data_bits)
105-
self.rx_rdy = Signal()
106-
self.rx_ack = Signal()
107+
self.rx_rdy = Signal()
108+
self.rx_ack = Signal()
107109
self.rx_ferr = Signal()
108110
self.rx_perr = Signal()
109-
self.rx_ovf = Signal()
110-
self.rx_err = Signal()
111+
self.rx_ovf = Signal()
112+
self.rx_err = Signal()
111113

112114
self.tx_data = Signal(data_bits)
113-
self.tx_rdy = Signal()
114-
self.tx_ack = Signal()
115+
self.tx_rdy = Signal()
116+
self.tx_ack = Signal()
115117

116-
self.bus = UARTBus(ports)
118+
self.bus = bus
117119

118120
def elaborate(self, platform):
119121
m = Module()
@@ -139,7 +141,7 @@ def calc_parity(sig, kind):
139141
if self.bus.has_rx:
140142
rx_start = Signal()
141143
rx_timer = Signal(range(self.max_bit_cyc))
142-
rx_stb = Signal()
144+
rx_stb = Signal()
143145
rx_shreg = Signal(self.data_bits)
144146
rx_bitno = Signal(range(len(rx_shreg)))
145147

@@ -199,11 +201,11 @@ def calc_parity(sig, kind):
199201
###
200202

201203
if self.bus.has_tx:
202-
tx_start = Signal()
203-
tx_timer = Signal(range(self.max_bit_cyc))
204-
tx_stb = Signal()
205-
tx_shreg = Signal(self.data_bits)
206-
tx_bitno = Signal(range(len(tx_shreg)))
204+
tx_start = Signal()
205+
tx_timer = Signal(range(self.max_bit_cyc))
206+
tx_stb = Signal()
207+
tx_shreg = Signal(self.data_bits)
208+
tx_bitno = Signal(range(len(tx_shreg)))
207209
tx_parity = Signal()
208210

209211
with m.If(tx_start | (tx_timer == 0)):
@@ -222,15 +224,17 @@ def calc_parity(sig, kind):
222224
self.bus.tx_o.eq(0),
223225
]
224226
if self.parity != "none":
225-
m.d.sync += tx_parity.eq(calc_parity(self.tx_data, self.parity))
227+
m.d.sync += tx_parity.eq(
228+
calc_parity(self.tx_data, self.parity)
229+
)
226230
m.next = "START"
227231
with m.Else():
228232
m.d.sync += self.bus.tx_o.eq(1)
229233
with m.State("START"):
230234
with m.If(tx_stb):
231235
m.d.sync += [
232236
self.bus.tx_o.eq(tx_shreg[0]),
233-
tx_shreg.eq(Cat(tx_shreg[1:], C(0,1))),
237+
tx_shreg.eq(Cat(tx_shreg[1:], C(0, 1))),
234238
]
235239
m.next = "DATA"
236240
with m.State("DATA"):
@@ -239,7 +243,7 @@ def calc_parity(sig, kind):
239243
with m.If(tx_bitno != len(tx_shreg) - 1):
240244
m.d.sync += [
241245
self.bus.tx_o.eq(tx_shreg[0]),
242-
tx_shreg.eq(Cat(tx_shreg[1:], C(0,1))),
246+
tx_shreg.eq(Cat(tx_shreg[1:], C(0, 1))),
243247
]
244248
with m.Else():
245249
if self.parity == "none":
@@ -250,10 +254,16 @@ def calc_parity(sig, kind):
250254
m.next = "PARITY"
251255
with m.State("PARITY"):
252256
with m.If(tx_stb):
253-
m.d.sync += self.bus.tx_o.eq(1),
257+
m.d.sync += (self.bus.tx_o.eq(1),)
254258
m.next = "STOP"
255259
with m.State("STOP"):
256260
with m.If(tx_stb):
257261
m.next = "IDLE"
258262

259263
return m
264+
265+
266+
class ExternalUART(UART):
267+
def __init__(self, ports, *args, **kwargs):
268+
bus = UARTBus(ports)
269+
super().__init__(bus, *args, **kwargs)

0 commit comments

Comments
 (0)