initial commit

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2019-06-19 09:51:22 -07:00
commit b1c2b36cb1
21 changed files with 4902 additions and 0 deletions

22
.gitattributes vendored Normal file
View file

@ -0,0 +1,22 @@
*.py text eol=lf
*.sh text eol=lf
LICENSE text eol=lf
README.* text eol=lf
*.interface text eol=lf
*.jig text eol=lf
*.logger text eol=lf
*.scenario text eol=lf
*.test text eol=lf
*.trigger text eol=lf
*.c text eol=lf
*.S text eol=lf
*.h text eol=lf
*.ld text eol=lf
hw/bin/* text eol=lf
Makefile text eol=lf
*.service text eol=lf
*.png binary
*.jpg binary
*.bin binary
*.elf binary
*.bin binary

12
.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
.obj/
*.swp
*.swo
*~
*.bin
*.dfu
*.ihex
*.elf
.vscode/
build/
__pycache__/
.env

24
.gitmodules vendored Normal file
View file

@ -0,0 +1,24 @@
[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/litex_boards"]
path = deps/litex_boards
url = https://github.com/litex-hub/litex-boards.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/lxsocsupport"]
path = deps/lxsocsupport
url = https://github.com/xobs/lxsocsupport.git
[submodule "deps/valentyusb"]
path = deps/valentyusb
url = https://github.com/im-tomu/valentyusb.git
[submodule "deps/litedram"]
path = deps/litedram
url = https://github.com/enjoy-digital/litedram.git

14
bin/litex_read_verilog Executable file
View file

@ -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.tools.litex_read_verilog import main
main()

14
bin/litex_server Executable file
View file

@ -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.tools.litex_server import main
main()

14
bin/litex_sim Executable file
View file

@ -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.tools.litex_sim import main
main()

14
bin/litex_simple Executable file
View file

@ -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()

14
bin/litex_term Executable file
View file

@ -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.tools.litex_term import main
main()

14
bin/mkmscimg Executable file
View file

@ -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.software.mkmscimg import main
main()

1
deps/litedram vendored Submodule

@ -0,0 +1 @@
Subproject commit 690e4f848ffccebb437a19b498a2adb840ce1e08

1
deps/litescope vendored Submodule

@ -0,0 +1 @@
Subproject commit 2474ce9db23e4d06bff4bbeacf0051efa3042f37

1
deps/litex vendored Submodule

@ -0,0 +1 @@
Subproject commit 408d3f1f7c5a4657dd9e964da4ed76f35cfd9e8f

1
deps/litex_boards vendored Submodule

@ -0,0 +1 @@
Subproject commit 482a00aa768159fe23622a08e67a503f39007967

1
deps/lxsocsupport vendored Submodule

@ -0,0 +1 @@
Subproject commit 74f133340144630e000f91e466ac5107f87a8d5a

1
deps/migen vendored Submodule

@ -0,0 +1 @@
Subproject commit 562c0466443f859d6cf0c87a0bb50db094d27cf4

1
deps/pyserial vendored Submodule

@ -0,0 +1 @@
Subproject commit acab9d2c0efb63323faebfd5e3405d77cd4b5617

1
deps/valentyusb vendored Submodule

@ -0,0 +1 @@
Subproject commit 3052a16d9f18360f407ce7a4d0cbd82e24cb4768

554
lxbuildenv.py Normal file
View file

@ -0,0 +1,554 @@
#!/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',
'litedram': 'https://github.com/enjoy-digital/litedram.git',
'litex_boards': 'https://github.com/litex-hub/litex-boards.git',
'litescope': 'https://github.com/enjoy-digital/litescope.git',
'pyserial': 'https://github.com/pyserial/pyserial.git',
}
OPTIONAL_DEPS = {
'liteeth': 'https://github.com/enjoy-digital/liteeth.git',
'liteusb': 'https://github.com/enjoy-digital/liteusb.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',
'usb': 'https://github.com/pyusb/pyusb.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):
riscv64 = check_cmd(args, "riscv64-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/boards/")
if riscv64[0] == True:
return riscv64
riscv32 = check_cmd(args, "riscv32-unknown-elf-gcc", "riscv toolchain", "download it from https://www.sifive.com/boards/")
if riscv32[0] == True:
return riscv32
return riscv64
def check_yosys(args):
return check_cmd(args, "yosys")
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,
'make': check_make,
'riscv': check_riscv,
'yosys': check_yosys,
'arachne-pnr': check_arachne,
'icestorm': check_icestorm,
}
# 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, breadcrumbs=[]):
if verbose:
print('git-dep: checking if "{}" requires updating (depth: {})...'.format(root_path, depth))
# If the directory isn't a valid git repo, initialization is required
git_dir_cmd = subprocess.Popen(["git", "rev-parse", "--show-toplevel"],
cwd=root_path,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(git_stdout, _) = git_dir_cmd.communicate()
if git_dir_cmd.wait() != 0:
if verbose:
print('git-dep: missing git directory, starting update...')
return True
git_dir = git_stdout.decode().strip()
if git_dir in breadcrumbs:
if verbose:
print('git-dep: root path {} is not in git path'.format(root_path))
return True
breadcrumbs.append(git_dir)
if not os.path.exists(git_dir + os.path.sep + '.git'):
if verbose:
print('git-dep: .git not found in "{}"'.format(git_dir))
return True
# If there are no submodules, no initialization needs to be done
if not os.path.isfile(git_dir + os.path.sep + '.gitmodules'):
if verbose:
print('git-dep: .gitmodules not found in "{}", so not updating'.format(git_dir))
return False
# Loop through the gitmodules to check all submodules
gitmodules = open(git_dir + 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(git_dir + os.path.sep + path, depth + 1, verbose=verbose, breadcrumbs=breadcrumbs):
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.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'
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.software.mkmscimg',
'litex_term': 'litex.tools.litex_term',
'litex_server': 'litex.tools.litex_server',
'litex_sim': 'litex.tools.litex_sim',
'litex_read_verilog': 'litex.tools.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', newline='\n') 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.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)
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"
)
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):
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)

3289
rtl/2-stage-1024-cache.v Normal file

File diff suppressed because it is too large Load diff

579
rtl/spimemio.v Normal file
View file

@ -0,0 +1,579 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module spimemio (
input clk, resetn,
input valid,
output ready,
input [23:0] addr,
output reg [31:0] rdata,
output flash_csb,
output flash_clk,
output flash_io0_oe,
output flash_io1_oe,
output flash_io2_oe,
output flash_io3_oe,
output flash_io0_do,
output flash_io1_do,
output flash_io2_do,
output flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di,
input [3:0] cfgreg_we,
input [31:0] cfgreg_di,
output [31:0] cfgreg_do
);
reg xfer_resetn;
reg din_valid;
wire din_ready;
reg [7:0] din_data;
reg [3:0] din_tag;
reg din_cont;
reg din_qspi;
reg din_ddr;
reg din_rd;
wire dout_valid;
wire [7:0] dout_data;
wire [3:0] dout_tag;
reg [23:0] buffer;
reg [23:0] rd_addr;
reg rd_valid;
reg rd_wait;
reg rd_inc;
assign ready = valid && (addr == rd_addr) && rd_valid;
wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
reg softreset;
reg config_en; // cfgreg[31]
reg config_ddr; // cfgreg[22]
reg config_qspi; // cfgreg[21]
reg config_cont; // cfgreg[20]
reg [3:0] config_dummy; // cfgreg[19:16]
reg [3:0] config_oe; // cfgreg[11:8]
reg config_csb; // cfgreg[5]
reg config_clk; // cfgref[4]
reg [3:0] config_do; // cfgreg[3:0]
assign cfgreg_do[31] = config_en;
assign cfgreg_do[30:23] = 0;
assign cfgreg_do[22] = config_ddr;
assign cfgreg_do[21] = config_qspi;
assign cfgreg_do[20] = config_cont;
assign cfgreg_do[19:16] = config_dummy;
assign cfgreg_do[15:12] = 0;
assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe};
assign cfgreg_do[7:6] = 0;
assign cfgreg_do[5] = flash_csb;
assign cfgreg_do[4] = flash_clk;
assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
always @(posedge clk) begin
softreset <= !config_en || cfgreg_we;
if (!resetn) begin
softreset <= 1;
config_en <= 1;
config_csb <= 0;
config_clk <= 0;
config_oe <= 0;
config_do <= 0;
config_ddr <= 0;
config_qspi <= 0;
config_cont <= 0;
config_dummy <= 8;
end else begin
if (cfgreg_we[0]) begin
config_csb <= cfgreg_di[5];
config_clk <= cfgreg_di[4];
config_do <= cfgreg_di[3:0];
end
if (cfgreg_we[1]) begin
config_oe <= cfgreg_di[11:8];
end
if (cfgreg_we[2]) begin
config_ddr <= cfgreg_di[22];
config_qspi <= cfgreg_di[21];
config_cont <= cfgreg_di[20];
config_dummy <= cfgreg_di[19:16];
end
if (cfgreg_we[3]) begin
config_en <= cfgreg_di[31];
end
end
end
wire xfer_csb;
wire xfer_clk;
wire xfer_io0_oe;
wire xfer_io1_oe;
wire xfer_io2_oe;
wire xfer_io3_oe;
wire xfer_io0_do;
wire xfer_io1_do;
wire xfer_io2_do;
wire xfer_io3_do;
reg xfer_io0_90;
reg xfer_io1_90;
reg xfer_io2_90;
reg xfer_io3_90;
always @(negedge clk) begin
xfer_io0_90 <= xfer_io0_do;
xfer_io1_90 <= xfer_io1_do;
xfer_io2_90 <= xfer_io2_do;
xfer_io3_90 <= xfer_io3_do;
end
assign flash_csb = config_en ? xfer_csb : config_csb;
assign flash_clk = config_en ? xfer_clk : config_clk;
assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0];
assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1];
assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2];
assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3];
assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0];
assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1];
assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2];
assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3];
wire xfer_dspi = din_ddr && !din_qspi;
wire xfer_ddr = din_ddr && din_qspi;
spimemio_xfer xfer (
.clk (clk ),
.resetn (xfer_resetn ),
.din_valid (din_valid ),
.din_ready (din_ready ),
.din_data (din_data ),
.din_tag (din_tag ),
.din_cont (din_cont ),
.din_dspi (xfer_dspi ),
.din_qspi (din_qspi ),
.din_ddr (xfer_ddr ),
.din_rd (din_rd ),
.dout_valid (dout_valid ),
.dout_data (dout_data ),
.dout_tag (dout_tag ),
.flash_csb (xfer_csb ),
.flash_clk (xfer_clk ),
.flash_io0_oe (xfer_io0_oe ),
.flash_io1_oe (xfer_io1_oe ),
.flash_io2_oe (xfer_io2_oe ),
.flash_io3_oe (xfer_io3_oe ),
.flash_io0_do (xfer_io0_do ),
.flash_io1_do (xfer_io1_do ),
.flash_io2_do (xfer_io2_do ),
.flash_io3_do (xfer_io3_do ),
.flash_io0_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di)
);
reg [3:0] state;
always @(posedge clk) begin
xfer_resetn <= 1;
din_valid <= 0;
if (!resetn || softreset) begin
state <= 0;
xfer_resetn <= 0;
rd_valid <= 0;
din_tag <= 0;
din_cont <= 0;
din_qspi <= 0;
din_ddr <= 0;
din_rd <= 0;
end else begin
if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data;
if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data;
if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data;
if (dout_valid && dout_tag == 4) begin
rdata <= {dout_data, buffer};
rd_addr <= rd_inc ? rd_addr + 4 : addr;
rd_valid <= 1;
rd_wait <= rd_inc;
rd_inc <= 1;
end
if (valid)
rd_wait <= 0;
case (state)
0: begin
din_valid <= 1;
din_data <= 8'h ff;
din_tag <= 0;
if (din_ready) begin
din_valid <= 0;
state <= 1;
end
end
1: begin
if (dout_valid) begin
xfer_resetn <= 0;
state <= 2;
end
end
2: begin
din_valid <= 1;
din_data <= 8'h ab;
din_tag <= 0;
if (din_ready) begin
din_valid <= 0;
state <= 3;
end
end
3: begin
if (dout_valid) begin
xfer_resetn <= 0;
state <= 4;
end
end
4: begin
rd_inc <= 0;
din_valid <= 1;
din_tag <= 0;
case ({config_ddr, config_qspi})
2'b11: din_data <= 8'h ED;
2'b01: din_data <= 8'h EB;
2'b10: din_data <= 8'h BB;
2'b00: din_data <= 8'h 03;
endcase
if (din_ready) begin
din_valid <= 0;
state <= 5;
end
end
5: begin
if (valid && !ready) begin
din_valid <= 1;
din_tag <= 0;
din_data <= addr[23:16];
din_qspi <= config_qspi;
din_ddr <= config_ddr;
if (din_ready) begin
din_valid <= 0;
state <= 6;
end
end
end
6: begin
din_valid <= 1;
din_tag <= 0;
din_data <= addr[15:8];
if (din_ready) begin
din_valid <= 0;
state <= 7;
end
end
7: begin
din_valid <= 1;
din_tag <= 0;
din_data <= addr[7:0];
if (din_ready) begin
din_valid <= 0;
din_data <= 0;
state <= config_qspi || config_ddr ? 8 : 9;
end
end
8: begin
din_valid <= 1;
din_tag <= 0;
din_data <= config_cont ? 8'h A5 : 8'h FF;
if (din_ready) begin
din_rd <= 1;
din_data <= config_dummy;
din_valid <= 0;
state <= 9;
end
end
9: begin
din_valid <= 1;
din_tag <= 1;
if (din_ready) begin
din_valid <= 0;
state <= 10;
end
end
10: begin
din_valid <= 1;
din_data <= 8'h 00;
din_tag <= 2;
if (din_ready) begin
din_valid <= 0;
state <= 11;
end
end
11: begin
din_valid <= 1;
din_tag <= 3;
if (din_ready) begin
din_valid <= 0;
state <= 12;
end
end
12: begin
if (!rd_wait || valid) begin
din_valid <= 1;
din_tag <= 4;
if (din_ready) begin
din_valid <= 0;
state <= 9;
end
end
end
endcase
if (jump) begin
rd_inc <= 0;
rd_valid <= 0;
xfer_resetn <= 0;
if (config_cont) begin
state <= 5;
end else begin
state <= 4;
din_qspi <= 0;
din_ddr <= 0;
end
din_rd <= 0;
end
end
end
endmodule
module spimemio_xfer (
input clk, resetn,
input din_valid,
output din_ready,
input [7:0] din_data,
input [3:0] din_tag,
input din_cont,
input din_dspi,
input din_qspi,
input din_ddr,
input din_rd,
output dout_valid,
output [7:0] dout_data,
output [3:0] dout_tag,
output reg flash_csb,
output reg flash_clk,
output reg flash_io0_oe,
output reg flash_io1_oe,
output reg flash_io2_oe,
output reg flash_io3_oe,
output reg flash_io0_do,
output reg flash_io1_do,
output reg flash_io2_do,
output reg flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di
);
reg [7:0] obuffer;
reg [7:0] ibuffer;
reg [3:0] count;
reg [3:0] dummy_count;
reg xfer_cont;
reg xfer_dspi;
reg xfer_qspi;
reg xfer_ddr;
reg xfer_ddr_q;
reg xfer_rd;
reg [3:0] xfer_tag;
reg [3:0] xfer_tag_q;
reg [7:0] next_obuffer;
reg [7:0] next_ibuffer;
reg [3:0] next_count;
reg fetch;
reg next_fetch;
reg last_fetch;
always @(posedge clk) begin
xfer_ddr_q <= xfer_ddr;
xfer_tag_q <= xfer_tag;
end
assign din_ready = din_valid && resetn && next_fetch;
assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn;
assign dout_data = ibuffer;
assign dout_tag = xfer_tag_q;
always @* begin
flash_io0_oe = 0;
flash_io1_oe = 0;
flash_io2_oe = 0;
flash_io3_oe = 0;
flash_io0_do = 0;
flash_io1_do = 0;
flash_io2_do = 0;
flash_io3_do = 0;
next_obuffer = obuffer;
next_ibuffer = ibuffer;
next_count = count;
next_fetch = 0;
if (dummy_count == 0) begin
casez ({xfer_ddr, xfer_qspi, xfer_dspi})
3'b 000: begin
flash_io0_oe = 1;
flash_io0_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[6:0], 1'b 0};
next_count = count - |count;
end else begin
next_ibuffer = {ibuffer[6:0], flash_io1_di};
end
next_fetch = (next_count == 0);
end
3'b 01?: begin
flash_io0_oe = !xfer_rd;
flash_io1_oe = !xfer_rd;
flash_io2_oe = !xfer_rd;
flash_io3_oe = !xfer_rd;
flash_io0_do = obuffer[4];
flash_io1_do = obuffer[5];
flash_io2_do = obuffer[6];
flash_io3_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[3:0], 4'b 0000};
next_count = count - {|count, 2'b00};
end else begin
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
end
next_fetch = (next_count == 0);
end
3'b 11?: begin
flash_io0_oe = !xfer_rd;
flash_io1_oe = !xfer_rd;
flash_io2_oe = !xfer_rd;
flash_io3_oe = !xfer_rd;
flash_io0_do = obuffer[4];
flash_io1_do = obuffer[5];
flash_io2_do = obuffer[6];
flash_io3_do = obuffer[7];
next_obuffer = {obuffer[3:0], 4'b 0000};
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
next_count = count - {|count, 2'b00};
next_fetch = (next_count == 0);
end
3'b ??1: begin
flash_io0_oe = !xfer_rd;
flash_io1_oe = !xfer_rd;
flash_io0_do = obuffer[6];
flash_io1_do = obuffer[7];
if (flash_clk) begin
next_obuffer = {obuffer[5:0], 2'b 00};
next_count = count - {|count, 1'b0};
end else begin
next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di};
end
next_fetch = (next_count == 0);
end
endcase
end
end
always @(posedge clk) begin
if (!resetn) begin
fetch <= 1;
last_fetch <= 1;
flash_csb <= 1;
flash_clk <= 0;
count <= 0;
dummy_count <= 0;
xfer_tag <= 0;
xfer_cont <= 0;
xfer_dspi <= 0;
xfer_qspi <= 0;
xfer_ddr <= 0;
xfer_rd <= 0;
end else begin
fetch <= next_fetch;
last_fetch <= xfer_ddr ? fetch : 1;
if (dummy_count) begin
flash_clk <= !flash_clk && !flash_csb;
dummy_count <= dummy_count - flash_clk;
end else
if (count) begin
flash_clk <= !flash_clk && !flash_csb;
obuffer <= next_obuffer;
ibuffer <= next_ibuffer;
count <= next_count;
end
if (din_valid && din_ready) begin
flash_csb <= 0;
flash_clk <= 0;
count <= 8;
dummy_count <= din_rd ? din_data : 0;
obuffer <= din_data;
xfer_tag <= din_tag;
xfer_cont <= din_cont;
xfer_dspi <= din_dspi;
xfer_qspi <= din_qspi;
xfer_ddr <= din_ddr;
xfer_rd <= din_rd;
end
end
end
endmodule

330
workshop.py Normal file
View file

@ -0,0 +1,330 @@
#!/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"]
# Import lxbuildenv to integrate the deps/ directory
import lxbuildenv
# "python.autoComplete.extraPaths": [
# "deps/litescope",
# "deps/litex",
# "deps/litex_boards",
# "deps/lxsocsupport",
# "deps/migen",
# "deps/valentyusb"
# ]
# Disable pylint's E1101, which breaks completely on migen
#pylint:disable=E1101
from migen import Module, Signal, Instance, ClockDomain, If
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.fhdl.specials import TSTriple
from migen.fhdl.bitcontainer import bits_for
from migen.fhdl.structure import ClockSignal, ResetSignal, Replicate, Cat
from litex_boards.partner.platforms.fomu_evt import Platform
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 AutoCSR, CSRStatus, CSRStorage
from lxsocsupport import up5kspram
class _CRG(Module):
def __init__(self, platform, use_pll):
clk48_raw = platform.request("clk48")
clk12_raw = Signal()
clk48 = Signal()
clk12 = Signal()
reset_delay = Signal(13, reset=4095)
self.clock_domains.cd_por = ClockDomain()
self.reset = Signal()
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_usb_12 = ClockDomain()
self.clock_domains.cd_usb_48 = ClockDomain()
platform.add_period_constraint(self.cd_usb_48.clk, 1e9/48e6)
platform.add_period_constraint(self.cd_sys.clk, 1e9/12e6)
platform.add_period_constraint(self.cd_usb_12.clk, 1e9/12e6)
platform.add_period_constraint(clk48, 1e9/48e6)
platform.add_period_constraint(clk48_raw, 1e9/48e6)
platform.add_period_constraint(clk12_raw, 1e9/12e6)
# POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset.
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),
]
if use_pll:
# Divide clk48 down to clk12, to ensure they're synchronized.
# By doing this, we avoid needing clock-domain crossing.
clk12_counter = Signal(2)
self.clock_domains.cd_usb_48_raw = ClockDomain()
platform.add_period_constraint(self.cd_usb_48_raw.clk, 1e9/48e6)
# POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset.
self.comb += [
self.cd_usb_48.rst.eq(reset_delay != 0),
]
self.comb += self.cd_usb_48_raw.clk.eq(clk48_raw)
self.comb += self.cd_usb_48.clk.eq(clk48)
self.sync.usb_48_raw += clk12_counter.eq(clk12_counter + 1)
self.comb += clk12_raw.eq(clk12_counter[1])
self.specials += Instance(
"SB_GB",
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw,
o_GLOBAL_BUFFER_OUTPUT=clk12,
)
self.specials += Instance(
"SB_PLL40_CORE",
# Parameters
p_DIVR = 0,
p_DIVF = 3,
p_DIVQ = 2,
p_FILTER_RANGE = 1,
p_FEEDBACK_PATH = "PHASE_AND_DELAY",
p_DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED",
p_FDA_FEEDBACK = 15,
p_DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED",
p_FDA_RELATIVE = 0,
p_SHIFTREG_DIV_MODE = 1,
p_PLLOUT_SELECT = "SHIFTREG_0deg",
p_ENABLE_ICEGATE = 0,
# IO
i_REFERENCECLK = clk12,
o_PLLOUTGLOBAL = clk48,
i_BYPASS = 0,
i_RESETB = 1,
)
else:
self.specials += Instance(
"SB_GB",
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk48_raw,
o_GLOBAL_BUFFER_OUTPUT=clk48,
)
self.comb += self.cd_usb_48.clk.eq(clk48)
clk12_counter = Signal(2)
self.sync.usb_48 += clk12_counter.eq(clk12_counter + 1)
self.comb += clk12_raw.eq(clk12_counter[1])
self.specials += Instance(
"SB_GB",
i_USER_SIGNAL_TO_GLOBAL_BUFFER=clk12_raw,
o_GLOBAL_BUFFER_OUTPUT=clk12,
)
self.comb += self.cd_sys.clk.eq(clk12)
self.comb += self.cd_usb_12.clk.eq(clk12)
self.sync.por += \
If(reset_delay != 0,
reset_delay.eq(reset_delay - 1)
)
self.specials += AsyncResetSynchronizer(self.cd_por, self.reset)
class PicoRVSpi(Module, AutoCSR):
def __init__(self, platform, pads, size=2*1024*1024):
self.size = size
self.bus = bus = wishbone.Interface()
self.reset = Signal()
self.cfg1 = CSRStorage(size=8)
self.cfg2 = CSRStorage(size=8)
self.cfg3 = CSRStorage(size=8)
self.cfg4 = CSRStorage(size=8)
self.stat1 = CSRStatus(size=8)
self.stat2 = CSRStatus(size=8)
self.stat3 = CSRStatus(size=8)
self.stat4 = CSRStatus(size=8)
cfg = Signal(32)
cfg_we = Signal(4)
cfg_out = Signal(32)
self.comb += [
cfg.eq(Cat(self.cfg1.storage, self.cfg2.storage, self.cfg3.storage, self.cfg4.storage)),
cfg_we.eq(Cat(self.cfg1.re, self.cfg2.re, self.cfg3.re, self.cfg4.re)),
self.stat1.status.eq(cfg_out[0:8]),
self.stat2.status.eq(cfg_out[8:16]),
self.stat3.status.eq(cfg_out[16:24]),
self.stat4.status.eq(cfg_out[24:32]),
]
mosi_pad = TSTriple()
miso_pad = TSTriple()
cs_n_pad = TSTriple()
clk_pad = TSTriple()
wp_pad = TSTriple()
hold_pad = TSTriple()
self.specials += mosi_pad.get_tristate(pads.mosi)
self.specials += miso_pad.get_tristate(pads.miso)
self.specials += cs_n_pad.get_tristate(pads.cs_n)
self.specials += clk_pad.get_tristate(pads.clk)
self.specials += wp_pad.get_tristate(pads.wp)
self.specials += hold_pad.get_tristate(pads.hold)
reset = Signal()
self.comb += [
reset.eq(ResetSignal() | self.reset),
cs_n_pad.oe.eq(~reset),
clk_pad.oe.eq(~reset),
]
flash_addr = Signal(24)
mem_bits = bits_for(size)
self.comb += flash_addr.eq(bus.adr[0:mem_bits-2] << 2),
read_active = Signal()
spi_ready = Signal()
self.sync += [
If(bus.stb & bus.cyc & ~read_active,
read_active.eq(1),
bus.ack.eq(0),
)
.Elif(read_active & spi_ready,
read_active.eq(0),
bus.ack.eq(1),
)
.Else(
bus.ack.eq(0),
read_active.eq(0),
)
]
o_rdata = Signal(32)
self.comb += bus.dat_r.eq(o_rdata)
self.specials += Instance("spimemio",
o_flash_io0_oe = mosi_pad.oe,
o_flash_io1_oe = miso_pad.oe,
o_flash_io2_oe = wp_pad.oe,
o_flash_io3_oe = hold_pad.oe,
o_flash_io0_do = mosi_pad.o,
o_flash_io1_do = miso_pad.o,
o_flash_io2_do = wp_pad.o,
o_flash_io3_do = hold_pad.o,
o_flash_csb = cs_n_pad.o,
o_flash_clk = clk_pad.o,
i_flash_io0_di = mosi_pad.i,
i_flash_io1_di = miso_pad.i,
i_flash_io2_di = wp_pad.i,
i_flash_io3_di = hold_pad.i,
i_resetn = ~reset,
i_clk = ClockSignal(),
i_valid = bus.stb & bus.cyc,
o_ready = spi_ready,
i_addr = flash_addr,
o_rdata = o_rdata,
i_cfgreg_we = cfg_we,
i_cfgreg_di = cfg,
o_cfgreg_do = cfg_out,
)
platform.add_source("rtl/spimemio.v")
class BaseSoC(SoCCore):
csr_peripherals = [
"ddrphy",
# "dna",
"xadc",
"cpu_or_bridge",
]
SoCCore.csr_map = {
"ctrl": 0, # provided by default (optional)
"crg": 1, # user
"uart_phy": 2, # provided by default (optional)
"uart": 3, # provided by default (optional)
"identifier_mem": 4, # provided by default (optional)
"timer0": 5, # provided by default (optional)
"cpu_or_bridge": 8,
"usb": 9,
"picorvspi": 10,
"touch": 11,
"reboot": 12,
"rgb": 13,
"version": 14,
}
mem_map = {
"spiflash": 0x20000000, # (default shadow @0xa0000000)
}
mem_map.update(SoCCore.mem_map)
def __init__(self, platform, output_dir="build", use_pll=True, **kwargs):
clk_freq = int(12e6)
self.output_dir = output_dir
self.submodules.crg = _CRG(platform, use_pll=use_pll)
SoCCore.__init__(self, platform, clk_freq,
integrated_sram_size=0, with_uart=False,
**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)
# Add a simple bit-banged SPI Flash module based on PicoRVSpi
spi_pads = platform.request("spiflash")
self.submodules.picorvspi = PicoRVSpi(platform, spi_pads)
self.register_mem("spiflash", self.mem_map["spiflash"],
self.picorvspi.bus, size=self.picorvspi.size)
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)
if hasattr(self, "cpu"):
self.cpu.use_external_variant("rtl/2-stage-1024-cache.v")
self.copy_memory_file("2-stage-1024-cache.v_toplevel_RegFilePlugin_regFile.bin")
def copy_memory_file(self, src):
import os
from shutil import copyfile
if not os.path.exists(self.output_dir):
os.mkdir(self.output_dir)
if not os.path.exists(os.path.join(self.output_dir, "gateware")):
os.mkdir(os.path.join(self.output_dir, "gateware"))
copyfile(os.path.join("rtl", src), os.path.join(self.output_dir, "gateware", src))
def main():
platform = Platform()
soc = BaseSoC(platform)
builder = Builder(soc,
output_dir="build", csr_csv="test/csr.csv",
compile_software=False)
vns = builder.build()
soc.do_exit(vns)
if __name__ == "__main__":
main()