uart: create phy directory and move phy logic to serial.py (will enable selecting uart phy, for example virtual uart with LiteEth or sim model for Verilator)
This commit is contained in:
parent
9e01bf5fdd
commit
bd4d3cd73b
|
@ -1,230 +1,30 @@
|
|||
from migen.fhdl.std import *
|
||||
from migen.genlib.cdc import MultiReg
|
||||
from migen.bank.description import *
|
||||
from migen.bank.eventmanager import *
|
||||
from migen.genlib.record import Record
|
||||
from migen.flow.actor import Sink, Source
|
||||
|
||||
class UARTRX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.source = Source([("d", 8)])
|
||||
|
||||
###
|
||||
|
||||
uart_clk_rxen = Signal()
|
||||
phase_accumulator_rx = Signal(32)
|
||||
|
||||
rx = Signal()
|
||||
self.specials += MultiReg(pads.rx, rx)
|
||||
rx_r = Signal()
|
||||
rx_reg = Signal(8)
|
||||
rx_bitcount = Signal(4)
|
||||
rx_busy = Signal()
|
||||
rx_done = self.source.stb
|
||||
rx_data = self.source.d
|
||||
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(uart_clk_rxen,
|
||||
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(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word)
|
||||
).Else(
|
||||
Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31)
|
||||
)
|
||||
|
||||
class UARTTX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.sink = Sink([("d", 8)])
|
||||
|
||||
###
|
||||
|
||||
uart_clk_txen = Signal()
|
||||
phase_accumulator_tx = Signal(32)
|
||||
|
||||
pads.tx.reset = 1
|
||||
|
||||
tx_reg = Signal(8)
|
||||
tx_bitcount = Signal(4)
|
||||
tx_busy = Signal()
|
||||
self.sync += [
|
||||
self.sink.ack.eq(0),
|
||||
If(self.sink.stb & ~tx_busy & ~self.sink.ack,
|
||||
tx_reg.eq(self.sink.d),
|
||||
tx_bitcount.eq(0),
|
||||
tx_busy.eq(1),
|
||||
pads.tx.eq(0)
|
||||
).Elif(uart_clk_txen & 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.ack.eq(1),
|
||||
).Else(
|
||||
pads.tx.eq(tx_reg[0]),
|
||||
tx_reg.eq(Cat(tx_reg[1:], 0))
|
||||
)
|
||||
)
|
||||
]
|
||||
self.sync += [
|
||||
If(tx_busy,
|
||||
Cat(phase_accumulator_tx, uart_clk_txen).eq(phase_accumulator_tx + tuning_word)
|
||||
).Else(
|
||||
Cat(phase_accumulator_tx, uart_clk_txen).eq(0)
|
||||
)
|
||||
]
|
||||
|
||||
class UART(Module, AutoCSR):
|
||||
def __init__(self, pads, clk_freq, baud=115200):
|
||||
def __init__(self, phy):
|
||||
self._rxtx = CSR(8)
|
||||
|
||||
self.submodules.ev = EventManager()
|
||||
self.ev.tx = EventSourcePulse()
|
||||
self.ev.rx = EventSourcePulse()
|
||||
self.ev.finalize()
|
||||
|
||||
# Tuning word value
|
||||
self._tuning_word = CSRStorage(32, reset=int((baud/clk_freq)*2**32))
|
||||
tuning_word = self._tuning_word.storage
|
||||
|
||||
###
|
||||
|
||||
self.submodules.rx = UARTRX(pads, tuning_word)
|
||||
self.submodules.tx = UARTTX(pads, tuning_word)
|
||||
|
||||
self.sync += [
|
||||
If(self._rxtx.re,
|
||||
self.tx.sink.stb.eq(1),
|
||||
self.tx.sink.d.eq(self._rxtx.r),
|
||||
).Elif(self.tx.sink.ack,
|
||||
self.tx.sink.stb.eq(0)
|
||||
phy.tx.sink.stb.eq(1),
|
||||
phy.tx.sink.d.eq(self._rxtx.r),
|
||||
).Elif(phy.tx.sink.ack,
|
||||
phy.tx.sink.stb.eq(0)
|
||||
),
|
||||
If(self.rx.source.stb,
|
||||
self._rxtx.w.eq(self.rx.source.d)
|
||||
If(phy.rx.source.stb,
|
||||
self._rxtx.w.eq(phy.rx.source.d)
|
||||
)
|
||||
]
|
||||
self.comb += [
|
||||
self.ev.tx.trigger.eq(self.tx.sink.stb & self.tx.sink.ack),
|
||||
self.ev.rx.trigger.eq(self.rx.source.stb) #self.rx.source.ack supposed to be always 1
|
||||
self.ev.tx.trigger.eq(phy.tx.sink.stb & phy.tx.sink.ack),
|
||||
self.ev.rx.trigger.eq(phy.rx.source.stb) #phy.rx.source.ack supposed to be always 1
|
||||
]
|
||||
|
||||
class UARTTB(Module):
|
||||
def __init__(self):
|
||||
self.clk_freq = 83333333
|
||||
self.baud = 3000000
|
||||
self.pads = Record([("rx", 1), ("tx", 1)])
|
||||
self.submodules.slave = UART(self.pads, self.clk_freq, self.baud)
|
||||
|
||||
def wait_for(self, ns_time):
|
||||
freq_in_ghz = self.clk_freq/(10**9)
|
||||
period = 1/freq_in_ghz
|
||||
num_loops = int(ns_time/period)
|
||||
for i in range(num_loops+1):
|
||||
yield
|
||||
|
||||
def gen_simulation(self, selfp):
|
||||
baud_in_ghz = self.baud/(10**9)
|
||||
uart_period = int(1/baud_in_ghz)
|
||||
half_uart_period = int(1/(2*baud_in_ghz))
|
||||
|
||||
# Set TX an RX lines idle
|
||||
selfp.pads.tx = 1
|
||||
selfp.pads.rx = 1
|
||||
yield
|
||||
|
||||
# First send a few characters
|
||||
|
||||
tx_string = "01234"
|
||||
print("Sending string: " + tx_string)
|
||||
for c in tx_string:
|
||||
selfp.slave._r_rxtx.r = ord(c)
|
||||
selfp.slave._r_rxtx.re = 1
|
||||
yield
|
||||
selfp.slave._r_rxtx.re = 0
|
||||
|
||||
yield from self.wait_for(half_uart_period)
|
||||
|
||||
if selfp.pads.tx:
|
||||
print("FAILURE: no start bit sent")
|
||||
|
||||
val = 0
|
||||
for i in range(8):
|
||||
yield from self.wait_for(uart_period)
|
||||
val >>= 1
|
||||
if selfp.pads.tx:
|
||||
val |= 0x80
|
||||
|
||||
yield from self.wait_for(uart_period)
|
||||
|
||||
if selfp.pads.tx == 0:
|
||||
print("FAILURE: no stop bit sent")
|
||||
|
||||
if ord(c) != val:
|
||||
print("FAILURE: sent decimal value "+str(val)+" (char "+chr(val)+") instead of "+c)
|
||||
else:
|
||||
print("SUCCESS: sent "+c)
|
||||
while selfp.slave.ev.tx.trigger != 1:
|
||||
yield
|
||||
|
||||
# Then receive a character
|
||||
|
||||
rx_string = '5'
|
||||
print("Receiving character "+rx_string)
|
||||
rx_value = ord(rx_string)
|
||||
for i in range(11):
|
||||
if (i == 0):
|
||||
# start bit
|
||||
selfp.pads.rx = 0
|
||||
elif (i == 9):
|
||||
# stop bit
|
||||
selfp.pads.rx = 1
|
||||
elif (i == 10):
|
||||
selfp.pads.rx = 1
|
||||
break
|
||||
else:
|
||||
selfp.pads.rx = 1 if (rx_value & 1) else 0
|
||||
rx_value >>= 1
|
||||
yield from self.wait_for(uart_period)
|
||||
|
||||
rx_value = ord(rx_string)
|
||||
received_value = selfp.slave._r_rxtx.w
|
||||
if (received_value == rx_value):
|
||||
print("RX SUCCESS: ")
|
||||
else:
|
||||
print("RX FAILURE: ")
|
||||
|
||||
print("received "+chr(received_value))
|
||||
|
||||
while True:
|
||||
yield
|
||||
|
||||
if __name__ == "__main__":
|
||||
from migen.sim.generic import Simulator, TopLevel
|
||||
from migen.sim import icarus
|
||||
with Simulator(UARTTB(), TopLevel("top.vcd", clk_period=int(1/0.08333333)), icarus.Runner(keep_files=False)) as s:
|
||||
s.run(20000)
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
from migen.fhdl.std import *
|
||||
from migen.genlib.cdc import MultiReg
|
||||
from migen.bank.description import *
|
||||
from migen.flow.actor import Sink, Source
|
||||
|
||||
class UARTPHYSerialRX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.source = Source([("d", 8)])
|
||||
###
|
||||
uart_clk_rxen = Signal()
|
||||
phase_accumulator_rx = Signal(32)
|
||||
|
||||
rx = Signal()
|
||||
self.specials += MultiReg(pads.rx, rx)
|
||||
rx_r = Signal()
|
||||
rx_reg = Signal(8)
|
||||
rx_bitcount = Signal(4)
|
||||
rx_busy = Signal()
|
||||
rx_done = self.source.stb
|
||||
rx_data = self.source.d
|
||||
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(uart_clk_rxen,
|
||||
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(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word)
|
||||
).Else(
|
||||
Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31)
|
||||
)
|
||||
|
||||
class UARTPHYSerialTX(Module):
|
||||
def __init__(self, pads, tuning_word):
|
||||
self.sink = Sink([("d", 8)])
|
||||
###
|
||||
uart_clk_txen = Signal()
|
||||
phase_accumulator_tx = Signal(32)
|
||||
|
||||
pads.tx.reset = 1
|
||||
|
||||
tx_reg = Signal(8)
|
||||
tx_bitcount = Signal(4)
|
||||
tx_busy = Signal()
|
||||
self.sync += [
|
||||
self.sink.ack.eq(0),
|
||||
If(self.sink.stb & ~tx_busy & ~self.sink.ack,
|
||||
tx_reg.eq(self.sink.d),
|
||||
tx_bitcount.eq(0),
|
||||
tx_busy.eq(1),
|
||||
pads.tx.eq(0)
|
||||
).Elif(uart_clk_txen & 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.ack.eq(1),
|
||||
).Else(
|
||||
pads.tx.eq(tx_reg[0]),
|
||||
tx_reg.eq(Cat(tx_reg[1:], 0))
|
||||
)
|
||||
)
|
||||
]
|
||||
self.sync += [
|
||||
If(tx_busy,
|
||||
Cat(phase_accumulator_tx, uart_clk_txen).eq(phase_accumulator_tx + tuning_word)
|
||||
).Else(
|
||||
Cat(phase_accumulator_tx, uart_clk_txen).eq(0)
|
||||
)
|
||||
]
|
||||
|
||||
class UARTPHYSerial(Module, AutoCSR):
|
||||
def __init__(self, pads, clk_freq, baudrate=115200):
|
||||
self._tuning_word = CSRStorage(32, reset=int((baudrate/clk_freq)*2**32))
|
||||
self.submodules.tx = UARTPHYSerialTX(pads, self._tuning_word.storage)
|
||||
self.submodules.rx = UARTPHYSerialRX(pads, self._tuning_word.storage)
|
||||
self.sink, self.source = self.tx.sink, self.rx.source
|
|
@ -0,0 +1,96 @@
|
|||
# XXX Adapt test to new architecture
|
||||
class UARTTB(Module):
|
||||
def __init__(self):
|
||||
self.clk_freq = 83333333
|
||||
self.baud = 3000000
|
||||
self.pads = Record([("rx", 1), ("tx", 1)])
|
||||
self.submodules.slave = UART(self.pads, self.clk_freq, self.baud)
|
||||
|
||||
def wait_for(self, ns_time):
|
||||
freq_in_ghz = self.clk_freq/(10**9)
|
||||
period = 1/freq_in_ghz
|
||||
num_loops = int(ns_time/period)
|
||||
for i in range(num_loops+1):
|
||||
yield
|
||||
|
||||
def gen_simulation(self, selfp):
|
||||
baud_in_ghz = self.baud/(10**9)
|
||||
uart_period = int(1/baud_in_ghz)
|
||||
half_uart_period = int(1/(2*baud_in_ghz))
|
||||
|
||||
# Set TX an RX lines idle
|
||||
selfp.pads.tx = 1
|
||||
selfp.pads.rx = 1
|
||||
yield
|
||||
|
||||
# First send a few characters
|
||||
|
||||
tx_string = "01234"
|
||||
print("Sending string: " + tx_string)
|
||||
for c in tx_string:
|
||||
selfp.slave._r_rxtx.r = ord(c)
|
||||
selfp.slave._r_rxtx.re = 1
|
||||
yield
|
||||
selfp.slave._r_rxtx.re = 0
|
||||
|
||||
yield from self.wait_for(half_uart_period)
|
||||
|
||||
if selfp.pads.tx:
|
||||
print("FAILURE: no start bit sent")
|
||||
|
||||
val = 0
|
||||
for i in range(8):
|
||||
yield from self.wait_for(uart_period)
|
||||
val >>= 1
|
||||
if selfp.pads.tx:
|
||||
val |= 0x80
|
||||
|
||||
yield from self.wait_for(uart_period)
|
||||
|
||||
if selfp.pads.tx == 0:
|
||||
print("FAILURE: no stop bit sent")
|
||||
|
||||
if ord(c) != val:
|
||||
print("FAILURE: sent decimal value "+str(val)+" (char "+chr(val)+") instead of "+c)
|
||||
else:
|
||||
print("SUCCESS: sent "+c)
|
||||
while selfp.slave.ev.tx.trigger != 1:
|
||||
yield
|
||||
|
||||
# Then receive a character
|
||||
|
||||
rx_string = '5'
|
||||
print("Receiving character "+rx_string)
|
||||
rx_value = ord(rx_string)
|
||||
for i in range(11):
|
||||
if (i == 0):
|
||||
# start bit
|
||||
selfp.pads.rx = 0
|
||||
elif (i == 9):
|
||||
# stop bit
|
||||
selfp.pads.rx = 1
|
||||
elif (i == 10):
|
||||
selfp.pads.rx = 1
|
||||
break
|
||||
else:
|
||||
selfp.pads.rx = 1 if (rx_value & 1) else 0
|
||||
rx_value >>= 1
|
||||
yield from self.wait_for(uart_period)
|
||||
|
||||
rx_value = ord(rx_string)
|
||||
received_value = selfp.slave._r_rxtx.w
|
||||
if (received_value == rx_value):
|
||||
print("RX SUCCESS: ")
|
||||
else:
|
||||
print("RX FAILURE: ")
|
||||
|
||||
print("received "+chr(received_value))
|
||||
|
||||
while True:
|
||||
yield
|
||||
|
||||
if __name__ == "__main__":
|
||||
from migen.sim.generic import Simulator, TopLevel
|
||||
from migen.sim import icarus
|
||||
with Simulator(UARTTB(), TopLevel("top.vcd", clk_period=int(1/0.08333333)), icarus.Runner(keep_files=False)) as s:
|
||||
s.run(20000)
|
|
@ -6,6 +6,7 @@ from migen.fhdl.std import *
|
|||
from migen.bank import csrgen
|
||||
from migen.bus import wishbone, csr, wishbone2csr
|
||||
|
||||
from misoclib.com.uart.phy.serial import UARTPHYSerial
|
||||
from misoclib.com import uart
|
||||
from misoclib.cpu import CPU, lm32, mor1kx
|
||||
from misoclib.cpu.peripherals import identifier, timer
|
||||
|
@ -16,11 +17,12 @@ def mem_decoder(address, start=26, end=29):
|
|||
class SoC(Module):
|
||||
csr_map = {
|
||||
"crg": 0, # user
|
||||
"uart": 1, # provided by default (optional)
|
||||
"identifier": 2, # provided by default (optional)
|
||||
"timer0": 3, # provided by default (optional)
|
||||
"buttons": 4, # user
|
||||
"leds": 5, # user
|
||||
"uart_phy": 1, # provided by default (optional)
|
||||
"uart": 2, # provided by default (optional)
|
||||
"identifier": 3, # provided by default (optional)
|
||||
"timer0": 4, # provided by default (optional)
|
||||
"buttons": 5, # user
|
||||
"leds": 6, # user
|
||||
}
|
||||
interrupt_map = {
|
||||
"uart": 0,
|
||||
|
@ -105,7 +107,8 @@ class SoC(Module):
|
|||
self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
|
||||
|
||||
if with_uart:
|
||||
self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=uart_baudrate)
|
||||
self.submodules.uart_phy = UARTPHYSerial(platform.request("serial"), clk_freq, uart_baudrate)
|
||||
self.submodules.uart = uart.UART(self.uart_phy)
|
||||
|
||||
if with_identifier:
|
||||
platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier
|
||||
|
|
|
@ -9,11 +9,11 @@ from misoclib.soc import SoC, mem_decoder
|
|||
|
||||
class SDRAMSoC(SoC):
|
||||
csr_map = {
|
||||
"dfii": 6,
|
||||
"lasmicon": 7,
|
||||
"wishbone2lasmi": 8,
|
||||
"memtest_w": 9,
|
||||
"memtest_r": 10
|
||||
"dfii": 7,
|
||||
"lasmicon": 8,
|
||||
"wishbone2lasmi": 9,
|
||||
"memtest_w": 10,
|
||||
"memtest_r": 11
|
||||
}
|
||||
csr_map.update(SoC.csr_map)
|
||||
|
||||
|
|
Loading…
Reference in New Issue