From 68694294e1470e17ce815372da23329193715eae Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 10:48:43 +0800 Subject: [PATCH 01/23] initial commit Signed-off-by: Sean Cross --- .gitmodules | 33 +++ bin/litex_read_verilog | 14 ++ bin/litex_server | 14 ++ bin/litex_sim | 14 ++ bin/litex_simple | 14 ++ bin/litex_term | 14 ++ bin/mkmscimg | 14 ++ deps/litedram | 1 + deps/liteeth | 1 + deps/liteiclink | 1 + deps/litepcie | 1 + deps/litescope | 1 + deps/litesdcard | 1 + deps/liteusb | 1 + deps/litevideo | 1 + deps/litex | 1 + deps/migen | 1 + deps/pyserial | 1 + foboot-bitstream.py | 60 +++++ lxbuildenv.py | 493 +++++++++++++++++++++++++++++++++++++++++ 20 files changed, 681 insertions(+) create mode 100644 .gitmodules create mode 100755 bin/litex_read_verilog create mode 100755 bin/litex_server create mode 100755 bin/litex_sim create mode 100755 bin/litex_simple create mode 100755 bin/litex_term create mode 100755 bin/mkmscimg create mode 160000 deps/litedram create mode 160000 deps/liteeth create mode 160000 deps/liteiclink create mode 160000 deps/litepcie create mode 160000 deps/litescope create mode 160000 deps/litesdcard create mode 160000 deps/liteusb create mode 160000 deps/litevideo create mode 160000 deps/litex create mode 160000 deps/migen create mode 160000 deps/pyserial create mode 100644 foboot-bitstream.py create mode 100644 lxbuildenv.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..df98602 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,33 @@ +[submodule "deps/migen"] + path = deps/migen + url = https://github.com/m-labs/migen.git +[submodule "deps/litex"] + path = deps/litex + url = https://github.com/enjoy-digital/litex.git +[submodule "deps/litescope"] + path = deps/litescope + url = https://github.com/enjoy-digital/litescope.git +[submodule "deps/pyserial"] + path = deps/pyserial + url = https://github.com/pyserial/pyserial.git +[submodule "deps/liteeth"] + path = deps/liteeth + url = https://github.com/enjoy-digital/liteeth.git +[submodule "deps/liteusb"] + path = deps/liteusb + url = https://github.com/enjoy-digital/liteusb.git +[submodule "deps/litedram"] + path = deps/litedram + url = https://github.com/enjoy-digital/litedram.git +[submodule "deps/litepcie"] + path = deps/litepcie + url = https://github.com/enjoy-digital/litepcie.git +[submodule "deps/litesdcard"] + path = deps/litesdcard + url = https://github.com/enjoy-digital/litesdcard.git +[submodule "deps/liteiclink"] + path = deps/liteiclink + url = https://github.com/enjoy-digital/liteiclink.git +[submodule "deps/litevideo"] + path = deps/litevideo + url = https://github.com/enjoy-digital/litevideo.git diff --git a/bin/litex_read_verilog b/bin/litex_read_verilog new file mode 100755 index 0000000..56139d4 --- /dev/null +++ b/bin/litex_read_verilog @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +from litex.utils.litex_read_verilog import main +main() diff --git a/bin/litex_server b/bin/litex_server new file mode 100755 index 0000000..b2b8650 --- /dev/null +++ b/bin/litex_server @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +from litex.utils.litex_server import main +main() diff --git a/bin/litex_sim b/bin/litex_sim new file mode 100755 index 0000000..24dbd96 --- /dev/null +++ b/bin/litex_sim @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +from litex.utils.litex_sim import main +main() diff --git a/bin/litex_simple b/bin/litex_simple new file mode 100755 index 0000000..7dbcd84 --- /dev/null +++ b/bin/litex_simple @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +from litex.boards.targets.simple import main +main() diff --git a/bin/litex_term b/bin/litex_term new file mode 100755 index 0000000..f817e63 --- /dev/null +++ b/bin/litex_term @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +from litex.utils.litex_term import main +main() diff --git a/bin/mkmscimg b/bin/mkmscimg new file mode 100755 index 0000000..23c9c01 --- /dev/null +++ b/bin/mkmscimg @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +from litex.soc.tools.mkmscimg import main +main() diff --git a/deps/litedram b/deps/litedram new file mode 160000 index 0000000..fd3e9af --- /dev/null +++ b/deps/litedram @@ -0,0 +1 @@ +Subproject commit fd3e9afbcd0872b645badc9b75aacab6dbf7459e diff --git a/deps/liteeth b/deps/liteeth new file mode 160000 index 0000000..77fa4bf --- /dev/null +++ b/deps/liteeth @@ -0,0 +1 @@ +Subproject commit 77fa4bfb1e452adb1fa34c1b0baede68c056763d diff --git a/deps/liteiclink b/deps/liteiclink new file mode 160000 index 0000000..ee9ae87 --- /dev/null +++ b/deps/liteiclink @@ -0,0 +1 @@ +Subproject commit ee9ae87641d98a1b9ad88e28042394797bfb9e00 diff --git a/deps/litepcie b/deps/litepcie new file mode 160000 index 0000000..3804c49 --- /dev/null +++ b/deps/litepcie @@ -0,0 +1 @@ +Subproject commit 3804c4947adedc6c720e3041e518627b0bf57f78 diff --git a/deps/litescope b/deps/litescope new file mode 160000 index 0000000..c1d8bdf --- /dev/null +++ b/deps/litescope @@ -0,0 +1 @@ +Subproject commit c1d8bdf6f23b1070b8bd2dd277a4708863474148 diff --git a/deps/litesdcard b/deps/litesdcard new file mode 160000 index 0000000..c07165f --- /dev/null +++ b/deps/litesdcard @@ -0,0 +1 @@ +Subproject commit c07165ff9f9e368c8147158b88fe90cea683e51c diff --git a/deps/liteusb b/deps/liteusb new file mode 160000 index 0000000..0a9110f --- /dev/null +++ b/deps/liteusb @@ -0,0 +1 @@ +Subproject commit 0a9110f901182a1233cc4e64b6e39175f6784621 diff --git a/deps/litevideo b/deps/litevideo new file mode 160000 index 0000000..98e145f --- /dev/null +++ b/deps/litevideo @@ -0,0 +1 @@ +Subproject commit 98e145fba8c25394e9958bad67e2a457d145127e diff --git a/deps/litex b/deps/litex new file mode 160000 index 0000000..ff155a4 --- /dev/null +++ b/deps/litex @@ -0,0 +1 @@ +Subproject commit ff155a474d12b62fb84db0ca07d2577687c5c141 diff --git a/deps/migen b/deps/migen new file mode 160000 index 0000000..afe4405 --- /dev/null +++ b/deps/migen @@ -0,0 +1 @@ +Subproject commit afe4405becdbc76539f0195c319367187012b05e diff --git a/deps/pyserial b/deps/pyserial new file mode 160000 index 0000000..a4d8f27 --- /dev/null +++ b/deps/pyserial @@ -0,0 +1 @@ +Subproject commit a4d8f27bf636ee598c4368d7e488f78a226bf778 diff --git a/foboot-bitstream.py b/foboot-bitstream.py new file mode 100644 index 0000000..1317c3b --- /dev/null +++ b/foboot-bitstream.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["riscv", "icestorm", "yosys"] + +# Import lxbuildenv to integrate the deps/ directory +import lxbuildenv + +# Disable pylint's E1101, which breaks completely on migen +#pylint:disable=E1101 + +#from migen import * +from litex.build.xilinx import VivadoProgrammer, XilinxPlatform +from litex.build.generic_platform import Pins, IOStandard +from litex.soc.integration import SoCSDRAM +from litex.soc.integration.builder import Builder +from litex.soc.integration.soc_core import csr_map_update + +_io = [ + ("clk50", 0, Pins("J19"), IOStandard("LVCMOS33")), +] + +class Platform(XilinxPlatform): + def __init__(self, toolchain="vivado", programmer="vivado", part="35"): + part = "xc7a" + part + "t-fgg484-2" + def create_programmer(self): + if self.programmer == "vivado": + return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") + else: + raise ValueError("{} programmer is not supported" + .format(self.programmer)) + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + +class BaseSoC(SoCSDRAM): + csr_peripherals = [ + "ddrphy", +# "dna", + "xadc", + "cpu_or_bridge", + ] + csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + + def __init__(self, platform, **kwargs): + # clk_freq = int(100e6) + self.integrated_main_ram_size = 8192 + self.add_memory() + +def main(): + platform = Platform() + soc = BaseSoC(platform) + builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv") + vns = builder.build() + soc.do_exit(vns) + +if __name__ == "__main__": + main() diff --git a/lxbuildenv.py b/lxbuildenv.py new file mode 100644 index 0000000..2b6d29f --- /dev/null +++ b/lxbuildenv.py @@ -0,0 +1,493 @@ +#!/usr/bin/env python3 + +# This script enables easy, cross-platform building without the need +# to install third-party Python modules. + +import sys +import os +import subprocess +import argparse + + +DEPS_DIR = "deps" + +DEFAULT_DEPS = { + 'migen': 'https://github.com/m-labs/migen.git', + 'litex': 'https://github.com/enjoy-digital/litex.git', + 'litescope': 'https://github.com/enjoy-digital/litescope.git', + 'pyserial': 'https://github.com/pyserial/pyserial.git', + 'liteeth': 'https://github.com/enjoy-digital/liteeth.git', + 'liteusb': 'https://github.com/enjoy-digital/liteusb.git', + 'litedram': 'https://github.com/enjoy-digital/litedram.git', + 'litepcie': 'https://github.com/enjoy-digital/litepcie.git', + 'litesdcard': 'https://github.com/enjoy-digital/litesdcard.git', + 'liteiclink': 'https://github.com/enjoy-digital/liteiclink.git', + 'litevideo': 'https://github.com/enjoy-digital/litevideo.git', +} + +# Obtain the path to this script, plus a trailing separator. This will +# be used later on to construct various environment variables for paths +# to a variety of support directories. +script_path = os.path.dirname(os.path.realpath(__file__)) + os.path.sep + +# Look through the specified file for known variables to get the dependency list +def get_required_dependencies(filename): + import ast + + # Always check the Python version + dependencies = { + 'python': 1 + } + main_src = "" + + try: + with open(sys.argv[0], 'r') as f: + main_src = f.read() + main_ast = ast.parse(main_src, filename=filename) + except: + return list(dependencies.keys()) + + # Iterate through the top-level nodes looking for variables named + # LX_DEPENDENCIES or LX_DEPENDENCY and get the values that are + # assigned to them. + for node in ast.iter_child_nodes(main_ast): + if isinstance(node, ast.Assign): + value = node.value + for target in node.targets: + if isinstance(target, ast.Name): + if target.id == "LX_DEPENDENCIES" or target.id == "LX_DEPENDENCY": + if isinstance(value, (ast.List, ast.Tuple)): + for elt in value.elts: + if isinstance(elt, ast.Str): + dependencies[elt.s] = 1 + elif isinstance(value, ast.Str): + dependencies[value.s] = 1 + + # Set up sub-dependencies + if 'riscv' in dependencies: + dependencies['make'] = 1 + return list(dependencies.keys()) + +def get_python_path(script_path, args): + # Python has no concept of a local dependency path, such as the C `-I`` + # switch, or the nodejs `node_modules` path, or the rust cargo registry. + # Instead, it relies on an environment variable to append to the search + # path. + # Construct this variable by adding each subdirectory under the `deps/` + # directory to the PYTHONPATH environment variable. + python_path = [] + if os.path.isdir(script_path + DEPS_DIR): + for dep in os.listdir(script_path + DEPS_DIR): + dep = script_path + DEPS_DIR + os.path.sep + dep + if os.path.isdir(dep): + python_path.append(dep) + return python_path + +def fixup_env(script_path, args): + os.environ["PYTHONPATH"] = os.pathsep.join(get_python_path(script_path, 0)) + + # Set the "LXBUILDENV_REEXEC" variable to prevent the script from continuously + # reinvoking itself. + os.environ["LXBUILDENV_REEXEC"] = "1" + + # Python randomizes the order in which it traverses hashes, and Migen uses + # hashes an awful lot when bringing together modules. As such, the order + # in which Migen generates its output Verilog will change with every run, + # and the addresses for various modules will change. + # Make builds deterministic so that the generated Verilog code won't change + # across runs. + os.environ["PYTHONHASHSEED"] = "1" + + # Some Makefiles are invoked as part of the build process, and those Makefiles + # occasionally have calls to Python. Ensure those Makefiles use the same + # interpreter that this script is using. + os.environ["PYTHON"] = sys.executable + + # Set the environment variable "V" to 1. This causes Makefiles to print + # the commands they run, which makes them easier to debug. + if "lx_verbose" in args and args.lx_verbose: + os.environ["V"] = "1" + + # If the user just wanted to print the environment variables, do that and quit. + if args.lx_print_env: + print("PYTHONPATH={}".format(os.environ["PYTHONPATH"])) + print("PYTHONHASHSEED={}".format(os.environ["PYTHONHASHSEED"])) + print("PYTHON={}".format(sys.executable)) + print("LXBUILDENV_REEXEC={}".format(os.environ["LXBUILDENV_REEXEC"])) + + sys.exit(0) + +# Equivalent to the powershell Get-Command, and kinda like `which` +def get_command(cmd): + if os.name == 'nt': + path_ext = os.environ["PATHEXT"].split(os.pathsep) + else: + path_ext = [""] + for ext in path_ext: + for path in os.environ["PATH"].split(os.pathsep): + + if os.path.exists(path + os.path.sep + cmd + ext): + return path + os.path.sep + cmd + ext + return None + +def check_python_version(args): + import platform + # Litex / Migen require Python 3.5 or newer. Ensure we're running + # under a compatible version of Python. + if sys.version_info[:3] < (3, 5): + return (False, + "python: You need Python 3.5+ (version {} found)".format(sys.version_info[:3])) + return (True, "python 3.5+: ok (Python {} found)".format(platform.python_version())) + +def check_vivado(args): + vivado_path = get_command("vivado") + if vivado_path == None: + # Look for the default Vivado install directory + if os.name == 'nt': + base_dir = r"C:\Xilinx\Vivado" + else: + base_dir = "/opt/Xilinx/Vivado" + if os.path.exists(base_dir): + for file in os.listdir(base_dir): + bin_dir = base_dir + os.path.sep + file + os.path.sep + "bin" + if os.path.exists(bin_dir + os.path.sep + "vivado"): + os.environ["PATH"] += os.pathsep + bin_dir + vivado_path = bin_dir + break + if vivado_path == None: + return (False, "toolchain not found in your PATH", "download it from https://www.xilinx.com/support/download.html") + return (True, "found at {}".format(vivado_path)) + +def check_cmd(args, cmd, name=None, fix=None): + if name is None: + name = cmd + path = get_command(cmd) + if path == None: + return (False, name + " not found in your PATH", fix) + return (True, "found at {}".format(path)) + +def check_make(args): + return check_cmd(args, "make", "GNU Make") + +def check_riscv(args): + return check_cmd(args, "riscv64-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/products/tools/") + +def check_yosys(args): + return check_cmd(args, "yosys") + +def check_arachne(args): + return check_cmd(args, "arachne-pnr") + +dependency_checkers = { + 'python': check_python_version, + 'vivado': check_vivado, + 'make': check_make, + 'riscv': check_riscv, + 'yosys': check_yosys, + 'arachne-pnr': check_arachne, +} + +# Validate that the required dependencies (Vivado, compilers, etc.) +# have been installed. +def check_dependencies(args, dependency_list): + + dependency_errors = 0 + for dependency_name in dependency_list: + if not dependency_name in dependency_checkers: + print('WARNING: Unrecognized dependency "{}"'.format(dependency_name)) + continue + result = dependency_checkers[dependency_name](args) + if result[0] == False: + if len(result) > 2: + print('{}: {} -- {}'.format(dependency_name, result[1], result[2])) + else: + print('{}: {}'.format(dependency_name, result[1])) + dependency_errors = dependency_errors + 1 + + elif args.lx_check_deps or args.lx_verbose: + print('dependency: {}: {}'.format(dependency_name, result[1])) + if dependency_errors > 0: + if args.lx_ignore_deps: + print('{} missing dependencies were found but continuing anyway'.format(dependency_errors)) + else: + raise SystemExit(str(dependency_errors) + + " missing dependencies were found") + + if args.lx_check_deps: + sys.exit(0) + +# Return True if the given tree needs to be initialized +def check_module_recursive(root_path, depth, verbose=False): + if verbose: + print('git-dep: checking if "{}" requires updating...'.format(root_path)) + # If the directory isn't a valid git repo, initialization is required + if not os.path.exists(root_path + os.path.sep + '.git'): + return True + + # If there are no submodules, no initialization needs to be done + if not os.path.isfile(root_path + os.path.sep + '.gitmodules'): + return False + + # Loop through the gitmodules to check all submodules + gitmodules = open(root_path + os.path.sep + '.gitmodules', 'r') + for line in gitmodules: + parts = line.split("=", 2) + if parts[0].strip() == "path": + path = parts[1].strip() + if check_module_recursive(root_path + os.path.sep + path, depth + 1, verbose=verbose): + return True + return False + +# Determine whether we need to invoke "git submodules init --recurse" +def check_submodules(script_path, args): + if check_module_recursive(script_path, 0, verbose=args.lx_verbose): + print("Missing submodules -- updating") + subprocess.Popen(["git", "submodule", "update", + "--init", "--recursive"], cwd=script_path).wait() + elif args.lx_verbose: + print("Submodule check: Submodules found") + + +def lx_git(cmd, *args): + import subprocess + git_cmd = ["git", cmd] + if args is not None: + for arg in args: + git_cmd = git_cmd + [arg] + subprocess.call(git_cmd) + +def lx_print_deps(): + print('Known dependencies:') + for dep in dependency_checkers.keys(): + print(' {}'.format(dep)) + print('To define a dependency, add a variable inside {} at the top level called LX_DEPENDENCIES and assign it a list or tuple.'.format(sys.argv[0])) + print('For example:') + print('LX_DEPENDENCIES = ("riscv", "vivado")') + + +def lx_main(args): + if args.lx_print_env: + fixup_env(script_path, args) + + elif args.lx_print_deps: + lx_print_deps() + + elif args.init: + if args.main is None: + main_name = os.getcwd().split(os.path.sep)[-1] + '.py' + new_main_name = input('What would you like your main program to be called? [' + main_name + '] ') + if new_main_name is not None and new_main_name != "": + main_name = new_main_name + else: + main_name = args.main + if not main_name.endswith('.py'): + main_name = main_name + '.py' + + if args.no_git: + print("skipping git initialization") + else: + if not os.path.exists(DEPS_DIR): + os.mkdir(DEPS_DIR) + + if not os.path.exists(".git"): + print("initializing git repository") + lx_git('init') + else: + print("using existing git repository") + lx_git('add', str(__file__)) + + for dep_name, dep_url in DEFAULT_DEPS.items(): + dest_path = '{}{}{}'.format(DEPS_DIR, '/', dep_name) + if not os.path.exists(dest_path): + lx_git('submodule', 'add', dep_url, dest_path) + lx_git('add', dest_path) + + lx_git('submodule', 'update', '--init', '--recursive') + + if args.no_bin: + print("skipping bin/ initialization") + elif os.path.exists("bin"): + print("bin/ directory exists -- remove bin/ directory to re-initialize") + else: + bin_tools = { + 'mkmscimg': 'litex.soc.tools.mkmscimg', + 'litex_term': 'litex.utils.litex_term', + 'litex_server': 'litex.utils.litex_server', + 'litex_sim': 'litex.utils.litex_sim', + 'litex_read_verilog': 'litex.utils.litex_read_verilog', + 'litex_simple': 'litex.boards.targets.simple', + } + bin_template = """#!/usr/bin/env python3 + +import sys +import os + +# This script lives in the "bin" directory, but uses a helper script in the parent +# directory. Obtain the current path so we can get the absolute parent path. +script_path = os.path.dirname(os.path.realpath( + __file__)) + os.path.sep + os.path.pardir + os.path.sep +sys.path.insert(0, script_path) +import lxbuildenv + +""" + print("Creating binaries") + os.mkdir("bin") + for bin_name, python_module in bin_tools.items(): + with open('bin' + os.path.sep + bin_name, 'w') as new_bin: + new_bin.write(bin_template) + new_bin.write('from ' + python_module + ' import main\n') + new_bin.write('main()\n') + import stat + os.chmod('bin' + os.path.sep + bin_name, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + if not args.no_git: + lx_git('add', '--chmod=+x', 'bin' + os.path.sep + bin_name) + + if os.path.exists(main_name): + print("skipping creation of {}: file exists".format(main_name)) + else: + print("creating main program {}".format(main_name)) + with open(main_name, 'w') as m: + program_template = """#!/usr/bin/env python3 +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["riscv", "vivado"] + +# Import lxbuildenv to integrate the deps/ directory +import lxbuildenv + +# Disable pylint's E1101, which breaks completely on migen +#pylint:disable=E1101 + +from migen import * +from litex.build.generic_platform import * + +_io = [ + ("clk50", 0, Pins("J19"), IOStandard("LVCMOS33")), +] + +class Platform(XilinxPlatform): + def __init__(self, toolchain="vivado", programmer="vivado", part="35"): + part = "xc7a" + part + "t-fgg484-2" + def create_programmer(self): + if self.programmer == "vivado": + return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") + else: + raise ValueError("{} programmer is not supported" + .format(self.programmer)) + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + +class BaseSoC(SoCSDRAM): + csr_peripherals = [ + "ddrphy", +# "dna", + "xadc", + "cpu_or_bridge", + ] + csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + + def __init__(self, platform, **kwargs): + clk_freq = int(100e6) + +def main(): + platform = Platform() + soc = BaseSoC(platform) + builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv") + vns = builder.build() + soc.do_exit(vns) + +if __name__ == "__main__": + main() +""" + m.write(program_template) + if not args.no_git: + lx_git("add", main_name) + else: + return False + return True + +# For the main command, parse args and hand it off to main() +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Wrap Python code to enable quickstart", + add_help=False) + parser.add_argument( + "-h", "--help", '--lx-help', help="show this help message and exit", action="help" + ) + parser.add_argument( + '-i', '--init', '--lx-init', help='initialize a new project', action="store_true" + ) + parser.add_argument( + '-m', '--main', '--lx-main', help='name of main project' + ) + parser.add_argument( + '--no-bin', '--lx-no-bin', help="don't create a bin/ directory" + ) + parser.add_argument( + '--no-git', '--lx-no-git', help="Don't create a git repository" + ) + parser.add_argument( + '-e', '--print-env', '--lx-print-env', dest="lx_print_env", help="print environment variable listing for pycharm, vscode, or bash", action="store_true" + ) + parser.add_argument( + '-d', '--print-deps', '--lx-print-deps', dest="lx_print_deps", help="print all possible dependencies and then exit", action="store_true" + ) + args = parser.parse_args() + + if not lx_main(args): + parser.print_help() + +elif not os.path.isfile(sys.argv[0]): + print("lxbuildenv doesn't operate while in interactive mode") + +elif "LXBUILDENV_REEXEC" not in os.environ: + parser = argparse.ArgumentParser( + description="Wrap Python code to enable quickstart", + add_help=False) + parser.add_argument( + "--lx-verbose", help="increase verboseness of some processes", action="store_true" + ) + parser.add_argument( + "--lx-print-env", help="print environment variable listing for pycharm, vscode, or bash", action="store_true" + ) + parser.add_argument( + "--lx-check-deps", help="check build environment for dependencies such as compiler and fpga tools and then exit", action="store_true" + ) + parser.add_argument( + "--lx-print-deps", help="print all possible dependencies and then exit", action="store_true" + ) + parser.add_argument( + "--lx-help", action="help" + ) + parser.add_argument( + "--lx-ignore-deps", help="try building even if dependencies are missing", action="store_true" + ) + (args, rest) = parser.parse_known_args() + + if args.lx_print_deps: + lx_print_deps() + sys.exit(0) + + deps = get_required_dependencies(sys.argv[0]) + + fixup_env(script_path, args) + check_dependencies(args, deps) + check_submodules(script_path, args) + + try: + sys.exit(subprocess.Popen( + [sys.executable] + [sys.argv[0]] + rest).wait()) + except: + sys.exit(1) +else: + # Overwrite the deps directory. + # Because we're running with a predefined PYTHONPATH, you'd think that + # the DEPS_DIR would be first. + # Unfortunately, setuptools causes the sitewide packages to take precedence + # over the PYTHONPATH variable. + # Work around this bug by inserting paths into the first index. + for path in get_python_path(script_path, None): + sys.path.insert(0, path) From f9eeee3ff7febae29ddcd967edab75612251dc0a Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 10:48:57 +0800 Subject: [PATCH 02/23] lxbuildenv: fix generation of initial python It still doesn't work (owing to some bit rot), but it's better now. Signed-off-by: Sean Cross --- lxbuildenv.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lxbuildenv.py b/lxbuildenv.py index 2b6d29f..876c312 100644 --- a/lxbuildenv.py +++ b/lxbuildenv.py @@ -178,6 +178,9 @@ def check_yosys(args): def check_arachne(args): return check_cmd(args, "arachne-pnr") +def check_icestorm(args): + return check_cmd(args, "icepack") and check_cmd(args, "nextpnr-ice40") + dependency_checkers = { 'python': check_python_version, 'vivado': check_vivado, @@ -185,6 +188,7 @@ dependency_checkers = { 'riscv': check_riscv, 'yosys': check_yosys, 'arachne-pnr': check_arachne, + 'icestorm': check_icestorm, } # Validate that the required dependencies (Vivado, compilers, etc.) @@ -361,7 +365,11 @@ import lxbuildenv #pylint:disable=E1101 from migen import * -from litex.build.generic_platform import * +from litex.build.xilinx import VivadoProgrammer, XilinxPlatform +from litex.build.generic_platform import Pins, IOStandard +from litex.soc.integration import SoCSDRAM +from litex.soc.integration.builder import Builder +from litex.soc.integration.soc_core import csr_map_update _io = [ ("clk50", 0, Pins("J19"), IOStandard("LVCMOS33")), From 7f77c49c7b7f7e567b8ccb0a7bbc731f36d2ed98 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 11:06:35 +0800 Subject: [PATCH 03/23] lx-socsupport: add submodule Signed-off-by: Sean Cross --- .gitmodules | 3 +++ deps/lx-socsupport | 1 + 2 files changed, 4 insertions(+) create mode 160000 deps/lx-socsupport diff --git a/.gitmodules b/.gitmodules index df98602..8709ee3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "deps/litevideo"] path = deps/litevideo url = https://github.com/enjoy-digital/litevideo.git +[submodule "deps/lx-socsupport"] + path = deps/lx-socsupport + url = https://github.com/xobs/lx-socsupport.git diff --git a/deps/lx-socsupport b/deps/lx-socsupport new file mode 160000 index 0000000..b198653 --- /dev/null +++ b/deps/lx-socsupport @@ -0,0 +1 @@ +Subproject commit b19865396c699a5c6ec0062867fff5b7d84c2483 From ea7e99af5b2f34bf52f76d86fa8aa8dbbb6f7768 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 12:10:15 +0800 Subject: [PATCH 04/23] deps: change lx-socsupport to lxsocsupport Signed-off-by: Sean Cross --- .gitmodules | 6 +++--- deps/{lx-socsupport => lxsocsupport} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename deps/{lx-socsupport => lxsocsupport} (100%) diff --git a/.gitmodules b/.gitmodules index 8709ee3..c3677ef 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,6 +31,6 @@ [submodule "deps/litevideo"] path = deps/litevideo url = https://github.com/enjoy-digital/litevideo.git -[submodule "deps/lx-socsupport"] - path = deps/lx-socsupport - url = https://github.com/xobs/lx-socsupport.git +[submodule "deps/lxsocsupport"] + path = deps/lxsocsupport + url = https://github.com/xobs/lxsocsupport.git diff --git a/deps/lx-socsupport b/deps/lxsocsupport similarity index 100% rename from deps/lx-socsupport rename to deps/lxsocsupport From 245a466654d6ae14fbda0cc3971c62cc7b8d91bf Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 12:42:06 +0800 Subject: [PATCH 05/23] lxsocsupport: ignore pycache files Signed-off-by: Sean Cross --- deps/lxsocsupport | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/lxsocsupport b/deps/lxsocsupport index b198653..74f1333 160000 --- a/deps/lxsocsupport +++ b/deps/lxsocsupport @@ -1 +1 @@ -Subproject commit b19865396c699a5c6ec0062867fff5b7d84c2483 +Subproject commit 74f133340144630e000f91e466ac5107f87a8d5a From ee006eff907d6947e3e1714335c762db60eebd53 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 12:43:09 +0800 Subject: [PATCH 06/23] deps: add valentyusb Signed-off-by: Sean Cross --- .gitmodules | 3 +++ deps/valentyusb | 1 + 2 files changed, 4 insertions(+) create mode 160000 deps/valentyusb diff --git a/.gitmodules b/.gitmodules index c3677ef..a9d43a4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "deps/lxsocsupport"] path = deps/lxsocsupport url = https://github.com/xobs/lxsocsupport.git +[submodule "deps/valentyusb"] + path = deps/valentyusb + url = https://github.com/xobs/valentyusb.git diff --git a/deps/valentyusb b/deps/valentyusb new file mode 160000 index 0000000..8eadbae --- /dev/null +++ b/deps/valentyusb @@ -0,0 +1 @@ +Subproject commit 8eadbae40146cf0ac1abcaf511a5f96eb94d336d From 21cdcaaee8dfe554f968ed9574ce9c752f26d58a Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 12:43:29 +0800 Subject: [PATCH 07/23] foboot-bitstream: first full build This actually compiles now, hooray! But does it work? No. Signed-off-by: Sean Cross --- foboot-bitstream.py | 185 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 161 insertions(+), 24 deletions(-) diff --git a/foboot-bitstream.py b/foboot-bitstream.py index 1317c3b..76589a5 100644 --- a/foboot-bitstream.py +++ b/foboot-bitstream.py @@ -12,47 +12,184 @@ import lxbuildenv #pylint:disable=E1101 #from migen import * -from litex.build.xilinx import VivadoProgrammer, XilinxPlatform -from litex.build.generic_platform import Pins, IOStandard -from litex.soc.integration import SoCSDRAM +from migen import Module, Signal, Instance, ClockDomain, If +from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.build.lattice.platform import LatticePlatform +from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal +from litex.soc.integration import SoCCore from litex.soc.integration.builder import Builder from litex.soc.integration.soc_core import csr_map_update +from litex.soc.interconnect import wishbone + +from lxsocsupport import up5kspram, cas, spi_flash + +import argparse _io = [ - ("clk50", 0, Pins("J19"), IOStandard("LVCMOS33")), + ("serial", 0, + Subsignal("rx", Pins("21")), + Subsignal("tx", Pins("13"), Misc("PULLUP")), + IOStandard("LVCMOS33") + ), + ("clk48", 0, Pins("44"), IOStandard("LVCMOS33")) ] -class Platform(XilinxPlatform): - def __init__(self, toolchain="vivado", programmer="vivado", part="35"): - part = "xc7a" + part + "t-fgg484-2" +_connectors = [] + +class _CRG(Module): + def __init__(self, platform): + clk12 = Signal() + # "0b00" Sets 48MHz HFOSC output + # "0b01" Sets 24MHz HFOSC output. + # "0b10" Sets 12MHz HFOSC output. + # "0b11" Sets 6MHz HFOSC output + self.specials += Instance( + "SB_HFOSC", + i_CLKHFEN=1, + i_CLKHFPU=1, + o_CLKHF=clk12, + p_CLKHF_DIV="0b10", # 12MHz + ) + + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_usb_12 = ClockDomain() + self.reset = Signal() + + # FIXME: Use PLL, increase system clock to 32 MHz, pending nextpnr + # fixes. + self.comb += self.cd_sys.clk.eq(clk12) + self.comb += self.cd_usb_12.clk.eq(clk12) + + # POR reset logic- POR generated from sys clk, POR logic feeds sys clk + # reset. + self.clock_domains.cd_por = ClockDomain() + reset_delay = Signal(12, reset=4095) + self.comb += [ + self.cd_por.clk.eq(self.cd_sys.clk), + self.cd_sys.rst.eq(reset_delay != 0), + self.cd_usb_12.rst.eq(reset_delay != 0) + ] + self.sync.por += \ + If(reset_delay != 0, + reset_delay.eq(reset_delay - 1) + ) + self.specials += AsyncResetSynchronizer(self.cd_por, self.reset) + + self.clock_domains.cd_usb_48 = ClockDomain() + platform.add_period_constraint(self.cd_usb_48.clk, 1e9/48e6) + self.comb += [ + self.cd_usb_48.clk.eq(platform.request("clk48")), + ] + +class RandomFirmwareROM(wishbone.SRAM): + def __init__(self, size, seed=2373): + import random + # Seed the random data with a fixed number, so different bitstreams + # can all share firmware. + random.seed(seed) + data = [] + for d in range(int(size / 4)): + data.append(random.getrandbits(32)) + print("Firmware {} bytes of random data".format(size)) + wishbone.SRAM.__init__(self, size, read_only=True, init=data) + +class Platform(LatticePlatform): + def __init__(self, toolchain="icestorm"): + LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, toolchain="icestorm") def create_programmer(self): - if self.programmer == "vivado": - return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") - else: - raise ValueError("{} programmer is not supported" - .format(self.programmer)) + raise ValueError("programming is not supported") def do_finalize(self, fragment): - XilinxPlatform.do_finalize(self, fragment) + LatticePlatform.do_finalize(self, fragment) -class BaseSoC(SoCSDRAM): +class BaseSoC(SoCCore): csr_peripherals = [ - "ddrphy", -# "dna", - "xadc", "cpu_or_bridge", ] - csr_map_update(SoCSDRAM.csr_map, csr_peripherals) + csr_map_update(SoCCore.csr_map, csr_peripherals) - def __init__(self, platform, **kwargs): - # clk_freq = int(100e6) - self.integrated_main_ram_size = 8192 - self.add_memory() + mem_map = { + "spiflash": 0x20000000, # (default shadow @0xa0000000) + } + mem_map.update(SoCCore.mem_map) + + gateware_size = 0x20000 + + def __init__(self, platform, boot_source="random_rom", **kwargs): + # Disable integrated RAM as we'll add it later + self.integrated_sram_size = 0 + + clk_freq = int(12e6) + self.submodules.crg = _CRG(platform) + platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq) + platform.add_period_constraint(self.crg.cd_usb_12.clk, 1e9/clk_freq) + + SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, **kwargs) + + # SPRAM- UP5K has single port RAM, might as well use it as SRAM to + # free up scarce block RAM. + spram_size = 128*1024 + self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size) + self.register_mem("sram", 0x10000000, self.spram.bus, spram_size) + + if boot_source == "random_rom": + kwargs['cpu_reset_address']=0 + bios_size = 0x2000 + self.submodules.random_rom = RandomFirmwareROM(bios_size) + self.add_constant("ROM_DISABLE", 1) + self.register_rom(self.random_rom.bus, bios_size) + elif boot_source == "bios_rom": + kwargs['cpu_reset_address']=0 + bios_size = 0x2000 + self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) + elif boot_source == "spi_rom": + bios_size = 0x8000 + kwargs['cpu_reset_address']=self.mem_map["spiflash"]+self.gateware_size + self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) + self.add_constant("ROM_DISABLE", 1) + self.flash_boot_address = self.mem_map["spiflash"]+self.gateware_size+bios_size + self.add_memory_region("user_flash", + self.flash_boot_address, + # Leave a grace area- possible one-by-off bug in add_memory_region? + # Possible fix: addr < origin + length - 1 + platform.spiflash_total_size - (self.flash_boot_address - self.mem_map["spiflash"]) - 0x100) + else: + raise ValueError("unrecognized boot_source: {}".format(boot_source)) + + # Disable final deep-sleep power down so firmware words are loaded + # onto softcore's address bus. + platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin" + platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin" def main(): platform = Platform() - soc = BaseSoC(platform) - builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv") + + parser = argparse.ArgumentParser( + description="Build Fomu Main Gateware", + add_help=False) + parser.add_argument( + "--bios", help="use bios as boot source", action="store_true" + ) + parser.add_argument( + "--rand", help="use random data as boot source", action="store_false" + ) + parser.add_argument( + "--spi", help="boot from spi", action="store_true" + ) + (args, rest) = parser.parse_known_args() + + if args.rand: + boot_source="random_rom" + compile_software=False + elif args.bios: + boot_source="bios_rom" + compile_software=True + elif args.spi: + boot_source = "spi_rom" + compile_software = False + + soc = BaseSoC(platform, cpu_type="vexriscv", cpu_variant="min", boot_source=boot_source) + builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv", compile_software=compile_software) vns = builder.build() soc.do_exit(vns) From 30d5a097d2bc64c739f654166df361385efd5f59 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 12:44:19 +0800 Subject: [PATCH 08/23] gitignore: ignore env, build, pycache Signed-off-by: Sean Cross --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2f21ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +__pycache__/ +.env \ No newline at end of file From e66f909bfdaaeb2bebd4b67040237d205f7cb598 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 18 Feb 2019 13:54:26 +0800 Subject: [PATCH 09/23] lxbuildenv: add '-r' command to run modules under lxbuildenv This will allow us to e.g. run tests. Signed-off-by: Sean Cross --- lxbuildenv.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lxbuildenv.py b/lxbuildenv.py index 876c312..d09da85 100644 --- a/lxbuildenv.py +++ b/lxbuildenv.py @@ -276,6 +276,18 @@ def lx_main(args): elif args.lx_print_deps: lx_print_deps() + elif args.lx_run is not None: + script_name=args.lx_run[0] + get_required_dependencies(script_name) + + fixup_env(script_path, args) + check_submodules(script_path, args) + + try: + sys.exit(subprocess.Popen( + [sys.executable] + [script_name] + args.lx_run[1:]).wait()) + except: + sys.exit(1) elif args.init: if args.main is None: main_name = os.getcwd().split(os.path.sep)[-1] + '.py' @@ -443,6 +455,12 @@ if __name__ == "__main__": parser.add_argument( '-d', '--print-deps', '--lx-print-deps', dest="lx_print_deps", help="print all possible dependencies and then exit", action="store_true" ) + parser.add_argument( + "--lx-verbose", help="increase verboseness of some processes", action="store_true" + ) + parser.add_argument( + '-r', '--run', '--lx-run', dest='lx_run', help="run the given script under lxbuildenv", nargs=argparse.REMAINDER + ) args = parser.parse_args() if not lx_main(args): From 49b22a19625614bd25f9fbef8861ada3c3740bea Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 15:16:19 +0800 Subject: [PATCH 10/23] foboot-bitstream: use new-style random rom Use a new pattern with a new function to generate the random ROM, used for ROM patching. Signed-off-by: Sean Cross --- foboot-bitstream.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/foboot-bitstream.py b/foboot-bitstream.py index 76589a5..ae1430a 100644 --- a/foboot-bitstream.py +++ b/foboot-bitstream.py @@ -82,14 +82,29 @@ class _CRG(Module): ] class RandomFirmwareROM(wishbone.SRAM): + """ + Seed the random data with a fixed number, so different bitstreams + can all share firmware. + """ def __init__(self, size, seed=2373): - import random - # Seed the random data with a fixed number, so different bitstreams - # can all share firmware. - random.seed(seed) + def xorshift32(x): + x = x ^ (x << 13) & 0xffffffff + x = x ^ (x >> 17) & 0xffffffff + x = x ^ (x << 5) & 0xffffffff + return x & 0xffffffff + + def get_rand(x): + out = 0 + for i in range(32): + x = xorshift32(x) + if (x & 1) == 1: + out = out | (1 << i) + return out & 0xffffffff data = [] + seed = 1 for d in range(int(size / 4)): - data.append(random.getrandbits(32)) + seed = get_rand(seed) + data.append(seed) print("Firmware {} bytes of random data".format(size)) wishbone.SRAM.__init__(self, size, read_only=True, init=data) From 8b54d5addb8cd9f00bc1b9c6cd5a84331b003653 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:19:01 +0800 Subject: [PATCH 11/23] csr-test: add simple program to test CSRs Signed-off-by: Sean Cross --- csr-test.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 csr-test.py diff --git a/csr-test.py b/csr-test.py new file mode 100644 index 0000000..c4f5d7e --- /dev/null +++ b/csr-test.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["riscv", "icestorm", "yosys"] + +# Import lxbuildenv to integrate the deps/ directory +import lxbuildenv + +# Disable pylint's E1101, which breaks completely on migen +#pylint:disable=E1101 + +from migen import Module, Signal, Instance, ClockDomain, If, run_simulation +from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.build.lattice.platform import LatticePlatform +from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal +from litex.soc.integration import SoCCore +from litex.soc.integration.builder import Builder +from litex.soc.integration.soc_core import csr_map_update +from litex.soc.interconnect import wishbone +from litex.soc.interconnect.csr import CSR, CSRStorage, AutoCSR + +def csr_test(dut): + for i in range(20): + counter = yield dut.counter + # test_value = yield dut.test_value.w + (test_value) = yield from dut.test_value.read() + print("CSR value: {} / {}".format(counter, test_value)) + # yield from CSRStorage.update_csrs() + yield + +class TestCSR(Module, AutoCSR): + def __init__(self): + # self.counter = Signal(8) + # self.test_value = CSR(8) + # self.result = Signal(8) + # self.read_result = Signal() + # self.sync += [ + # self.counter.eq(self.counter+1), + # self.test_value.w.eq(self.counter), + # self.result.eq(self.test_value.r), + # self.read_result.eq(self.test_value.re), + # ] + self.counter = Signal(8) + self.test_value = CSRStorage(8, write_from_dev=True) + self.result = Signal(8) + self.result_re = Signal() + self.sync += [ + self.counter.eq(self.counter+1), + self.test_value.we.eq(1), + self.test_value.dat_w.eq(self.counter), + self.result.eq(self.test_value.storage), + self.result_re.eq(self.test_value.re), + ] + +def main(): + dut = TestCSR() + for x in dir(dut): + print("x: {}".format(x)) + for csr in dut.get_csrs(): + print("csr: {}".format(csr)) + if isinstance(csr, CSRStorage) and hasattr(csr, "dat_w"): + print("Adding CSRStorage patch") + dut.sync += [ + If(csr.we, + csr.storage.eq(csr.dat_w), + csr.re.eq(1), + ).Else( + csr.re.eq(0), + ) + ] + run_simulation(dut, csr_test(dut), vcd_name="csr-test.vcd") + +if __name__ == "__main__": + main() From 6771d28fb48e595e6900988cad00053757095a9e Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:19:17 +0800 Subject: [PATCH 12/23] foboot-bitstream: work-in-progress commit Signed-off-by: Sean Cross --- foboot-bitstream.py | 52 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/foboot-bitstream.py b/foboot-bitstream.py index ae1430a..c2c7dc9 100644 --- a/foboot-bitstream.py +++ b/foboot-bitstream.py @@ -21,6 +21,11 @@ from litex.soc.integration.builder import Builder from litex.soc.integration.soc_core import csr_map_update from litex.soc.interconnect import wishbone +from valentyusb import usbcore +from valentyusb.usbcore import io as usbio +from valentyusb.usbcore.cpu import epmem, unififo, epfifo +from valentyusb.usbcore.endpoint import EndpointType + from lxsocsupport import up5kspram, cas, spi_flash import argparse @@ -31,6 +36,25 @@ _io = [ Subsignal("tx", Pins("13"), Misc("PULLUP")), IOStandard("LVCMOS33") ), + ("usb", 0, + Subsignal("d_p", Pins("34")), + Subsignal("d_n", Pins("37")), + Subsignal("pullup", Pins("35")), + IOStandard("LVCMOS33") + ), + ("spiflash", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")), + Subsignal("wp", Pins("18"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("19"), IOStandard("LVCMOS33")), + ), + ("spiflash4x", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("dq", Pins("14 17 19 18"), IOStandard("LVCMOS33")), + ), ("clk48", 0, Pins("44"), IOStandard("LVCMOS33")) ] @@ -109,17 +133,25 @@ class RandomFirmwareROM(wishbone.SRAM): wishbone.SRAM.__init__(self, size, read_only=True, init=data) class Platform(LatticePlatform): + default_clk_name = "clk48" + default_clk_period = 20.833 + + gateware_size = 0x20000 + def __init__(self, toolchain="icestorm"): LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, toolchain="icestorm") def create_programmer(self): raise ValueError("programming is not supported") - def do_finalize(self, fragment): - LatticePlatform.do_finalize(self, fragment) + # def do_finalize(self, fragment): + # LatticePlatform.do_finalize(self, fragment) class BaseSoC(SoCCore): csr_peripherals = [ "cpu_or_bridge", + "usb", + "usb_obuf", + "usb_ibuf", ] csr_map_update(SoCCore.csr_map, csr_peripherals) @@ -128,7 +160,10 @@ class BaseSoC(SoCCore): } mem_map.update(SoCCore.mem_map) - gateware_size = 0x20000 + interrupt_map = { + "usb": 3, + } + interrupt_map.update(SoCCore.interrupt_map) def __init__(self, platform, boot_source="random_rom", **kwargs): # Disable integrated RAM as we'll add it later @@ -159,10 +194,10 @@ class BaseSoC(SoCCore): self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) elif boot_source == "spi_rom": bios_size = 0x8000 - kwargs['cpu_reset_address']=self.mem_map["spiflash"]+self.gateware_size + kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) self.add_constant("ROM_DISABLE", 1) - self.flash_boot_address = self.mem_map["spiflash"]+self.gateware_size+bios_size + self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size self.add_memory_region("user_flash", self.flash_boot_address, # Leave a grace area- possible one-by-off bug in add_memory_region? @@ -171,6 +206,13 @@ class BaseSoC(SoCCore): else: raise ValueError("unrecognized boot_source: {}".format(boot_source)) + # Add USB pads + usb_pads = platform.request("usb") + usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup) + self.submodules.usb = epfifo.PerEndpointFifoInterface(usb_iobuf, endpoints=[EndpointType.BIDIR]) + # self.submodules.usb = epmem.MemInterface(usb_iobuf) + # self.submodules.usb = unififo.UsbUniFifo(usb_iobuf) + # Disable final deep-sleep power down so firmware words are loaded # onto softcore's address bus. platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin" From 7caff80f6be485927cc1d92d5f2b56ac440ecfe9 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:21:23 +0800 Subject: [PATCH 13/23] foboot-bitstream: change line endings These matter on non-Windows machines. Signed-off-by: Sean Cross --- foboot-bitstream.py | 508 ++++++++++++++++++++++---------------------- 1 file changed, 254 insertions(+), 254 deletions(-) diff --git a/foboot-bitstream.py b/foboot-bitstream.py index c2c7dc9..ed64e34 100644 --- a/foboot-bitstream.py +++ b/foboot-bitstream.py @@ -1,254 +1,254 @@ -#!/usr/bin/env python3 -# This variable defines all the external programs that this module -# relies on. lxbuildenv reads this variable in order to ensure -# the build will finish without exiting due to missing third-party -# programs. -LX_DEPENDENCIES = ["riscv", "icestorm", "yosys"] - -# Import lxbuildenv to integrate the deps/ directory -import lxbuildenv - -# Disable pylint's E1101, which breaks completely on migen -#pylint:disable=E1101 - -#from migen import * -from migen import Module, Signal, Instance, ClockDomain, If -from migen.genlib.resetsync import AsyncResetSynchronizer -from litex.build.lattice.platform import LatticePlatform -from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal -from litex.soc.integration import SoCCore -from litex.soc.integration.builder import Builder -from litex.soc.integration.soc_core import csr_map_update -from litex.soc.interconnect import wishbone - -from valentyusb import usbcore -from valentyusb.usbcore import io as usbio -from valentyusb.usbcore.cpu import epmem, unififo, epfifo -from valentyusb.usbcore.endpoint import EndpointType - -from lxsocsupport import up5kspram, cas, spi_flash - -import argparse - -_io = [ - ("serial", 0, - Subsignal("rx", Pins("21")), - Subsignal("tx", Pins("13"), Misc("PULLUP")), - IOStandard("LVCMOS33") - ), - ("usb", 0, - Subsignal("d_p", Pins("34")), - Subsignal("d_n", Pins("37")), - Subsignal("pullup", Pins("35")), - IOStandard("LVCMOS33") - ), - ("spiflash", 0, - Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), - Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), - Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")), - Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")), - Subsignal("wp", Pins("18"), IOStandard("LVCMOS33")), - Subsignal("hold", Pins("19"), IOStandard("LVCMOS33")), - ), - ("spiflash4x", 0, - Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), - Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), - Subsignal("dq", Pins("14 17 19 18"), IOStandard("LVCMOS33")), - ), - ("clk48", 0, Pins("44"), IOStandard("LVCMOS33")) -] - -_connectors = [] - -class _CRG(Module): - def __init__(self, platform): - clk12 = Signal() - # "0b00" Sets 48MHz HFOSC output - # "0b01" Sets 24MHz HFOSC output. - # "0b10" Sets 12MHz HFOSC output. - # "0b11" Sets 6MHz HFOSC output - self.specials += Instance( - "SB_HFOSC", - i_CLKHFEN=1, - i_CLKHFPU=1, - o_CLKHF=clk12, - p_CLKHF_DIV="0b10", # 12MHz - ) - - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_usb_12 = ClockDomain() - self.reset = Signal() - - # FIXME: Use PLL, increase system clock to 32 MHz, pending nextpnr - # fixes. - self.comb += self.cd_sys.clk.eq(clk12) - self.comb += self.cd_usb_12.clk.eq(clk12) - - # POR reset logic- POR generated from sys clk, POR logic feeds sys clk - # reset. - self.clock_domains.cd_por = ClockDomain() - reset_delay = Signal(12, reset=4095) - self.comb += [ - self.cd_por.clk.eq(self.cd_sys.clk), - self.cd_sys.rst.eq(reset_delay != 0), - self.cd_usb_12.rst.eq(reset_delay != 0) - ] - self.sync.por += \ - If(reset_delay != 0, - reset_delay.eq(reset_delay - 1) - ) - self.specials += AsyncResetSynchronizer(self.cd_por, self.reset) - - self.clock_domains.cd_usb_48 = ClockDomain() - platform.add_period_constraint(self.cd_usb_48.clk, 1e9/48e6) - self.comb += [ - self.cd_usb_48.clk.eq(platform.request("clk48")), - ] - -class RandomFirmwareROM(wishbone.SRAM): - """ - Seed the random data with a fixed number, so different bitstreams - can all share firmware. - """ - def __init__(self, size, seed=2373): - def xorshift32(x): - x = x ^ (x << 13) & 0xffffffff - x = x ^ (x >> 17) & 0xffffffff - x = x ^ (x << 5) & 0xffffffff - return x & 0xffffffff - - def get_rand(x): - out = 0 - for i in range(32): - x = xorshift32(x) - if (x & 1) == 1: - out = out | (1 << i) - return out & 0xffffffff - data = [] - seed = 1 - for d in range(int(size / 4)): - seed = get_rand(seed) - data.append(seed) - print("Firmware {} bytes of random data".format(size)) - wishbone.SRAM.__init__(self, size, read_only=True, init=data) - -class Platform(LatticePlatform): - default_clk_name = "clk48" - default_clk_period = 20.833 - - gateware_size = 0x20000 - - def __init__(self, toolchain="icestorm"): - LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, toolchain="icestorm") - def create_programmer(self): - raise ValueError("programming is not supported") - - # def do_finalize(self, fragment): - # LatticePlatform.do_finalize(self, fragment) - -class BaseSoC(SoCCore): - csr_peripherals = [ - "cpu_or_bridge", - "usb", - "usb_obuf", - "usb_ibuf", - ] - csr_map_update(SoCCore.csr_map, csr_peripherals) - - mem_map = { - "spiflash": 0x20000000, # (default shadow @0xa0000000) - } - mem_map.update(SoCCore.mem_map) - - interrupt_map = { - "usb": 3, - } - interrupt_map.update(SoCCore.interrupt_map) - - def __init__(self, platform, boot_source="random_rom", **kwargs): - # Disable integrated RAM as we'll add it later - self.integrated_sram_size = 0 - - clk_freq = int(12e6) - self.submodules.crg = _CRG(platform) - platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq) - platform.add_period_constraint(self.crg.cd_usb_12.clk, 1e9/clk_freq) - - SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, **kwargs) - - # SPRAM- UP5K has single port RAM, might as well use it as SRAM to - # free up scarce block RAM. - spram_size = 128*1024 - self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size) - self.register_mem("sram", 0x10000000, self.spram.bus, spram_size) - - if boot_source == "random_rom": - kwargs['cpu_reset_address']=0 - bios_size = 0x2000 - self.submodules.random_rom = RandomFirmwareROM(bios_size) - self.add_constant("ROM_DISABLE", 1) - self.register_rom(self.random_rom.bus, bios_size) - elif boot_source == "bios_rom": - kwargs['cpu_reset_address']=0 - bios_size = 0x2000 - self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) - elif boot_source == "spi_rom": - bios_size = 0x8000 - kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size - self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) - self.add_constant("ROM_DISABLE", 1) - self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size - self.add_memory_region("user_flash", - self.flash_boot_address, - # Leave a grace area- possible one-by-off bug in add_memory_region? - # Possible fix: addr < origin + length - 1 - platform.spiflash_total_size - (self.flash_boot_address - self.mem_map["spiflash"]) - 0x100) - else: - raise ValueError("unrecognized boot_source: {}".format(boot_source)) - - # Add USB pads - usb_pads = platform.request("usb") - usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup) - self.submodules.usb = epfifo.PerEndpointFifoInterface(usb_iobuf, endpoints=[EndpointType.BIDIR]) - # self.submodules.usb = epmem.MemInterface(usb_iobuf) - # self.submodules.usb = unififo.UsbUniFifo(usb_iobuf) - - # Disable final deep-sleep power down so firmware words are loaded - # onto softcore's address bus. - platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin" - platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin" - -def main(): - platform = Platform() - - parser = argparse.ArgumentParser( - description="Build Fomu Main Gateware", - add_help=False) - parser.add_argument( - "--bios", help="use bios as boot source", action="store_true" - ) - parser.add_argument( - "--rand", help="use random data as boot source", action="store_false" - ) - parser.add_argument( - "--spi", help="boot from spi", action="store_true" - ) - (args, rest) = parser.parse_known_args() - - if args.rand: - boot_source="random_rom" - compile_software=False - elif args.bios: - boot_source="bios_rom" - compile_software=True - elif args.spi: - boot_source = "spi_rom" - compile_software = False - - soc = BaseSoC(platform, cpu_type="vexriscv", cpu_variant="min", boot_source=boot_source) - builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv", compile_software=compile_software) - vns = builder.build() - soc.do_exit(vns) - -if __name__ == "__main__": - main() +#!/usr/bin/env python3 +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["riscv", "icestorm", "yosys"] + +# Import lxbuildenv to integrate the deps/ directory +import lxbuildenv + +# Disable pylint's E1101, which breaks completely on migen +#pylint:disable=E1101 + +#from migen import * +from migen import Module, Signal, Instance, ClockDomain, If +from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.build.lattice.platform import LatticePlatform +from litex.build.generic_platform import Pins, IOStandard, Misc, Subsignal +from litex.soc.integration import SoCCore +from litex.soc.integration.builder import Builder +from litex.soc.integration.soc_core import csr_map_update +from litex.soc.interconnect import wishbone + +from valentyusb import usbcore +from valentyusb.usbcore import io as usbio +from valentyusb.usbcore.cpu import epmem, unififo, epfifo +from valentyusb.usbcore.endpoint import EndpointType + +from lxsocsupport import up5kspram, cas, spi_flash + +import argparse + +_io = [ + ("serial", 0, + Subsignal("rx", Pins("21")), + Subsignal("tx", Pins("13"), Misc("PULLUP")), + IOStandard("LVCMOS33") + ), + ("usb", 0, + Subsignal("d_p", Pins("34")), + Subsignal("d_n", Pins("37")), + Subsignal("pullup", Pins("35")), + IOStandard("LVCMOS33") + ), + ("spiflash", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")), + Subsignal("wp", Pins("18"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("19"), IOStandard("LVCMOS33")), + ), + ("spiflash4x", 0, + Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")), + Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")), + Subsignal("dq", Pins("14 17 19 18"), IOStandard("LVCMOS33")), + ), + ("clk48", 0, Pins("44"), IOStandard("LVCMOS33")) +] + +_connectors = [] + +class _CRG(Module): + def __init__(self, platform): + clk12 = Signal() + # "0b00" Sets 48MHz HFOSC output + # "0b01" Sets 24MHz HFOSC output. + # "0b10" Sets 12MHz HFOSC output. + # "0b11" Sets 6MHz HFOSC output + self.specials += Instance( + "SB_HFOSC", + i_CLKHFEN=1, + i_CLKHFPU=1, + o_CLKHF=clk12, + p_CLKHF_DIV="0b10", # 12MHz + ) + + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_usb_12 = ClockDomain() + self.reset = Signal() + + # FIXME: Use PLL, increase system clock to 32 MHz, pending nextpnr + # fixes. + self.comb += self.cd_sys.clk.eq(clk12) + self.comb += self.cd_usb_12.clk.eq(clk12) + + # POR reset logic- POR generated from sys clk, POR logic feeds sys clk + # reset. + self.clock_domains.cd_por = ClockDomain() + reset_delay = Signal(12, reset=4095) + self.comb += [ + self.cd_por.clk.eq(self.cd_sys.clk), + self.cd_sys.rst.eq(reset_delay != 0), + self.cd_usb_12.rst.eq(reset_delay != 0) + ] + self.sync.por += \ + If(reset_delay != 0, + reset_delay.eq(reset_delay - 1) + ) + self.specials += AsyncResetSynchronizer(self.cd_por, self.reset) + + self.clock_domains.cd_usb_48 = ClockDomain() + platform.add_period_constraint(self.cd_usb_48.clk, 1e9/48e6) + self.comb += [ + self.cd_usb_48.clk.eq(platform.request("clk48")), + ] + +class RandomFirmwareROM(wishbone.SRAM): + """ + Seed the random data with a fixed number, so different bitstreams + can all share firmware. + """ + def __init__(self, size, seed=2373): + def xorshift32(x): + x = x ^ (x << 13) & 0xffffffff + x = x ^ (x >> 17) & 0xffffffff + x = x ^ (x << 5) & 0xffffffff + return x & 0xffffffff + + def get_rand(x): + out = 0 + for i in range(32): + x = xorshift32(x) + if (x & 1) == 1: + out = out | (1 << i) + return out & 0xffffffff + data = [] + seed = 1 + for d in range(int(size / 4)): + seed = get_rand(seed) + data.append(seed) + print("Firmware {} bytes of random data".format(size)) + wishbone.SRAM.__init__(self, size, read_only=True, init=data) + +class Platform(LatticePlatform): + default_clk_name = "clk48" + default_clk_period = 20.833 + + gateware_size = 0x20000 + + def __init__(self, toolchain="icestorm"): + LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors, toolchain="icestorm") + def create_programmer(self): + raise ValueError("programming is not supported") + + # def do_finalize(self, fragment): + # LatticePlatform.do_finalize(self, fragment) + +class BaseSoC(SoCCore): + csr_peripherals = [ + "cpu_or_bridge", + "usb", + "usb_obuf", + "usb_ibuf", + ] + csr_map_update(SoCCore.csr_map, csr_peripherals) + + mem_map = { + "spiflash": 0x20000000, # (default shadow @0xa0000000) + } + mem_map.update(SoCCore.mem_map) + + interrupt_map = { + "usb": 3, + } + interrupt_map.update(SoCCore.interrupt_map) + + def __init__(self, platform, boot_source="random_rom", **kwargs): + # Disable integrated RAM as we'll add it later + self.integrated_sram_size = 0 + + clk_freq = int(12e6) + self.submodules.crg = _CRG(platform) + platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq) + platform.add_period_constraint(self.crg.cd_usb_12.clk, 1e9/clk_freq) + + SoCCore.__init__(self, platform, clk_freq, integrated_sram_size=0, **kwargs) + + # SPRAM- UP5K has single port RAM, might as well use it as SRAM to + # free up scarce block RAM. + spram_size = 128*1024 + self.submodules.spram = up5kspram.Up5kSPRAM(size=spram_size) + self.register_mem("sram", 0x10000000, self.spram.bus, spram_size) + + if boot_source == "random_rom": + kwargs['cpu_reset_address']=0 + bios_size = 0x2000 + self.submodules.random_rom = RandomFirmwareROM(bios_size) + self.add_constant("ROM_DISABLE", 1) + self.register_rom(self.random_rom.bus, bios_size) + elif boot_source == "bios_rom": + kwargs['cpu_reset_address']=0 + bios_size = 0x2000 + self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) + elif boot_source == "spi_rom": + bios_size = 0x8000 + kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size + self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size) + self.add_constant("ROM_DISABLE", 1) + self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size + self.add_memory_region("user_flash", + self.flash_boot_address, + # Leave a grace area- possible one-by-off bug in add_memory_region? + # Possible fix: addr < origin + length - 1 + platform.spiflash_total_size - (self.flash_boot_address - self.mem_map["spiflash"]) - 0x100) + else: + raise ValueError("unrecognized boot_source: {}".format(boot_source)) + + # Add USB pads + usb_pads = platform.request("usb") + usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup) + self.submodules.usb = epfifo.PerEndpointFifoInterface(usb_iobuf, endpoints=[EndpointType.BIDIR]) + # self.submodules.usb = epmem.MemInterface(usb_iobuf) + # self.submodules.usb = unififo.UsbUniFifo(usb_iobuf) + + # Disable final deep-sleep power down so firmware words are loaded + # onto softcore's address bus. + platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin" + platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin" + +def main(): + platform = Platform() + + parser = argparse.ArgumentParser( + description="Build Fomu Main Gateware", + add_help=False) + parser.add_argument( + "--bios", help="use bios as boot source", action="store_true" + ) + parser.add_argument( + "--rand", help="use random data as boot source", action="store_false" + ) + parser.add_argument( + "--spi", help="boot from spi", action="store_true" + ) + (args, rest) = parser.parse_known_args() + + if args.rand: + boot_source="random_rom" + compile_software=False + elif args.bios: + boot_source="bios_rom" + compile_software=True + elif args.spi: + boot_source = "spi_rom" + compile_software = False + + soc = BaseSoC(platform, cpu_type="vexriscv", cpu_variant="min", boot_source=boot_source) + builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv", compile_software=compile_software) + vns = builder.build() + soc.do_exit(vns) + +if __name__ == "__main__": + main() From d42418d62ab390c24ada108b27fcddfbee6d0b5c Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:22:05 +0800 Subject: [PATCH 14/23] foboot-bitstream: mark executable Signed-off-by: Sean Cross --- foboot-bitstream.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 foboot-bitstream.py diff --git a/foboot-bitstream.py b/foboot-bitstream.py old mode 100644 new mode 100755 From 5fbd0fc667be43228b96d0d919c7d02162b446cb Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:25:16 +0800 Subject: [PATCH 15/23] lxbuildenv: riscv: also allow riscv32 toolchain Signed-off-by: Sean Cross --- lxbuildenv.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lxbuildenv.py b/lxbuildenv.py index d09da85..e571248 100644 --- a/lxbuildenv.py +++ b/lxbuildenv.py @@ -170,7 +170,15 @@ def check_make(args): return check_cmd(args, "make", "GNU Make") def check_riscv(args): - return check_cmd(args, "riscv64-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/products/tools/") + riscv64 = check_cmd(args, "riscv64-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/products/tools/") + if riscv64[0] == True: + return riscv64 + + riscv32 = check_cmd(args, "riscv32-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/products/tools/") + if riscv32[0] == True: + return riscv32 + + return riscv64 def check_yosys(args): return check_cmd(args, "yosys") From 6ca4b6a3984ee85159fe4ae9c9466b74a3f23621 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:32:28 +0800 Subject: [PATCH 16/23] deps: valentyusb: update submodule Signed-off-by: Sean Cross --- deps/valentyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/valentyusb b/deps/valentyusb index 8eadbae..14e116f 160000 --- a/deps/valentyusb +++ b/deps/valentyusb @@ -1 +1 @@ -Subproject commit 8eadbae40146cf0ac1abcaf511a5f96eb94d336d +Subproject commit 14e116ff82b825069a92292308f4f66ad6167dff From 05480670c56343503d141f8ea379a7731ed10884 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:32:48 +0800 Subject: [PATCH 17/23] migen: update submodule Signed-off-by: Sean Cross --- deps/migen | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/migen b/deps/migen index afe4405..867adbf 160000 --- a/deps/migen +++ b/deps/migen @@ -1 +1 @@ -Subproject commit afe4405becdbc76539f0195c319367187012b05e +Subproject commit 867adbf5a2046a1b7936e0ad47ba90f5caee1f62 From dd7839cc68d9ea40ec9a73ca432b598c953bf3c7 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 25 Feb 2019 16:36:21 +0800 Subject: [PATCH 18/23] deps: migen: fix upstream ref Signed-off-by: Sean Cross --- deps/migen | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/migen b/deps/migen index 867adbf..ae42105 160000 --- a/deps/migen +++ b/deps/migen @@ -1 +1 @@ -Subproject commit 867adbf5a2046a1b7936e0ad47ba90f5caee1f62 +Subproject commit ae421054f1e3621621bcc397df171caf3681763c From cad2ae01d73caf43fc8da2be1c47ffbd0e87c392 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 27 Feb 2019 14:20:04 +0800 Subject: [PATCH 19/23] foboot-bitstream: use crystal for 12 MHz clock This fixes heterodyning that was occurring in the USB block, as it transitioned from the 48 MHz down to the 12 MHz domain. Signed-off-by: Sean Cross --- foboot-bitstream.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/foboot-bitstream.py b/foboot-bitstream.py index ed64e34..af14156 100755 --- a/foboot-bitstream.py +++ b/foboot-bitstream.py @@ -63,17 +63,17 @@ _connectors = [] class _CRG(Module): def __init__(self, platform): clk12 = Signal() - # "0b00" Sets 48MHz HFOSC output - # "0b01" Sets 24MHz HFOSC output. - # "0b10" Sets 12MHz HFOSC output. - # "0b11" Sets 6MHz HFOSC output - self.specials += Instance( - "SB_HFOSC", - i_CLKHFEN=1, - i_CLKHFPU=1, - o_CLKHF=clk12, - p_CLKHF_DIV="0b10", # 12MHz - ) + # # "0b00" Sets 48MHz HFOSC output + # # "0b01" Sets 24MHz HFOSC output. + # # "0b10" Sets 12MHz HFOSC output. + # # "0b11" Sets 6MHz HFOSC output + # self.specials += Instance( + # "SB_HFOSC", + # i_CLKHFEN=1, + # i_CLKHFPU=1, + # o_CLKHF=clk12, + # p_CLKHF_DIV="0b10", # 12MHz + # ) self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_usb_12 = ClockDomain() @@ -93,6 +93,18 @@ class _CRG(Module): self.cd_sys.rst.eq(reset_delay != 0), self.cd_usb_12.rst.eq(reset_delay != 0) ] + + # Divide clk48 down to clk12, to ensure they're synchronized. + clk12_counter = Signal(2) + self.sync.usb_48 += [ + clk12_counter.eq(clk12_counter + 1), + ] + self.specials += Instance( + "SB_GB", + i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_counter[1], + o_GLOBAL_BUFFER_OUTPUT=clk12, + ) + self.sync.por += \ If(reset_delay != 0, reset_delay.eq(reset_delay - 1) From 1cb67f8f8d7d8e5f2e38cedbae4e7f62e9043e0c Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 28 Feb 2019 10:45:37 +0800 Subject: [PATCH 20/23] crc5-test: add simple program to generate SOF frames This can be used to tell if we're properly decoding packets. Signed-off-by: Sean Cross --- crc5-test.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 crc5-test.c diff --git a/crc5-test.c b/crc5-test.c new file mode 100644 index 0000000..9d57cfb --- /dev/null +++ b/crc5-test.c @@ -0,0 +1,160 @@ +#include +#include + +const uint8_t crc5Table4[] = + { + 0x00, 0x0E, 0x1C, 0x12, 0x11, 0x1F, 0x0D, 0x03, + 0x0B, 0x05, 0x17, 0x19, 0x1A, 0x14, 0x06, 0x08}; +const uint8_t crc5Table0[] = + { + 0x00, 0x16, 0x05, 0x13, 0x0A, 0x1C, 0x0F, 0x19, + 0x14, 0x02, 0x11, 0x07, 0x1E, 0x08, 0x1B, 0x0D}; +//--------------- +int crc5Check(const uint8_t *data) +//--------------- +{ + uint8_t b = data[0] ^ 0x1F; + uint8_t crc = crc5Table4[b & 0x0F] ^ crc5Table0[(b >> 4) & 0x0F]; + b = data[1] ^ crc; + return (crc5Table4[b & 0x0F] ^ crc5Table0[(b >> 4) & 0x0F]) == 0x06; +} +// crc5Check + +int do_check(uint16_t pkt) { + uint8_t data[2] = { + pkt >> 8, + pkt, + }; + return crc5Check(data); +} + +#define INT_SIZE 32 +unsigned CRC5(unsigned dwInput, int iBitcnt) +{ + const uint32_t poly5 = (0x05 << (INT_SIZE-5)); + uint32_t crc5 = (0x1f << (INT_SIZE-5)); + uint32_t udata = (dwInput << (INT_SIZE-iBitcnt)); + + if ( (iBitcnt<1) || (iBitcnt>INT_SIZE) ) // Validate iBitcnt + return 0xffffffff; + + while (iBitcnt--) + { + if ( (udata ^ crc5) & (0x1<<(INT_SIZE-1)) ) // bit4 != bit4? + { + crc5 <<= 1; + crc5 ^= poly5; + } + else + crc5 <<= 1; + + udata <<= 1; + } + + // Shift back into position + crc5 >>= (INT_SIZE-5); + + // Invert contents to generate crc field + crc5 ^= 0x1f; + + return crc5; +} //CRC5() + +static uint32_t reverse_sof(uint32_t data) { + int i; + uint32_t data_flipped = 0; + for (i = 0; i < 11; i++) + if (data & (1 << i)) + data_flipped |= 1 << (10 - i); + + return data_flipped; +} + +static uint8_t reverse_byte(uint8_t data) { + int i; + uint8_t data_flipped = 0; + for (i = 0; i < 8; i++) + if (data & (1 << i)) + data_flipped |= 1 << (7 - i); + + return data_flipped; +} + +static uint8_t reverse_crc5(uint8_t data) { + int i; + uint8_t data_flipped = 0; + for (i = 0; i < 5; i++) + if (data & (1 << i)) + data_flipped |= 1 << (4 - i); + + return data_flipped; +} + +static uint16_t make_token(uint16_t data) { + uint16_t val = 0; + + data = reverse_sof(data); + val = data << 5; + val |= CRC5(data, 11); + + return (reverse_byte(val >> 8) << 8) | reverse_byte(val); +} + +int do_crc5(uint16_t pkt) { + uint8_t pkt_flipped[2] = { + reverse_byte(pkt >> 8), + reverse_byte(pkt), + }; + uint32_t data = (pkt_flipped[1] >> 5) | (pkt_flipped[0] << 3); + uint32_t data_flipped; + uint8_t crc; + uint8_t found_crc = (pkt >> 3) & 0x1f; + + data_flipped = reverse_sof(data); + + crc = CRC5(data, 11); + crc = reverse_crc5(crc); + + uint16_t reconstructed = make_token(data_flipped); + uint16_t wire = (reverse_byte(pkt >> 8) << 8) | reverse_byte(pkt); + + printf("Packet: 0x%04x FCRC: %02x Data: 0x%04x " + "Flipped: 0x%04x CRC5: 0x%02x Pass? %d Reconstructed: 0x%04x Wire: %04x\n", + pkt, found_crc, data, data_flipped, crc, do_check(pkt), + reconstructed, + wire + ); + + return crc; +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) +int main(int argc, char **argv) +{ + uint32_t check_bytes[] = { + /* + 0xff3c, + 0x12c5, + 0xe17e, + 0x19f5, + 0x0225, + 0x0165, + 0x009d, + 0x102f, + make_token(1013), + make_token(1429), + make_token(100), + */ + 0x82bc, + make_token(0x0483),//0x5fde, + 0x843c, + + }; + + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(check_bytes); i++) + do_crc5(check_bytes[i]); + + return 0; +} From 6a147c43337278eba9e9c75820c26d9bcb7c5431 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 28 Feb 2019 10:51:35 +0800 Subject: [PATCH 21/23] valentyusb: pull latest version Signed-off-by: Sean Cross --- deps/valentyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/valentyusb b/deps/valentyusb index 14e116f..98edf5f 160000 --- a/deps/valentyusb +++ b/deps/valentyusb @@ -1 +1 @@ -Subproject commit 14e116ff82b825069a92292308f4f66ad6167dff +Subproject commit 98edf5f02562e16b8528e3e97e36a8bdf0eee78e From a897c7f2fa5c4d2d5edf6460bf48a9f2b01af1f0 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 28 Feb 2019 10:52:06 +0800 Subject: [PATCH 22/23] foboot-bitstream: remove `cas` module from imports It's unused in the current implementation. Signed-off-by: Sean Cross --- foboot-bitstream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/foboot-bitstream.py b/foboot-bitstream.py index af14156..e7aa9f4 100755 --- a/foboot-bitstream.py +++ b/foboot-bitstream.py @@ -26,7 +26,7 @@ from valentyusb.usbcore import io as usbio from valentyusb.usbcore.cpu import epmem, unififo, epfifo from valentyusb.usbcore.endpoint import EndpointType -from lxsocsupport import up5kspram, cas, spi_flash +from lxsocsupport import up5kspram, spi_flash import argparse From d812378c4d61f7c957ac4bcba15a8344fb7fb458 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 5 Mar 2019 08:56:30 +0800 Subject: [PATCH 23/23] deps: update valentyusb Signed-off-by: Sean Cross --- deps/valentyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/valentyusb b/deps/valentyusb index 98edf5f..ac9a522 160000 --- a/deps/valentyusb +++ b/deps/valentyusb @@ -1 +1 @@ -Subproject commit 98edf5f02562e16b8528e3e97e36a8bdf0eee78e +Subproject commit ac9a522847a116c842c8f7f795e587ff3d0d0dbb