From bd4d3cd73ba9d4033092d3bb77c42f1d75c2f8bf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 1 Mar 2015 11:58:46 +0100 Subject: [PATCH] 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) --- misoclib/com/uart/__init__.py | 218 +--------------------- misoclib/com/uart/phy/__init__.py | 0 misoclib/com/uart/phy/serial.py | 101 ++++++++++ misoclib/com/uart/test/test_serial_phy.py | 96 ++++++++++ misoclib/soc/__init__.py | 15 +- misoclib/soc/sdram.py | 10 +- 6 files changed, 220 insertions(+), 220 deletions(-) create mode 100644 misoclib/com/uart/phy/__init__.py create mode 100644 misoclib/com/uart/phy/serial.py create mode 100644 misoclib/com/uart/test/test_serial_phy.py diff --git a/misoclib/com/uart/__init__.py b/misoclib/com/uart/__init__.py index ae82797e1..44a74e062 100644 --- a/misoclib/com/uart/__init__.py +++ b/misoclib/com/uart/__init__.py @@ -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) diff --git a/misoclib/com/uart/phy/__init__.py b/misoclib/com/uart/phy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/misoclib/com/uart/phy/serial.py b/misoclib/com/uart/phy/serial.py new file mode 100644 index 000000000..35f5b7d80 --- /dev/null +++ b/misoclib/com/uart/phy/serial.py @@ -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 diff --git a/misoclib/com/uart/test/test_serial_phy.py b/misoclib/com/uart/test/test_serial_phy.py new file mode 100644 index 000000000..e7185c9a9 --- /dev/null +++ b/misoclib/com/uart/test/test_serial_phy.py @@ -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) diff --git a/misoclib/soc/__init__.py b/misoclib/soc/__init__.py index f7d479a0a..b6ac22f83 100644 --- a/misoclib/soc/__init__.py +++ b/misoclib/soc/__init__.py @@ -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 diff --git a/misoclib/soc/sdram.py b/misoclib/soc/sdram.py index c8534329f..3dead170f 100644 --- a/misoclib/soc/sdram.py +++ b/misoclib/soc/sdram.py @@ -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)