From e0bcb57d3d0b905502502733ffd9b9531d2cc8df Mon Sep 17 00:00:00 2001 From: Jan Kowalewski Date: Thu, 13 Feb 2020 16:41:11 +0100 Subject: [PATCH 1/3] wishbone: add extracting module signals to the top --- litex/soc/interconnect/wishbone.py | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index a77d60cca..a1f6d2493 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -13,6 +13,7 @@ from migen.genlib.misc import split, displacer, chooser, WaitTimer from migen.genlib.fsm import FSM, NextState from litex.soc.interconnect import csr +from litex.build.generic_platform import * # TODO: rewrite without FlipFlop @@ -69,6 +70,59 @@ class Interface(Record): yield from self._do_transaction() return (yield self.dat_r) + def _signals_in_channels(self, channels): + for channel_name in channels: + s = getattr(self, channel_name) + for l in _layout: + if l[0] == channel_name: + yield channel_name, s.nbits, l[2] + + def to_pads(self, bus_name='wb'): + wb_bus = {} + for name, width, direction in self._signals_in_channels(['adr', 'dat_w', 'dat_r', + 'sel', 'cyc', 'stb', 'ack', + 'we', 'cti', 'bte', 'err']): + signal_name = name + wb_bus[signal_name] = width + + signals = [] + for pad in wb_bus: + signals.append(Subsignal(pad, Pins(wb_bus[pad]))) + + pads = [ + (bus_name , 0) + tuple(signals) + ] + print(pads) + return pads + + def connect_to_pads(self, module, platform, bus_name, mode='master'): + + def _get_signals(pads, name): + signal_name = name + wb_signal = getattr(self, signal_name) + pads_signal = getattr(pads, signal_name) + return pads_signal, wb_signal + + wb_pads = self.to_pads(bus_name) + platform.add_extension(wb_pads) + pads = platform.request(bus_name) + + for name, width, direction in self._signals_in_channels(['adr', 'dat_w', 'dat_r', + 'sel', 'cyc', 'stb', 'ack', + 'we', 'cti', 'bte', 'err']): + pads_signal, wb_signal = _get_signals(pads, name) + + if mode == 'master': + if direction == DIR_M_TO_S: + module.comb += pads_signal.eq(wb_signal) + else: + module.comb += wb_signal.eq(pads_signal) + else: + if direction == DIR_S_TO_M: + module.comb += pads_signal.eq(wb_signal) + else: + module.comb += wb_signal.eq(pads_signal) + class InterconnectPointToPoint(Module): def __init__(self, master, slave): From 79a14001b0819e974cf2222c24872fbb3f38c6ba Mon Sep 17 00:00:00 2001 From: Karol Gugala Date: Mon, 3 Feb 2020 14:38:24 +0100 Subject: [PATCH 2/3] axi: add to_pads method Signed-off-by: Karol Gugala --- litex/soc/interconnect/axi.py | 78 ++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/litex/soc/interconnect/axi.py b/litex/soc/interconnect/axi.py index 2681ff5ae..a118970ea 100644 --- a/litex/soc/interconnect/axi.py +++ b/litex/soc/interconnect/axi.py @@ -1,4 +1,5 @@ # This file is Copyright (c) 2018-2019 Florent Kermarrec +# This file is Copyright (c) 2020 Karol Gugala # License: BSD """AXI4 Full/Lite support for LiteX""" @@ -6,6 +7,7 @@ from migen import * from litex.soc.interconnect import stream +from litex.build.generic_platform import * # AXI Definition ----------------------------------------------------------------------------------- @@ -54,7 +56,7 @@ def r_description(data_width, id_width): ] class AXIInterface(Record): - def __init__(self, data_width, address_width, id_width=1, clock_domain="sys"): + def __init__(self, data_width, address_width, mode="master", id_width=1, clock_domain="sys"): self.data_width = data_width self.address_width = address_width self.id_width = id_width @@ -66,6 +68,80 @@ class AXIInterface(Record): self.ar = stream.Endpoint(ax_description(address_width, id_width)) self.r = stream.Endpoint(r_description(data_width, id_width)) + def _signals_in_channels(self, channels): + for channel_name in channels: + channel = getattr(self, channel_name) + for signal in channel.layout: + if signal[0] == 'param': + continue + if signal[0] == 'payload': + for s in signal[1]: + yield s[0], channel_name, s[1], s[2] + else: + if signal[0] == 'first': + continue + if signal[0] == 'last' and channel_name != 'w' and channel_name != 'r': + continue + yield signal[0], channel_name, signal[1], signal[2] + + + def to_pads(self, bus_name='axi'): + axi_bus = {} + for signal, channel, width, direction in self._signals_in_channels(['aw', 'w', 'b', 'ar', 'r']): + signal_name = channel + signal + axi_bus[signal_name] = width + + signals = [] + for pad in axi_bus: + signals.append(Subsignal(pad, Pins(axi_bus[pad]))) + + pads = [ + (bus_name , 0) + tuple(signals) + ] + return pads + + def connect_to_pads(self, module, platform, bus_name, mode='master'): + + def _get_signals(pads, channel, signal): + signal_name = channel + signal + channel = getattr(self, channel) + axi_signal = getattr(channel, signal) + pads_signal = getattr(pads, signal_name) + return pads_signal, axi_signal + + axi_pads = self.to_pads(bus_name) + platform.add_extension(axi_pads) + pads = platform.request(bus_name) + + for signal, channel, width, direction in self._signals_in_channels(['aw', 'w', 'ar']): + pads_signal, axi_signal = _get_signals(pads, channel, signal) + + if mode == 'master': + if direction == DIR_M_TO_S: + module.comb += pads_signal.eq(axi_signal) + else: + module.comb += axi_signal.eq(pads_signal) + else: + if direction == DIR_S_TO_M: + module.comb += pads_signal.eq(axi_signal) + else: + module.comb += axi_signal.eq(pads_signal) + + for signal, channel, width, direction in self._signals_in_channels(['r', 'b']): + pads_signal, axi_signal = _get_signals(pads, channel, signal) + + if mode == 'master': + if direction == DIR_S_TO_M: + module.comb += pads_signal.eq(axi_signal) + else: + module.comb += axi_signal.eq(pads_signal) + else: + if direction == DIR_M_TO_S: + module.comb += pads_signal.eq(axi_signal) + else: + module.comb += axi_signal.eq(pads_signal) + + # AXI Lite Definition ------------------------------------------------------------------------------ def ax_lite_description(address_width): From 9e2aede8a8bf3cfdc31a76f42a3f0a3b8485bb40 Mon Sep 17 00:00:00 2001 From: Piotr Binkowski Date: Fri, 21 Feb 2020 14:43:15 +0100 Subject: [PATCH 3/3] tools: add script for extracting wishbone cores --- litex/tools/litex_extract.py | 143 +++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100755 litex/tools/litex_extract.py diff --git a/litex/tools/litex_extract.py b/litex/tools/litex_extract.py new file mode 100755 index 000000000..b77e881f8 --- /dev/null +++ b/litex/tools/litex_extract.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +import argparse + +from migen import * + +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.interconnect import wishbone + +from litex.soc.cores.pwm import PWM +from litex.soc.cores.gpio import GPIOTristate +from litex.soc.cores.spi import SPIMaster, SPISlave +from litex.build.generic_platform import * + +class Platform(GenericPlatform): + def __init__(self, io): + GenericPlatform.__init__(self, "extractor", io) + + def build(self, fragment, build_dir="build", **kwargs): + os.makedirs(build_dir, exist_ok=True) + os.chdir(build_dir) + + top_output = self.get_verilog(fragment) + top_file = "top.v" + + top_output.write(top_file) + +_io = [ + ("sys_clk", 0, Pins(1)), + ("sys_rst", 0, Pins(1)), + ("serial", 0, + Subsignal("rx", Pins(1)), + Subsignal("tx", Pins(1)), + ), + ("pwm", 0, Pins(1)), +] + +class BaseSoC(SoCMini): + SoCMini.mem_map["csr"] = 0x00000000 + def __init__(self, sys_clk_freq=int(100e6), + with_pwm=False, + with_gpio=False, gpio_width=32, + with_spi_master=False, spi_master_data_width=8, spi_master_clk_freq=8e6, + **kwargs): + + platform = Platform(_io) + + kwargs["integrated_rom_size"] = 0 + kwargs["integrated_sram_size"] = 0 + + # CRG ------------------------------------------------------------------------------------- + self.submodules.crg = CRG(platform.request("sys_clk"), rst=platform.request("sys_rst")) + + # SoCMini --------------------------------------------------------------------------------- + SoCMini.__init__(self, platform, clk_freq=sys_clk_freq, **kwargs) + + if with_spi_master: + platform.add_extension([("spi_m", 0, + Subsignal("clk", Pins(1)), + Subsignal("cs_n", Pins(1)), + Subsignal("mosi", Pins(1)), + Subsignal("miso", Pins(1)), + )]) + self.submodules.spi_m = SPIMaster( + platform.request("spi_m"), + spi_master_data_width, + sys_clk_freq, + spi_master_clk_freq, + ) + self.add_csr("spi_m") + + if with_pwm: + self.submodules.pwm = PWM(platform.request("pwm")) + self.add_csr('pwm') + + if with_gpio: + platform.add_extension([("gpio", 0, Pins(gpio_width))]) + self.submodules.gpio = GPIOTristate(platform.request("gpio")) + self.add_csr('gpio') + + self.wb_bus = wishbone.Interface() + self.bus.add_master(name="wb_master", master=self.wb_bus) + self.wb_bus.connect_to_pads(self, platform, 'wb', mode='slave') + + for name, loc in sorted(self.irq.locs.items()): + module = getattr(self, name) + platform.add_extension([("irq_"+name, 0, Pins(1))]) + irq_pin = platform.request("irq_"+name) + self.comb += irq_pin.eq(module.ev.irq) + +# Build ------------------------------------------------------------------------------------------- + +def soc_argdict(args): + ret = {} + for arg in ["with_pwm", "with_uart", "with_ctrl", "with_timer", + "with_gpio", "gpio_width", + "with_spi_master", "spi_master_data_width", "spi_master_clk_freq", + "csr_data_width", "csr_address_width", "csr_paging"]: + ret[arg] = getattr(args, arg) + return ret + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC") + builder_args(parser) + + # Cores + parser.add_argument("--with-pwm", action="store_true", + help="Add PWM core") + parser.add_argument("--with-uart", action="store_true", + help="Add UART core") + parser.add_argument("--with-ctrl", action="store_true", + help="Add bus controller core") + parser.add_argument("--with-timer", action="store_true", + help="Add timer core") + parser.add_argument("--with-spi-master", action="store_true", + help="Add SPI master core") + parser.add_argument("--spi-master-data-width", default=8, type=int, + help="SPI master data width") + parser.add_argument("--spi-master-clk-freq", default=8e6, type=int, + help="SPI master output clock frequency") + parser.add_argument("--with-gpio", action="store_true", + help="Add GPIO core") + parser.add_argument("--gpio-width", default=32, type=int, + help="GPIO signals width") + + # CSR settings + parser.add_argument("--csr-data-width", default=8, type=int, + help="CSR bus data-width (8 or 32, default=8)") + parser.add_argument("--csr-address-width", default=14, type=int, + help="CSR bus address-width") + parser.add_argument("--csr-paging", default=0x800, type=int, + help="CSR bus paging") + + args = parser.parse_args() + + soc = BaseSoC(**soc_argdict(args)) + builder = Builder(soc, **builder_argdict(args)) + builder.build() + + +if __name__ == "__main__": + main()