diff --git a/litex/boards/platforms/arty.py b/litex/boards/platforms/arty.py new file mode 100644 index 000000000..3f5d09aaa --- /dev/null +++ b/litex/boards/platforms/arty.py @@ -0,0 +1,115 @@ +# This file is Copyright (c) 2015 Yann Sionneau +# This file is Copyright (c) 2015 Florent Kermarrec +# License: BSD + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, XC3SProg, VivadoProgrammer + +_io = [ + ("user_led", 0, Pins("H5"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("J5"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("T9"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("T10"), IOStandard("LVCMOS33")), + + ("rgb_leds", 0, + Subsignal("r", Pins("G6 G3 J3 K1")), + Subsignal("g", Pins("F6 J4 J2 H6")), + Subsignal("b", Pins("E1 G4 H4 K2")), + IOStandard("LVCMOS33") + ), + + ("user_sw", 0, Pins("A8"), IOStandard("LVCMOS33")), + ("user_sw", 1, Pins("C11"), IOStandard("LVCMOS33")), + ("user_sw", 2, Pins("C10"), IOStandard("LVCMOS33")), + ("user_sw", 3, Pins("A10"), IOStandard("LVCMOS33")), + + ("user_btn", 0, Pins("D9"), IOStandard("LVCMOS33")), + ("user_btn", 1, Pins("C9"), IOStandard("LVCMOS33")), + ("user_btn", 2, Pins("B9"), IOStandard("LVCMOS33")), + ("user_btn", 3, Pins("B8"), IOStandard("LVCMOS33")), + + ("clk100", 0, Pins("E3"), IOStandard("LVCMOS33")), + + ("cpu_reset", 0, Pins("C2"), IOStandard("LVCMOS33")), + + ("serial", 0, + Subsignal("tx", Pins("D10")), + Subsignal("rx", Pins("A9")), + IOStandard("LVCMOS33")), + + ("spiflash", 0, # clock needs to be accessed through STARTUPE2 + Subsignal("cs_n", Pins("L13")), + Subsignal("dq", Pins("K17", "K18", "L14", "M14")), + IOStandard("LVCMOS33") + ), + + ("eth_ref_clk", 0, Pins("G18"), IOStandard("LVCMOS33")), + + ("ddram", 0, + Subsignal("a", Pins( + "R2 M6 N4 T1 N6 R7 V6 U7"), + IOStandard("SSTL135")), + Subsignal("ba", Pins("R1 P4 P2"), IOStandard("SSTL135")), + Subsignal("ras_n", Pins("P3"), IOStandard("SSTL135")), + Subsignal("cas_n", Pins("M4"), IOStandard("SSTL135")), + Subsignal("we_n", Pins("P5"), IOStandard("SSTL135")), + Subsignal("cs_n", Pins("U8"), IOStandard("SSTL135")), + Subsignal("dm", Pins("L1"), IOStandard("SSTL135")), + Subsignal("dq", Pins( + "K5 L3 K3 L6 M3 M1 L4 M2"), + IOStandard("SSTL135"), + Misc("IN_TERM=UNTUNED_SPLIT_50")), + Subsignal("dqs_p", Pins("N2"), IOStandard("DIFF_SSTL135")), + Subsignal("dqs_n", Pins("N1"), IOStandard("DIFF_SSTL135")), + Subsignal("clk_p", Pins("U9"), IOStandard("DIFF_SSTL135")), + Subsignal("clk_n", Pins("V9"), IOStandard("DIFF_SSTL135")), + Subsignal("cke", Pins("N5"), IOStandard("SSTL135")), + Subsignal("odt", Pins("R5"), IOStandard("SSTL135")), + Subsignal("reset_n", Pins("K6"), IOStandard("SSTL135")), + Misc("SLEW=FAST"), + ), + + ("eth_clocks", 0, + Subsignal("tx", Pins("H16")), + Subsignal("rx", Pins("F15")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + Subsignal("rst_n", Pins("C16")), + Subsignal("mdio", Pins("K13")), + Subsignal("mdc", Pins("F16")), + Subsignal("dv", Pins("G16")), + Subsignal("rx_er", Pins("C17")), + Subsignal("rx_data", Pins("D18 E17 E18 G17")), + Subsignal("tx_en", Pins("H15")), + Subsignal("tx_data", Pins("H14 J14 J13 H17")), + Subsignal("col", Pins("D17")), + Subsignal("crs", Pins("G14")), + IOStandard("LVCMOS33") + ), +] + + +class Platform(XilinxPlatform): + default_clk_name = "clk100" + default_clk_period = 10.0 + + def __init__(self, toolchain="vivado", programmer="vivado"): + XilinxPlatform.__init__(self, "xc7a35ticsg324-1L", _io, + toolchain=toolchain) + self.toolchain.bitstream_commands = \ + ["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"] + self.toolchain.additional_commands = \ + ["write_cfgmem -force -format bin -interface spix4 -size 16 " + "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] + self.programmer = programmer + self.add_platform_command("set_property INTERNAL_VREF 0.675 [get_iobanks 34]") + + def create_programmer(self): + if self.programmer == "xc3sprog": + return XC3SProg("nexys4") + elif self.programmer == "vivado": + return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") + else: + raise ValueError("{} programmer is not supported" + .format(self.programmer)) diff --git a/litex/boards/targets/arty.py b/litex/boards/targets/arty.py new file mode 100644 index 000000000..eb07d1ae5 --- /dev/null +++ b/litex/boards/targets/arty.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +import argparse +import os + +from litex.gen import * +from litex.gen.genlib.resetsync import AsyncResetSynchronizer + +from litex.boards.platforms import arty + +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * + +from liteeth.phy.mii import LiteEthPHYMII +from liteeth.core.mac import LiteEthMAC + +class _CRG(Module): + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_eth = ClockDomain(reset_less=True) + + clk100 = platform.request("clk100") + rst = platform.request("cpu_reset") + + pll_locked = Signal() + pll_fb = Signal() + pll_sys = Signal() + pll_eth = Signal() + self.specials += [ + Instance("PLLE2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + # VCO @ 800 MHz + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + i_CLKIN1=clk100, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + + # 100 MHz + p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=pll_sys, + + # 25 MHz + p_CLKOUT1_DIVIDE=32, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=pll_eth, + + # 200 MHz + p_CLKOUT2_DIVIDE=4, p_CLKOUT2_PHASE=0.0, + #o_CLKOUT2=, + + # 200 MHz + p_CLKOUT3_DIVIDE=4, p_CLKOUT3_PHASE=0.0, + #o_CLKOUT3=, + + # 200MHz + p_CLKOUT4_DIVIDE=4, p_CLKOUT4_PHASE=0.0, + #o_CLKOUT4= + ), + Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), + Instance("BUFG", i_I=pll_eth, o_O=self.cd_eth.clk), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | ~rst), + ] + + + self.specials += [ + Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, + i_C0=self.cd_eth.clk, i_C1=~self.cd_eth.clk, + o_Q=platform.request("eth_ref_clk")) + ] + + +class BaseSoC(SoCCore): + def __init__(self, **kwargs): + platform = arty.Platform() + SoCCore.__init__(self, platform, clk_freq=100*1000000, **kwargs) + + self.submodules.crg = _CRG(platform) + + +class MiniSoC(BaseSoC): + csr_map = { + "ethphy": 18, + "ethmac": 19 + } + csr_map.update(BaseSoC.csr_map) + + interrupt_map = { + "ethmac": 2, + } + interrupt_map.update(BaseSoC.interrupt_map) + + mem_map = { + "ethmac": 0x30000000, # (shadow @0xb0000000) + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, **kwargs): + BaseSoC.__init__(self, **kwargs) + + self.submodules.ethphy = LiteEthPHYMII(self.platform.request("eth_clocks"), + self.platform.request("eth")) + self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone") + self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) + self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000) + + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC port to Arty") + builder_args(parser) + soc_core_args(parser) + parser.add_argument("--with-ethernet", action="store_true", + help="enable Ethernet support") + parser.add_argument("--build", action="store_true", + help="build bitstream") + parser.add_argument("--load", action="store_true", + help="load bitstream") + args = parser.parse_args() + + cls = MiniSoC if args.with_ethernet else BaseSoC + soc = cls(**soc_core_argdict(args)) + builder = Builder(soc, **builder_argdict(args)) + + if args.build: + builder.build() + + if args.load: + prog = soc.platform.create_programmer() + prog.load_bitstream(os.path.join(builder.output_dir, "gateware", "top.bit")) + + +if __name__ == "__main__": + main()