From: Florent Kermarrec Date: Thu, 5 Feb 2015 10:02:46 +0000 (+0100) Subject: add udpip target for hw tests (untested) X-Git-Tag: 24jan2021_ls180~2604^2~84 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=afae3f0f0050e8649ef8948ed1aed739c97c360d;p=litex.git add udpip target for hw tests (untested) --- diff --git a/liteeth/core/__init__.py b/liteeth/core/__init__.py index 3189a1f8..14e01fdd 100644 --- a/liteeth/core/__init__.py +++ b/liteeth/core/__init__.py @@ -6,7 +6,6 @@ from liteeth.core.udp import LiteEthUDP class LiteEthIPCore(Module, AutoCSR): def __init__(self, phy, mac_address, ip_address): - self.phy = phy self.submodules.mac = LiteEthMAC(phy, 8, interface="crossbar", with_hw_preamble_crc=True) self.submodules.arp = LiteEthARP(self.mac, mac_address, ip_address) self.submodules.ip = LiteEthIP(self.mac, mac_address, ip_address, self.arp.table) diff --git a/liteeth/mac/__init__.py b/liteeth/mac/__init__.py index 6176190c..10a090f3 100644 --- a/liteeth/mac/__init__.py +++ b/liteeth/mac/__init__.py @@ -25,7 +25,7 @@ class LiteEthMAC(Module, AutoCSR): def __init__(self, phy, dw, interface="crossbar", endianness="be", with_hw_preamble_crc=True): self.submodules.core = LiteEthMACCore(phy, dw, endianness, with_hw_preamble_crc) - self.csrs = None + self.csrs = [] if interface == "crossbar": self.submodules.crossbar = LiteEthMACCrossbar() self.submodules.packetizer = LiteEthMACPacketizer() diff --git a/make.py b/make.py new file mode 100644 index 00000000..ba6b9b1d --- /dev/null +++ b/make.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 + +import sys, os, argparse, subprocess, struct, importlib + +from mibuild.tools import write_to_file +from migen.util.misc import autotype +from migen.fhdl import verilog, edif +from migen.fhdl.structure import _Fragment +from mibuild import tools +from mibuild.xilinx_common import * + +from misoclib.gensoc import cpuif + +from liteeth.common import * + +def _import(default, name): + return importlib.import_module(default + "." + name) + +def _get_args(): + parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, + description="""\ +LiteEth - based on Migen. + +This program builds and/or loads LiteEth components. +One or several actions can be specified: + +clean delete previous build(s). +build-rtl build verilog rtl. +build-bitstream build-bitstream build FPGA bitstream. +build-csr-csv save CSR map into CSV file. + +load-bitstream load bitstream into volatile storage. + +all clean, build-csr-csv, build-bitstream, load-bitstream. +""") + + parser.add_argument("-t", "--target", default="udpip", help="Core type to build") + parser.add_argument("-s", "--sub-target", default="", help="variant of the Core type to build") + parser.add_argument("-p", "--platform", default=None, help="platform to build for") + parser.add_argument("-Ot", "--target-option", default=[], nargs=2, action="append", help="set target-specific option") + parser.add_argument("-Op", "--platform-option", default=[("programmer", "vivado")], nargs=2, action="append", help="set platform-specific option") + parser.add_argument("--csr_csv", default="./test/csr.csv", help="CSV file to save the CSR map into") + + parser.add_argument("action", nargs="+", help="specify an action") + + return parser.parse_args() + +# Note: misoclib need to be installed as a python library + +if __name__ == "__main__": + args = _get_args() + + # create top-level Core object + target_module = _import("targets", args.target) + if args.sub_target: + top_class = getattr(target_module, args.sub_target) + else: + top_class = target_module.default_subtarget + + if args.platform is None: + platform_name = top_class.default_platform + else: + platform_name = args.platform + platform_module = _import("platforms", platform_name) + platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option) + platform = platform_module.Platform(**platform_kwargs) + + build_name = top_class.__name__.lower() + "-" + platform_name + top_kwargs = dict((k, autotype(v)) for k, v in args.target_option) + soc = top_class(platform, **top_kwargs) + soc.finalize() + + # decode actions + action_list = ["clean", "build-csr-csv", "build-bitstream", "load-bitstream", "all"] + actions = {k: False for k in action_list} + for action in args.action: + if action in actions: + actions[action] = True + else: + print("Unknown action: "+action+". Valid actions are:") + for a in action_list: + print(" "+a) + sys.exit(1) + + print(""" + __ _ __ ______ __ + / / (_) /____ / __/ /_/ / + / /__/ / __/ -_) _// __/ _ \\ + /____/_/\__/\__/___/\__/_//_/ + + A small footprint and configurable + Ethernet core + +====== Building options: ====== +System Clk: {} MHz +===============================""".format( + soc.clk_freq/1000000 + ) +) + + # dependencies + if actions["all"]: + actions["clean"] = True + actions["build-csr-csv"] = True + actions["build-bitstream"] = True + actions["load-bitstream"] = True + + if actions["build-bitstream"]: + actions["clean"] = True + actions["build-csr-csv"] = True + actions["build-bitstream"] = True + actions["load-bitstream"] = True + + if actions["clean"]: + subprocess.call(["rm", "-rf", "build/*"]) + + if actions["build-csr-csv"]: + csr_csv = cpuif.get_csr_csv(soc.cpu_csr_regions) + write_to_file(args.csr_csv, csr_csv) + + if actions["build-bitstream"]: + platform.build(soc, build_name=build_name) + + if actions["load-bitstream"]: + prog = platform.create_programmer() + prog.load_bitstream("build/" + build_name + platform.bitstream_ext) diff --git a/platforms/kc705.py b/platforms/kc705.py new file mode 100644 index 00000000..a0e2098f --- /dev/null +++ b/platforms/kc705.py @@ -0,0 +1,124 @@ +from mibuild.generic_platform import * +from mibuild.crg import SimpleCRG +from mibuild.xilinx_common import CRG_DS +from mibuild.xilinx_ise import XilinxISEPlatform +from mibuild.xilinx_vivado import XilinxVivadoPlatform +from mibuild.programmer import * + +def _run_vivado(cmds): + with subprocess.Popen("vivado -mode tcl", stdin=subprocess.PIPE, shell=True) as process: + process.stdin.write(cmds.encode("ASCII")) + process.communicate() + +class VivadoProgrammer(Programmer): + needs_bitreverse = False + + def load_bitstream(self, bitstream_file): + cmds = """open_hw +connect_hw_server +open_hw_target [lindex [get_hw_targets -of_objects [get_hw_servers localhost]] 0] + +set_property PROBES.FILE {{}} [lindex [get_hw_devices] 0] +set_property PROGRAM.FILE {{{bitstream}}} [lindex [get_hw_devices] 0] + +program_hw_devices [lindex [get_hw_devices] 0] +refresh_hw_device [lindex [get_hw_devices] 0] + +quit +""".format(bitstream=bitstream_file) + _run_vivado(cmds) + + def flash(self, address, data_file): + raise NotImplementedError + +_io = [ + ("user_led", 0, Pins("AB8"), IOStandard("LVCMOS15")), + ("user_led", 1, Pins("AA8"), IOStandard("LVCMOS15")), + ("user_led", 2, Pins("AC9"), IOStandard("LVCMOS15")), + ("user_led", 3, Pins("AB9"), IOStandard("LVCMOS15")), + ("user_led", 4, Pins("AE26"), IOStandard("LVCMOS25")), + ("user_led", 5, Pins("G19"), IOStandard("LVCMOS25")), + ("user_led", 6, Pins("E18"), IOStandard("LVCMOS25")), + ("user_led", 7, Pins("F16"), IOStandard("LVCMOS25")), + + ("cpu_reset", 0, Pins("AB7"), IOStandard("LVCMOS15")), + + ("clk200", 0, + Subsignal("p", Pins("AD12"), IOStandard("LVDS")), + Subsignal("n", Pins("AD11"), IOStandard("LVDS")) + ), + + ("clk156", 0, + Subsignal("p", Pins("K28"), IOStandard("LVDS_25")), + Subsignal("n", Pins("K29"), IOStandard("LVDS_25")) + ), + + + ("serial", 0, + Subsignal("cts", Pins("L27")), + Subsignal("rts", Pins("K23")), + Subsignal("tx", Pins("K24")), + Subsignal("rx", Pins("M19")), + IOStandard("LVCMOS25") + ), + + ("eth_clocks", 0, + Subsignal("tx", Pins("M28")), + Subsignal("gtx", Pins("K30")), + Subsignal("rx", Pins("U27")), + IOStandard("LVCMOS25") + ), + ("eth", 0, + Subsignal("rst_n", Pins("L20")), + Subsignal("int_n", Pins("N30")), + Subsignal("mdio", Pins("J21")), + Subsignal("mdc", Pins("R23")), + Subsignal("dv", Pins("R28")), + Subsignal("rx_er", Pins("V26")), + Subsignal("rx_data", Pins("U30 U25 T25 U28 R19 T27 T26 T28")), + Subsignal("tx_en", Pins("M27")), + Subsignal("tx_er", Pins("N29")), + Subsignal("tx_data", Pins("N27 N25 M29 L28 J26 K26 L30 J28")), + Subsignal("col", Pins("W19")), + Subsignal("crs", Pins("R30")), + IOStandard("LVCMOS25") + ), + +] + +def Platform(*args, toolchain="vivado", programmer="xc3sprog", **kwargs): + if toolchain == "ise": + xilinx_platform = XilinxISEPlatform + elif toolchain == "vivado": + xilinx_platform = XilinxVivadoPlatform + else: + raise ValueError + + class RealPlatform(xilinx_platform): + bitgen_opt = "-g LCK_cycle:6 -g Binary:Yes -w -g ConfigRate:12 -g SPI_buswidth:4" + + def __init__(self, crg_factory=lambda p: CRG_DS(p, "clk200", "cpu_reset")): + xilinx_platform.__init__(self, "xc7k325t-ffg900-2", _io, crg_factory) + + def create_programmer(self): + if programmer == "xc3sprog": + return XC3SProg("jtaghs1_fast", "bscan_spi_kc705.bit") + elif programmer == "vivado": + return VivadoProgrammer() + else: + raise ValueError + + def do_finalize(self, fragment): + try: + self.add_period_constraint(self.lookup_request("clk156").p, 6.4) + except ConstraintError: + pass + try: + self.add_period_constraint(self.lookup_request("clk200").p, 5.0) + except ConstraintError: + pass + try: + self.add_period_constraint(self.lookup_request("eth_clocks").rx, 8.0) + except ConstraintError: + pass + return RealPlatform(*args, **kwargs) diff --git a/targets/udpip.py b/targets/udpip.py new file mode 100644 index 00000000..0019c684 --- /dev/null +++ b/targets/udpip.py @@ -0,0 +1,211 @@ +import os, atexit + +from migen.bank import csrgen +from migen.bus import wishbone, csr +from migen.bus import wishbone2csr +from migen.genlib.cdc import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.bank.description import * + +from misoclib import identifier + +from litescope.common import * +from litescope.bridge.uart2wb import LiteScopeUART2WB +from litescope.frontend.la import LiteScopeLA +from litescope.core.port import LiteScopeTerm + +from liteeth.common import * +from liteeth.phy.gmii import LiteEthPHYGMII +from liteeth.core import LiteEthUDPIPCore + +class _CRG(Module): + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.reset = Signal() + + clk200 = platform.request("clk200") + clk200_se = Signal() + self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se) + + pll_locked = Signal() + pll_fb = Signal() + pll_sys = Signal() + self.specials += [ + Instance("PLLE2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + # VCO @ 1GHz + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0, + p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1, + i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + + # 166MHz + p_CLKOUT0_DIVIDE=6, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys, + + p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, #o_CLKOUT1=, + + p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, #o_CLKOUT2=, + + p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=, + + p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4= + ), + Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.reset), + ] + +class GenSoC(Module): + csr_base = 0x00000000 + csr_data_width = 32 + csr_map = { + "bridge": 0, + "identifier": 1, + } + interrupt_map = {} + cpu_type = None + def __init__(self, platform, clk_freq): + self.clk_freq = clk_freq + # UART <--> Wishbone bridge + self.submodules.bridge = LiteScopeUART2WB(platform.request("serial"), clk_freq, baud=921600) + + # CSR bridge 0x00000000 (shadow @0x00000000) + self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(self.csr_data_width)) + self._wb_masters = [self.bridge.wishbone] + self._wb_slaves = [(lambda a: a[23:25] == 0, self.wishbone2csr.wishbone)] + self.cpu_csr_regions = [] # list of (name, origin, busword, csr_list/Memory) + + # CSR + self.submodules.identifier = identifier.Identifier(0, int(clk_freq), 0) + + def add_cpu_memory_region(self, name, origin, length): + self.cpu_memory_regions.append((name, origin, length)) + + def add_cpu_csr_region(self, name, origin, busword, obj): + self.cpu_csr_regions.append((name, origin, busword, obj)) + + def do_finalize(self): + # Wishbone + self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters, + self._wb_slaves, register=True) + + # CSR + self.submodules.csrbankarray = csrgen.BankArray(self, + lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override], + data_width=self.csr_data_width) + self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses()) + for name, csrs, mapaddr, rmap in self.csrbankarray.banks: + self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), csrs) + for name, memory, mapaddr, mmap in self.csrbankarray.srams: + self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), memory) + +class UDPIPBISTGeneratorUnit(Module): + def __init__(self): + self.start = Signal() + self.src_port = Signal(16) + self.dst_port = Signal(16) + self.ip_address = Signal(32) + self.length = Signal(16) + self.done = Signal() + + self.source = source = Source(eth_udp_user_description(8)) + ### + + counter = Counter(bits_sign=16) + self.submodules += counter + + self.fsm = fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + self.done.eq(1), + counter.reset.eq(1), + If(self.start, + NextState("SEND") + ) + ) + self.comb += [ + source.sop.eq(counter.value == 0), + source.eop.eq(counter.value == (self.length-1)), + source.src_port.eq(self.src_port), + source.dst_port.eq(self.dst_port), + source.ip_address.eq(self.ip_address), + source.data.eq(counter.value) + ] + fsm.act("SEND", + source.stb.eq(1), + If(source.stb & source.ack, + counter.ce.eq(1), + If(source.eop, + NextState("IDLE") + ) + ) + ) + +class UDPIPBISTGenerator(UDPIPBISTGeneratorUnit, AutoCSR): + def __init__(self): + self._start = CSR() + self._src_port = CSRStorage(16) + self._dst_port = CSRStorage(16) + self._ip_address = CSRStorage(32) + self._length = CSRStorage(16) + self._done = CSRStatus() + ### + UDPIPBISTGeneratorUnit.__init__(self) + + self.comb += [ + self.start.eq(self._start.r & self._start.re), + self.src_port.eq(self._src_port.storage), + self.dst_port.eq(self._dst_port.storage), + self.ip_address.eq(self._ip_address.storage), + self.length.eq(self._length.storage), + self._done.status.eq(self.done) + ] + +class UDPIPSoC(GenSoC, AutoCSR): + default_platform = "kc705" + csr_map = { + "ethphy": 11, + "udpipcore": 12, + "bist_generator": 13 + } + csr_map.update(GenSoC.csr_map) + def __init__(self, platform): + clk_freq = 166*1000000 + GenSoC.__init__(self, platform, clk_freq) + self.submodules.crg = _CRG(platform) + + # Ethernet PHY and UDP/IP + self.submodules.ethphy = LiteEthPHYGMII(platform.request("eth_clocks"), platform.request("eth")) + self.submodules.udpipcore = LiteEthUDPIPCore(self.ethphy, 0x12345678, 0x10e2d5000000) + + # BIST + self.submodules.bist_generator = UDPIPBISTGenerator() + self.comb += [ + Record.connect(self.bist_generator.source, self.udpipcore.sink), + self.udpipcore.source.ack.eq(1) + ] + +class UDPIPSoCDevel(UDPIPSoC, AutoCSR): + csr_map = { + "la": 20 + } + csr_map.update(UDPIPSoC.csr_map) + def __init__(self, platform): + UDPIPSoC.__init__(self, platform) + + debug = ( + Signal(), + Signal() + ) + + self.submodules.la = LiteScopeLA(debug, 2048) + self.la.trigger.add_port(LiteScopeTerm(self.la.dw)) + atexit.register(self.exit, platform) + + def do_finalize(self): + UDPIPSoC.do_finalize(self) + + def exit(self, platform): + if platform.vns is not None: + self.la.export(platform.vns, "../test/la.csv") + +default_subtarget = UDPIPSoC diff --git a/test/config.py b/test/config.py new file mode 100644 index 00000000..44d8fcee --- /dev/null +++ b/test/config.py @@ -0,0 +1,9 @@ +from litescope.host.driver import LiteScopeUART2WBDriver + +csr_csv_file = "./csr.csv" +busword = 32 +debug_wb = False + +com = 2 +baud = 921600 +wb = LiteScopeUART2WBDriver(com, baud, csr_csv_file, busword, debug_wb) \ No newline at end of file diff --git a/test/test_regs.py b/test/test_regs.py new file mode 100644 index 00000000..982f849c --- /dev/null +++ b/test/test_regs.py @@ -0,0 +1,10 @@ +from config import * + +wb.open() +regs = wb.regs +### +print("sysid : 0x%04x" %regs.identifier_sysid.read()) +print("revision : 0x%04x" %regs.identifier_revision.read()) +print("frequency : %d MHz" %(regs.identifier_frequency.read()/1000000)) +### +wb.close() diff --git a/test/test_udpip.py b/test/test_udpip.py new file mode 100644 index 00000000..9aff6ac9 --- /dev/null +++ b/test/test_udpip.py @@ -0,0 +1,20 @@ +from config import * +import time + +wb.open() +regs = wb.regs +### +regs.ethphy_crg_reset.write(1) +regs.ethphy_crg_reset.write(0) +time.sleep(5) +regs.bist_generator_src_port.write(0x1234) +regs.bist_generator_dst_port.write(0x5678) +regs.bist_generator_ip_address.write(0x12345678) +regs.bist_generator_length.write(64) + +for i in range(16): + regs.bist_generator_start.write(1) + time.sleep(1) + +### +wb.close()