cores/uart: rewrite RS232PHYTX/RX (with FSM and comments) and optimize resource usage (~100LCs).
This commit is contained in:
parent
7c7f540488
commit
908e72e65b
|
@ -31,104 +31,121 @@ class UARTInterface:
|
|||
|
||||
# RS232 PHY ----------------------------------------------------------------------------------------
|
||||
|
||||
class RS232PHYInterface(UARTInterface):
|
||||
pass
|
||||
RS232_IDLE = 1
|
||||
RS232_START = 0
|
||||
RS232_STOP = 1
|
||||
|
||||
class RS232PHYRX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.source = stream.Endpoint([("data", 8)])
|
||||
class RS232PHYInterface(UARTInterface): pass
|
||||
|
||||
|
||||
class RS232ClkPhaseAccum(Module):
|
||||
def __init__(self, tuning_word, mode="tx"):
|
||||
assert mode in ["tx", "rx"]
|
||||
self.enable = Signal()
|
||||
self.tick = Signal(32)
|
||||
|
||||
# # #
|
||||
|
||||
rx_clken = Signal()
|
||||
rx_clkphase = Signal(32, reset_less=True)
|
||||
|
||||
rx = Signal()
|
||||
rx_r = Signal()
|
||||
rx_reg = Signal(8, reset_less=True)
|
||||
rx_bitcount = Signal(4, reset_less=True)
|
||||
rx_busy = Signal()
|
||||
rx_done = self.source.valid
|
||||
rx_data = self.source.data
|
||||
self.specials += MultiReg(pads.rx, rx)
|
||||
self.sync += [
|
||||
rx_done.eq(0),
|
||||
rx_r.eq(rx),
|
||||
If(~rx_busy,
|
||||
If(~rx & rx_r, # look for start bit
|
||||
rx_busy.eq(1),
|
||||
rx_bitcount.eq(0),
|
||||
)
|
||||
).Else(
|
||||
If(rx_clken,
|
||||
rx_bitcount.eq(rx_bitcount + 1),
|
||||
If(rx_bitcount == 0,
|
||||
If(rx, # verify start bit
|
||||
rx_busy.eq(0)
|
||||
)
|
||||
).Elif(rx_bitcount == 9,
|
||||
rx_busy.eq(0),
|
||||
If(rx, # verify stop bit
|
||||
rx_data.eq(rx_reg),
|
||||
rx_done.eq(1)
|
||||
)
|
||||
).Else(
|
||||
rx_reg.eq(Cat(rx_reg[1:], rx))
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
self.sync += [
|
||||
If(rx_busy,
|
||||
Cat(rx_clkphase, rx_clken).eq(rx_clkphase + tuning_word)
|
||||
).Else(
|
||||
Cat(rx_clkphase, rx_clken).eq(2**31)
|
||||
)
|
||||
]
|
||||
phase = Signal(32)
|
||||
self.sync += Cat(phase, self.tick).eq(tuning_word if mode == "tx" else 2**31)
|
||||
self.sync += If(self.enable, Cat(phase, self.tick).eq(phase + tuning_word))
|
||||
|
||||
|
||||
class RS232PHYTX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.sink = stream.Endpoint([("data", 8)])
|
||||
self.sink = sink = stream.Endpoint([("data", 8)])
|
||||
|
||||
# # #
|
||||
|
||||
tx_clken = Signal()
|
||||
tx_clkphase = Signal(32, reset_less=True)
|
||||
data = Signal(8, reset_less=True)
|
||||
count = Signal(4, reset_less=True)
|
||||
|
||||
pads.tx.reset = 1
|
||||
# Clock Phase Accumulator.
|
||||
clk_phase_accum = RS232ClkPhaseAccum(tuning_word, mode="tx")
|
||||
self.submodules += clk_phase_accum
|
||||
|
||||
tx_reg = Signal(8, reset_less=True)
|
||||
tx_bitcount = Signal(4, reset_less=True)
|
||||
tx_busy = Signal()
|
||||
self.sync += [
|
||||
self.sink.ready.eq(0),
|
||||
If(self.sink.valid & ~tx_busy & ~self.sink.ready,
|
||||
tx_reg.eq(self.sink.data),
|
||||
tx_bitcount.eq(0),
|
||||
tx_busy.eq(1),
|
||||
pads.tx.eq(0)
|
||||
).Elif(tx_clken & tx_busy,
|
||||
tx_bitcount.eq(tx_bitcount + 1),
|
||||
If(tx_bitcount == 8,
|
||||
pads.tx.eq(1)
|
||||
).Elif(tx_bitcount == 9,
|
||||
pads.tx.eq(1),
|
||||
tx_busy.eq(0),
|
||||
self.sink.ready.eq(1),
|
||||
).Else(
|
||||
pads.tx.eq(tx_reg[0]),
|
||||
tx_reg.eq(Cat(tx_reg[1:], 0))
|
||||
|
||||
# FSM
|
||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||
fsm.act("IDLE",
|
||||
# Reset Count and set TX to Idle.
|
||||
NextValue(count, 0),
|
||||
NextValue(pads.tx, RS232_IDLE),
|
||||
# Wait for TX data to transmit.
|
||||
If(sink.valid,
|
||||
NextValue(pads.tx, RS232_START),
|
||||
NextValue(data, sink.data),
|
||||
NextState("RUN")
|
||||
)
|
||||
)
|
||||
fsm.act("RUN",
|
||||
# Enable Clock Phase Accumulator.
|
||||
clk_phase_accum.enable.eq(1),
|
||||
# On Clock Phase Accumulator tick:
|
||||
If(clk_phase_accum.tick,
|
||||
# Set TX data.
|
||||
NextValue(pads.tx, data),
|
||||
# Increment Count.
|
||||
NextValue(count, count + 1),
|
||||
# Shift TX data.
|
||||
NextValue(data, Cat(data[1:], RS232_STOP)),
|
||||
# When 10-bit have been transmitted...
|
||||
If(count == (10 - 1),
|
||||
# Ack sink and return to Idle.
|
||||
sink.ready.eq(1),
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
]
|
||||
self.sync += [
|
||||
If(tx_busy,
|
||||
Cat(tx_clkphase, tx_clken).eq(tx_clkphase + tuning_word)
|
||||
).Else(
|
||||
Cat(tx_clkphase, tx_clken).eq(tuning_word)
|
||||
)
|
||||
|
||||
|
||||
class RS232PHYRX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.source = source = stream.Endpoint([("data", 8)])
|
||||
|
||||
# # #
|
||||
|
||||
data = Signal(8, reset_less=True)
|
||||
count = Signal(4, reset_less=True)
|
||||
|
||||
# Clock Phase Accumulator.
|
||||
clk_phase_accum = RS232ClkPhaseAccum(tuning_word, mode="rx")
|
||||
self.submodules += clk_phase_accum
|
||||
|
||||
# Resynchronize pads.rx and generate delayed version.
|
||||
rx = Signal()
|
||||
rx_d = Signal()
|
||||
self.specials += MultiReg(pads.rx, rx)
|
||||
self.sync += rx_d.eq(rx)
|
||||
|
||||
# FSM
|
||||
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||
fsm.act("IDLE",
|
||||
# Reset Count.
|
||||
NextValue(count, 0),
|
||||
# Wait for RX Start bit.
|
||||
If((rx == RS232_START) & (rx_d == RS232_IDLE),
|
||||
NextState("RUN")
|
||||
)
|
||||
]
|
||||
)
|
||||
fsm.act("RUN",
|
||||
# Enable Clock Phase Accumulator.
|
||||
clk_phase_accum.enable.eq(1),
|
||||
# On Clock Phase Accumulator tick:
|
||||
If(clk_phase_accum.tick,
|
||||
# Increment Count.
|
||||
NextValue(count, count + 1),
|
||||
# Shift RX data.
|
||||
NextValue(data, Cat(data[1:], rx)),
|
||||
# When 10-bit have been received...
|
||||
If(count == (10 - 1),
|
||||
# Produce data (but only when RX Stop bit is seen).
|
||||
source.valid.eq(rx == RS232_STOP),
|
||||
source.data.eq(data),
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class RS232PHY(Module, AutoCSR):
|
||||
|
|
Loading…
Reference in New Issue