From b8373a361dcbbf760fda6ebed546eb1fc496c924 Mon Sep 17 00:00:00 2001 From: "Nathaniel R. Lewis" Date: Fri, 10 Sep 2021 01:40:44 -0700 Subject: [PATCH] alchitry_mojo: new board --- litex_boards/platforms/alchitry_mojo.py | 123 ++++++++++++++++ litex_boards/targets/alchitry_mojo.py | 185 ++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 litex_boards/platforms/alchitry_mojo.py create mode 100755 litex_boards/targets/alchitry_mojo.py diff --git a/litex_boards/platforms/alchitry_mojo.py b/litex_boards/platforms/alchitry_mojo.py new file mode 100644 index 0000000..ab24065 --- /dev/null +++ b/litex_boards/platforms/alchitry_mojo.py @@ -0,0 +1,123 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2021 Nathaniel Lewis +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst + ("clk50", 0, Pins("P56"), IOStandard("LVCMOS33")), + ("cpu_reset", 0, Pins("P38"), IOStandard("LVCMOS33")), + + # Leds + ("user_led", 0, Pins("P134"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("P133"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("P132"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("P131"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("P127"), IOStandard("LVCMOS33")), + ("user_led", 5, Pins("P126"), IOStandard("LVCMOS33")), + ("user_led", 6, Pins("P124"), IOStandard("LVCMOS33")), + ("user_led", 7, Pins("P123"), IOStandard("LVCMOS33")), + + # Serial + ("serial", 0, + Subsignal("tx", Pins("P59")), + Subsignal("rx", Pins("P55")), + IOStandard("LVCMOS33") + ), + + # AVR signals + ("tx_busy", 0, Pins("P39"), IOStandard("LVCMOS33")), + ("cclk", 0, Pins("P70"), IOStandard("LVCMOS33")), +] + +_hdmi_shield = [ + # SDRAM + ("sdram_clock", 0, Pins("P29"), IOStandard("LVCMOS33"), Misc("SLEW=FAST")), + ("sdram", 0, + Subsignal("a", Pins("P101 P102 P104 P105 P5 P6 P7 P8 P9 P10 P88 P27 P26")), + Subsignal("dq", Pins("P75 P78 P79 P80 P34 P35 P40 P41")), + Subsignal("ba", Pins("P85 P87")), + Subsignal("dm", Pins("P74")), + Subsignal("ras_n", Pins("P83")), + Subsignal("cas_n", Pins("P82")), + Subsignal("we_n", Pins("P81")), + Subsignal("cs_n", Pins("P84")), + Subsignal("cke", Pins("P30")), + IOStandard("LVCMOS33"), + Misc("SLEW = FAST") + ), + + # HDMI Out (HDMI 1) + ("hdmi_out", 0, + # TODO: do clock pins need "CLOCK_DEDICATED_ROUTE = FALSE" ? + Subsignal("clk_p", Pins("P144")), + Subsignal("clk_n", Pins("P143")), + Subsignal("data0_p", Pins("P142")), + Subsignal("data0_n", Pins("P141")), + Subsignal("data1_p", Pins("P140")), + Subsignal("data1_n", Pins("P139")), + Subsignal("data2_p", Pins("P138")), + Subsignal("data2_n", Pins("P137")), + IOStandard("TMDS_33") + ), + + # HDMI Out DDC Bus + ("hdmi_out_sda", 0, Pins("P2"), IOStandard("LVCMOS33")), + ("hdmi_out_scl", 0, Pins("P1"), IOStandard("LVCMOS33")), + + # HDMI In (HDMI 2) + ("hdmi_in", 0, + # TODO: do clock pins need "CLOCK_DEDICATED_ROUTE = FALSE" ? + Subsignal("clk_p", Pins("P121")), + Subsignal("clk_n", Pins("P120")), + Subsignal("data0_p", Pins("P119")), + Subsignal("data0_n", Pins("P118")), + Subsignal("data1_p", Pins("P117")), + Subsignal("data1_n", Pins("P116")), + Subsignal("data2_p", Pins("P115")), + Subsignal("data2_n", Pins("P114")), + IOStandard("TMDS_33") + ), + + # HDMI In DDC Bus + ("hdmi_in_sda", 0, Pins("P111"), IOStandard("LVCMOS33")), + ("hdmi_in_scl", 0, Pins("P112"), IOStandard("LVCMOS33")), +] + +_sdram_shield = [ + # SDRAM + ("sdram_clock", 0, Pins("P5"), IOStandard("LVCMOS33"), Misc("SLEW=FAST")), + ("sdram", 0, + Subsignal("a", Pins("P118 P119 P120 P121 P138 P139 P140 P141 P142 P143 P137 P144 P1")), + Subsignal("dq", Pins("P101 P102 P104 P105 P7 P8 P9 P10")), + Subsignal("ba", Pins("P116 P117")), + Subsignal("dm", Pins("P6")), + Subsignal("ras_n", Pins("P114")), + Subsignal("cas_n", Pins("P112")), + Subsignal("we_n", Pins("P111")), + Subsignal("cs_n", Pins("P115")), + Subsignal("cke", Pins("P2")), + IOStandard("LVCMOS33"), + Misc("SLEW = FAST") + ) +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = "clk50" + default_clk_period = 1e9/50e6 + + def __init__(self): + XilinxPlatform.__init__(self, "xc6slx9-2-tqg144", _io) + self.toolchain.additional_commands = ["write_bitstream -force -bin_file {build_name}"] + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk50", loose=True), 1e9/50e6) diff --git a/litex_boards/targets/alchitry_mojo.py b/litex_boards/targets/alchitry_mojo.py new file mode 100755 index 0000000..bf93599 --- /dev/null +++ b/litex_boards/targets/alchitry_mojo.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2021 Nathaniel Lewis +# SPDX-License-Identifier: BSD-2-Clause + +# Testing build for HDMI +# - The main trouble with HDMI demos are that they require many SLICEMs, which are a very limited +# resource on the XC6SLX9. Many of these examples are just trying to reduce usage of them. +# +# # Simple colorbar output +# ./alchitry_mojo.py \ +# --build \ +# --with-hdmi-shield \ +# --with-video-colorbars \ +# --csr-csv=build/alchitry_mojo/csr.csv +# +# # Video Terminal (lower SRAM size to allow for text buffer) +# ./alchitry_mojo.py \ +# --build \ +# --with-hdmi-shield \ +# --with-video-terminal \ +# --csr-csv=build/alchitry_mojo/csr.csv \ +# --integrated-rom-size 32768 \ +# --integrated-sram-size 4096 +# +# # Video Framebuffer (double sdram speed to have enough bandwidth) +# # Lower the fifo_depth in litex/litex/soc/cores/video.py "class VideoFrameBuffer" to 1024 +# ./alchitry_mojo.py \ +# --build \ +# --with-hdmi-shield \ +# --with-video-framebuffer \ +# --csr-csv=build/alchitry_mojo/csr.csv \ +# --integrated-rom-size 32768 \ +# --sdram-rate 1:2 +# +# litex> # Turn screen Red +# litex> mem_write 0x40c00000 0xffff0000 307200 + +import os +import argparse +import sys + +from migen import * + +from litex.build.io import DDROutput +from litex_boards.platforms import alchitry_mojo + +from litex.soc.interconnect.csr import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * + +from litex.soc.cores.clock import * +from litex.soc.cores.video import VideoS6HDMIPHY +from litex.soc.cores.led import LedChaser + +from litedram.modules import MT48LC32M8, SDRModule +from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY + +# CRG ---------------------------------------------------------------------------------------------- + +class CRG(Module): + def __init__(self, platform, sys_clk_freq, sdram_rate="1:1"): + self.rst = Signal() + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_hdmi = ClockDomain() + self.clock_domains.cd_hdmi5x = ClockDomain() + if sdram_rate == "1:2": + self.clock_domains.cd_sys2x = ClockDomain(reset_less=True) + self.clock_domains.cd_sys2x_ps = ClockDomain(reset_less=True) + else: + self.clock_domains.cd_sys_ps = ClockDomain(reset_less=True) + + # Clk/Rst + clk50 = platform.request("clk50") + rst = platform.request("cpu_reset") + avr_ready = platform.request("cclk") + + # PLL + self.submodules.pll = pll = S6PLL() + self.comb += pll.reset.eq(~rst | ~avr_ready | self.rst) + pll.register_clkin(clk50, 50e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + pll.create_clkout(self.cd_hdmi, 25e6, margin=0) + pll.create_clkout(self.cd_hdmi5x, 125e6, margin=0) + if sdram_rate == "1:2": + pll.create_clkout(self.cd_sys2x, 2*sys_clk_freq) + pll.create_clkout(self.cd_sys2x_ps, 2*sys_clk_freq, phase=90) + else: + pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=90) + +# BaseSoC ----------------------------------------------------------------------------------------- + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=int(62.5e6), sdram_rate="1:1", with_hdmi_shield=False, + with_sdram_shield=False, with_led_chaser=True, with_video_terminal=False, + with_video_framebuffer=False, with_video_colorbars=False, **kwargs): + platform = alchitry_mojo.Platform() + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Alchitry Mojo", + ident_version = True, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = CRG(platform, sys_clk_freq, sdram_rate) + + # HDMI Shield ------------------------------------------------------------------------------ + if with_hdmi_shield: + self.platform.add_extension(alchitry_mojo._hdmi_shield) + + # SDRAM Shield ----------------------------------------------------------------------------- + if with_sdram_shield: + self.platform.add_extension(alchitry_mojo._sdram_shield) + + # Add SDRAM if a shield with RAM has been added + if not self.integrated_main_ram_size and (with_hdmi_shield or with_sdram_shield): + sdram_clk = ClockSignal("sys2x_ps" if sdram_rate == "1:2" else "sys_ps") + self.crg.specials += DDROutput(1, 0, platform.request("sdram_clock"), sdram_clk) + + sdrphy_cls = HalfRateGENSDRPHY if sdram_rate == "1:2" else GENSDRPHY + self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"), sys_clk_freq) + self.add_sdram("sdram", + phy = self.sdrphy, + module = MT48LC32M8(sys_clk_freq, sdram_rate), + l2_cache_size = kwargs.get("l2_size", 1024) + ) + + # HDMI Options ----------------------------------------------------------------------------- + if with_hdmi_shield and (with_video_colorbars or with_video_framebuffer or with_video_terminal): + self.submodules.videophy = VideoS6HDMIPHY(platform.request("hdmi_out"), clock_domain="hdmi") + if with_video_colorbars: + self.add_video_colorbars(phy=self.videophy, timings="640x480@60Hz", clock_domain="hdmi") + if with_video_terminal: + self.add_video_terminal(phy=self.videophy, timings="640x480@60Hz", clock_domain="hdmi") + if with_video_framebuffer: + self.add_video_framebuffer(phy=self.videophy, timings="640x480@60Hz", clock_domain="hdmi") + + # Leds ------------------------------------------------------------------------------------- + if with_led_chaser: + self.submodules.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Alchitry Mojo") + parser.add_argument("--build", action="store_true", help="Build bitstream") + parser.add_argument("--sys-clk-freq", default=62.5e6, help="System clock frequency (default: 62.5 MHz)") + parser.add_argument("--sdram-rate", default="1:1", help="SDRAM Rate: 1:1 Full Rate (default), 1:2 Half Rate") + shields1 = parser.add_mutually_exclusive_group() + shields1.add_argument("--with-hdmi-shield", action="store_true", help="Enable HDMI Shield") + shields1.add_argument("--with-sdram-shield", action="store_true", help="Enable SDRAM Shield") + viopts = parser.add_mutually_exclusive_group() + viopts.add_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (HDMI)") + viopts.add_argument("--with-video-framebuffer", action="store_true", help="Enable Video Framebuffer (HDMI)") + viopts.add_argument("--with-video-colorbars", action="store_true", help="Enable Video Colorbars (HDMI)") + + builder_args(parser) + soc_core_args(parser) + args = parser.parse_args() + + # Note: baudrate is fixed because regardless of USB->TTL baud, the AVR <-> FPGA baudrate is + # set to a fixed rate of 500 kilobaud. + soc = BaseSoC( + sys_clk_freq = int(float(args.sys_clk_freq)), + sdram_rate = args.sdram_rate, + with_hdmi_shield = args.with_hdmi_shield, + with_sdram_shield = args.with_sdram_shield, + with_video_terminal = args.with_video_terminal, + with_video_framebuffer = args.with_video_framebuffer, + with_video_colorbars = args.with_video_colorbars, + uart_baudrate = 500000, + **soc_core_argdict(args) + ) + + builder = Builder(soc, **builder_argdict(args)) + builder.build(run=args.build) + +if __name__ == "__main__": + main()