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:
Florent Kermarrec 2015-03-01 11:58:46 +01:00
parent 9e01bf5fdd
commit bd4d3cd73b
6 changed files with 220 additions and 220 deletions

View File

@ -1,230 +1,30 @@
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.genlib.cdc import MultiReg
from migen.bank.description import * from migen.bank.description import *
from migen.bank.eventmanager import * from migen.bank.eventmanager import *
from migen.genlib.record import Record from migen.genlib.record import Record
from migen.flow.actor import Sink, Source 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): class UART(Module, AutoCSR):
def __init__(self, pads, clk_freq, baud=115200): def __init__(self, phy):
self._rxtx = CSR(8) self._rxtx = CSR(8)
self.submodules.ev = EventManager() self.submodules.ev = EventManager()
self.ev.tx = EventSourcePulse() self.ev.tx = EventSourcePulse()
self.ev.rx = EventSourcePulse() self.ev.rx = EventSourcePulse()
self.ev.finalize() 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 += [ self.sync += [
If(self._rxtx.re, If(self._rxtx.re,
self.tx.sink.stb.eq(1), phy.tx.sink.stb.eq(1),
self.tx.sink.d.eq(self._rxtx.r), phy.tx.sink.d.eq(self._rxtx.r),
).Elif(self.tx.sink.ack, ).Elif(phy.tx.sink.ack,
self.tx.sink.stb.eq(0) phy.tx.sink.stb.eq(0)
), ),
If(self.rx.source.stb, If(phy.rx.source.stb,
self._rxtx.w.eq(self.rx.source.d) self._rxtx.w.eq(phy.rx.source.d)
) )
] ]
self.comb += [ self.comb += [
self.ev.tx.trigger.eq(self.tx.sink.stb & self.tx.sink.ack), self.ev.tx.trigger.eq(phy.tx.sink.stb & phy.tx.sink.ack),
self.ev.rx.trigger.eq(self.rx.source.stb) #self.rx.source.ack supposed to be always 1 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)

View File

View File

@ -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

View File

@ -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)

View File

@ -6,6 +6,7 @@ from migen.fhdl.std import *
from migen.bank import csrgen from migen.bank import csrgen
from migen.bus import wishbone, csr, wishbone2csr from migen.bus import wishbone, csr, wishbone2csr
from misoclib.com.uart.phy.serial import UARTPHYSerial
from misoclib.com import uart from misoclib.com import uart
from misoclib.cpu import CPU, lm32, mor1kx from misoclib.cpu import CPU, lm32, mor1kx
from misoclib.cpu.peripherals import identifier, timer from misoclib.cpu.peripherals import identifier, timer
@ -16,11 +17,12 @@ def mem_decoder(address, start=26, end=29):
class SoC(Module): class SoC(Module):
csr_map = { csr_map = {
"crg": 0, # user "crg": 0, # user
"uart": 1, # provided by default (optional) "uart_phy": 1, # provided by default (optional)
"identifier": 2, # provided by default (optional) "uart": 2, # provided by default (optional)
"timer0": 3, # provided by default (optional) "identifier": 3, # provided by default (optional)
"buttons": 4, # user "timer0": 4, # provided by default (optional)
"leds": 5, # user "buttons": 5, # user
"leds": 6, # user
} }
interrupt_map = { interrupt_map = {
"uart": 0, "uart": 0,
@ -105,7 +107,8 @@ class SoC(Module):
self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone) self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
if with_uart: 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: if with_identifier:
platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier

View File

@ -9,11 +9,11 @@ from misoclib.soc import SoC, mem_decoder
class SDRAMSoC(SoC): class SDRAMSoC(SoC):
csr_map = { csr_map = {
"dfii": 6, "dfii": 7,
"lasmicon": 7, "lasmicon": 8,
"wishbone2lasmi": 8, "wishbone2lasmi": 9,
"memtest_w": 9, "memtest_w": 10,
"memtest_r": 10 "memtest_r": 11
} }
csr_map.update(SoC.csr_map) csr_map.update(SoC.csr_map)