Merge pull request #396 from antmicro/external-wb
Add a script that allows to generate standalone cores
This commit is contained in:
commit
0083e0978b
|
@ -1,4 +1,5 @@
|
||||||
# This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
# This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# This file is Copyright (c) 2020 Karol Gugala <kgugala@antmicro.com>
|
||||||
# License: BSD
|
# License: BSD
|
||||||
|
|
||||||
"""AXI4 Full/Lite support for LiteX"""
|
"""AXI4 Full/Lite support for LiteX"""
|
||||||
|
@ -6,6 +7,7 @@
|
||||||
from migen import *
|
from migen import *
|
||||||
|
|
||||||
from litex.soc.interconnect import stream
|
from litex.soc.interconnect import stream
|
||||||
|
from litex.build.generic_platform import *
|
||||||
|
|
||||||
# AXI Definition -----------------------------------------------------------------------------------
|
# AXI Definition -----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ def r_description(data_width, id_width):
|
||||||
]
|
]
|
||||||
|
|
||||||
class AXIInterface(Record):
|
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.data_width = data_width
|
||||||
self.address_width = address_width
|
self.address_width = address_width
|
||||||
self.id_width = id_width
|
self.id_width = id_width
|
||||||
|
@ -66,6 +68,80 @@ class AXIInterface(Record):
|
||||||
self.ar = stream.Endpoint(ax_description(address_width, id_width))
|
self.ar = stream.Endpoint(ax_description(address_width, id_width))
|
||||||
self.r = stream.Endpoint(r_description(data_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 ------------------------------------------------------------------------------
|
# AXI Lite Definition ------------------------------------------------------------------------------
|
||||||
|
|
||||||
def ax_lite_description(address_width):
|
def ax_lite_description(address_width):
|
||||||
|
|
|
@ -13,6 +13,7 @@ from migen.genlib.misc import split, displacer, chooser, WaitTimer
|
||||||
from migen.genlib.fsm import FSM, NextState
|
from migen.genlib.fsm import FSM, NextState
|
||||||
|
|
||||||
from litex.soc.interconnect import csr
|
from litex.soc.interconnect import csr
|
||||||
|
from litex.build.generic_platform import *
|
||||||
|
|
||||||
# TODO: rewrite without FlipFlop
|
# TODO: rewrite without FlipFlop
|
||||||
|
|
||||||
|
@ -69,6 +70,59 @@ class Interface(Record):
|
||||||
yield from self._do_transaction()
|
yield from self._do_transaction()
|
||||||
return (yield self.dat_r)
|
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):
|
class InterconnectPointToPoint(Module):
|
||||||
def __init__(self, master, slave):
|
def __init__(self, master, slave):
|
||||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue