From d9e09707ae3c0f5ba6d48b1dbf3ee1dccfb3965f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 13 Apr 2015 16:19:55 +0200 Subject: [PATCH] global: pep8 (replace tabs with spaces) --- crc.py | 28 +- flash_extra.py | 36 +- make.py | 308 ++++---- misoc_import.py | 24 +- misoclib/com/gpio/__init__.py | 30 +- misoclib/com/spi/__init__.py | 296 ++++---- misoclib/com/spi/test/spi_master_tb.py | 120 ++-- misoclib/com/uart/__init__.py | 46 +- misoclib/com/uart/phy/__init__.py | 14 +- misoclib/com/uart/phy/serial.py | 176 ++--- misoclib/com/uart/phy/sim.py | 40 +- misoclib/com/uart/test/test_serial_phy.py | 184 ++--- misoclib/cpu/lm32/__init__.py | 112 +-- misoclib/cpu/mor1kx/__init__.py | 128 ++-- .../cpu/peripherals/identifier/__init__.py | 24 +- misoclib/cpu/peripherals/identifier/git.py | 4 +- misoclib/cpu/peripherals/timer/__init__.py | 50 +- misoclib/mem/flash/norflash16/__init__.py | 174 ++--- misoclib/mem/flash/spiflash/__init__.py | 316 ++++---- misoclib/mem/sdram/__init__.py | 4 +- misoclib/mem/sdram/core/__init__.py | 34 +- misoclib/mem/sdram/core/lasmibus.py | 288 ++++---- misoclib/mem/sdram/core/lasmicon/__init__.py | 92 +-- .../mem/sdram/core/lasmicon/bankmachine.py | 248 +++---- .../mem/sdram/core/lasmicon/multiplexer.py | 412 +++++------ misoclib/mem/sdram/core/lasmicon/perf.py | 76 +- misoclib/mem/sdram/core/lasmicon/refresher.py | 116 +-- misoclib/mem/sdram/core/lasmixbar.py | 332 ++++----- misoclib/mem/sdram/core/minicon/__init__.py | 372 +++++----- misoclib/mem/sdram/frontend/dma_lasmi.py | 162 ++--- misoclib/mem/sdram/frontend/memtest.py | 174 ++--- misoclib/mem/sdram/frontend/wishbone2lasmi.py | 316 ++++---- misoclib/mem/sdram/module.py | 270 +++---- misoclib/mem/sdram/phy/dfi.py | 104 +-- misoclib/mem/sdram/phy/dfii.py | 100 +-- misoclib/mem/sdram/phy/gensdrphy.py | 114 +-- misoclib/mem/sdram/phy/initsequence.py | 398 +++++----- misoclib/mem/sdram/phy/k7ddrphy.py | 512 ++++++------- misoclib/mem/sdram/phy/s6ddrphy.py | 678 +++++++++--------- misoclib/mem/sdram/phy/simphy.py | 330 ++++----- .../sdram/test/abstract_transactions_lasmi.py | 48 +- misoclib/mem/sdram/test/bankmachine_tb.py | 54 +- misoclib/mem/sdram/test/common.py | 144 ++-- misoclib/mem/sdram/test/lasmicon_df_tb.py | 50 +- misoclib/mem/sdram/test/lasmicon_tb.py | 42 +- misoclib/mem/sdram/test/lasmicon_wb.py | 40 +- misoclib/mem/sdram/test/minicon_tb.py | 264 +++---- misoclib/mem/sdram/test/refresher.py | 62 +- misoclib/others/mxcrg/__init__.py | 70 +- misoclib/soc/__init__.py | 370 +++++----- misoclib/soc/cpuif.py | 154 ++-- misoclib/soc/sdram.py | 128 ++-- misoclib/video/dvisampler/__init__.py | 108 +-- misoclib/video/dvisampler/analysis.py | 382 +++++----- misoclib/video/dvisampler/chansync.py | 216 +++--- misoclib/video/dvisampler/charsync.py | 90 +-- misoclib/video/dvisampler/clocking.py | 130 ++-- misoclib/video/dvisampler/datacapture.py | 362 +++++----- misoclib/video/dvisampler/debug.py | 64 +- misoclib/video/dvisampler/decoding.py | 32 +- misoclib/video/dvisampler/dma.py | 254 +++---- misoclib/video/dvisampler/edid.py | 356 ++++----- misoclib/video/dvisampler/wer.py | 102 +-- misoclib/video/framebuffer/__init__.py | 32 +- misoclib/video/framebuffer/dvi.py | 396 +++++----- misoclib/video/framebuffer/format.py | 240 +++---- misoclib/video/framebuffer/phy.py | 408 +++++------ mkmscimg.py | 12 +- setup.py | 46 +- targets/de0nano.py | 144 ++-- targets/kc705.py | 212 +++--- targets/minispartan6.py | 114 +-- targets/mlabs_video.py | 182 ++--- targets/pipistrello.py | 194 ++--- targets/ppro.py | 130 ++-- targets/simple.py | 60 +- targets/versa.py | 16 +- tools/flterm.py | 506 ++++++------- 78 files changed, 6728 insertions(+), 6728 deletions(-) diff --git a/crc.py b/crc.py index 26323fe2..7967802e 100644 --- a/crc.py +++ b/crc.py @@ -1,19 +1,19 @@ import binascii def insert_crc(i_filename, fbi_mode=False, o_filename=None): - if o_filename is None: - o_filename = i_filename + if o_filename is None: + o_filename = i_filename - with open(i_filename, 'rb') as f: - fdata = f.read() - fcrc = binascii.crc32(fdata).to_bytes(4, byteorder="big") - flength = len(fdata).to_bytes(4, byteorder="big") + with open(i_filename, 'rb') as f: + fdata = f.read() + fcrc = binascii.crc32(fdata).to_bytes(4, byteorder="big") + flength = len(fdata).to_bytes(4, byteorder="big") - with open(o_filename, 'wb') as f: - if fbi_mode: - f.write(flength) - f.write(fcrc) - f.write(fdata) - else: - f.write(fdata) - f.write(fcrc) + with open(o_filename, 'wb') as f: + if fbi_mode: + f.write(flength) + f.write(fcrc) + f.write(fdata) + else: + f.write(fdata) + f.write(fcrc) diff --git a/flash_extra.py b/flash_extra.py index 34ee8c6b..68b26a0d 100755 --- a/flash_extra.py +++ b/flash_extra.py @@ -7,24 +7,24 @@ from migen.util.misc import autotype from misoc_import import misoc_import if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Program extra data to flash memory.") - parser.add_argument("-f", "--flash-proxy-dir", default=None, help="set search directory for flash proxy bitstreams") - parser.add_argument("-X", "--external", default="", help="use external directory for platforms and imports") - parser.add_argument("-Op", "--platform-option", default=[], nargs=2, action="append", help="set platform-specific option") - parser.add_argument("platform", help="target platform") - parser.add_argument("file", help="file to flash") - parser.add_argument("address", help="flash address to write") - args = parser.parse_args() + parser = argparse.ArgumentParser(description="Program extra data to flash memory.") + parser.add_argument("-f", "--flash-proxy-dir", default=None, help="set search directory for flash proxy bitstreams") + parser.add_argument("-X", "--external", default="", help="use external directory for platforms and imports") + parser.add_argument("-Op", "--platform-option", default=[], nargs=2, action="append", help="set platform-specific option") + parser.add_argument("platform", help="target platform") + parser.add_argument("file", help="file to flash") + parser.add_argument("address", help="flash address to write") + args = parser.parse_args() - external_platform = "" - if args.external: - external_platform = os.path.join(args.external, "platforms") - sys.path.insert(1, os.path.abspath(args.external)) + external_platform = "" + if args.external: + external_platform = os.path.join(args.external, "platforms") + sys.path.insert(1, os.path.abspath(args.external)) - platform_module = misoc_import("mibuild.platforms", external_platform, args.platform) - platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option) - platform = platform_module.Platform(**platform_kwargs) + platform_module = misoc_import("mibuild.platforms", external_platform, args.platform) + platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option) + platform = platform_module.Platform(**platform_kwargs) - prog = platform.create_programmer() - prog.set_flash_proxy_dir(args.flash_proxy_dir) - prog.flash(int(args.address, 0), args.file) + prog = platform.create_programmer() + prog.set_flash_proxy_dir(args.flash_proxy_dir) + prog.flash(int(args.address, 0), args.file) diff --git a/make.py b/make.py index 6591ceee..0ac7df7f 100755 --- a/make.py +++ b/make.py @@ -12,8 +12,8 @@ from misoclib.mem.sdram.phy import initsequence from misoc_import import misoc_import def _get_args(): - parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, - description="""\ + parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, + description="""\ MiSoC - a high performance and small footprint SoC based on Migen. This program builds and/or loads MiSoC components. @@ -35,73 +35,73 @@ all clean, build-bitstream, build-bios, flash-bitstream, flash-bios. Load/flash actions use the existing outputs, and do not trigger new builds. """) - parser.add_argument("-t", "--target", default="mlabs_video", help="SoC type to build") - parser.add_argument("-s", "--sub-target", default="", help="variant of the SoC type to build") - parser.add_argument("-p", "--platform", default=None, help="platform to build for") - parser.add_argument("-Ot", "--target-option", default=[], nargs=2, action="append", help="set target-specific option") - parser.add_argument("-Op", "--platform-option", default=[], nargs=2, action="append", help="set platform-specific option") - parser.add_argument("-X", "--external", default="", help="use external directory for targets, platforms and imports") - parser.add_argument("--csr_csv", default="csr.csv", help="CSV file to save the CSR map into") + parser.add_argument("-t", "--target", default="mlabs_video", help="SoC type to build") + parser.add_argument("-s", "--sub-target", default="", help="variant of the SoC type to build") + parser.add_argument("-p", "--platform", default=None, help="platform to build for") + parser.add_argument("-Ot", "--target-option", default=[], nargs=2, action="append", help="set target-specific option") + parser.add_argument("-Op", "--platform-option", default=[], nargs=2, action="append", help="set platform-specific option") + parser.add_argument("-X", "--external", default="", help="use external directory for targets, platforms and imports") + parser.add_argument("--csr_csv", default="csr.csv", help="CSV file to save the CSR map into") - parser.add_argument("-d", "--decorate", default=[], action="append", help="apply simplification decorator to top-level") - parser.add_argument("-Ob", "--build-option", default=[], nargs=2, action="append", help="set build option") - parser.add_argument("-f", "--flash-proxy-dir", default=None, help="set search directory for flash proxy bitstreams") + parser.add_argument("-d", "--decorate", default=[], action="append", help="apply simplification decorator to top-level") + parser.add_argument("-Ob", "--build-option", default=[], nargs=2, action="append", help="set build option") + parser.add_argument("-f", "--flash-proxy-dir", default=None, help="set search directory for flash proxy bitstreams") - parser.add_argument("action", nargs="+", help="specify an action") + parser.add_argument("action", nargs="+", help="specify an action") - return parser.parse_args() + return parser.parse_args() if __name__ == "__main__": - args = _get_args() - - external_target = "" - external_platform = "" - if args.external: - external_target = os.path.join(args.external, "targets") - external_platform = os.path.join(args.external, "platforms") - sys.path.insert(1, os.path.abspath(args.external)) - - # create top-level SoC object - target_module = misoc_import("targets", external_target, args.target) - if args.sub_target: - top_class = getattr(target_module, args.sub_target) - else: - top_class = target_module.default_subtarget - - if args.platform is None: - if hasattr(top_class, "default_platform"): - platform_name = top_class.default_platform - else: - raise ValueError("Target has no default platform, specify a platform with -p your_platform") - else: - platform_name = args.platform - platform_module = misoc_import("mibuild.platforms", external_platform, platform_name) - platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option) - platform = platform_module.Platform(**platform_kwargs) - if args.external: - platform.soc_ext_path = os.path.abspath(args.external) - - build_name = args.target + "-" + top_class.__name__.lower() + "-" + platform_name - top_kwargs = dict((k, autotype(v)) for k, v in args.target_option) - soc = top_class(platform, **top_kwargs) - soc.finalize() - memory_regions = soc.get_memory_regions() - csr_regions = soc.get_csr_regions() - - # decode actions - action_list = ["clean", "build-bitstream", "build-headers", "build-csr-csv", "build-bios", - "load-bitstream", "flash-bitstream", "flash-bios", "all"] - actions = {k: False for k in action_list} - for action in args.action: - if action in actions: - actions[action] = True - else: - print("Unknown action: {}. Valid actions are:".format(action)) - for a in action_list: - print(" "+a) - sys.exit(1) - - print("""\ + args = _get_args() + + external_target = "" + external_platform = "" + if args.external: + external_target = os.path.join(args.external, "targets") + external_platform = os.path.join(args.external, "platforms") + sys.path.insert(1, os.path.abspath(args.external)) + + # create top-level SoC object + target_module = misoc_import("targets", external_target, args.target) + if args.sub_target: + top_class = getattr(target_module, args.sub_target) + else: + top_class = target_module.default_subtarget + + if args.platform is None: + if hasattr(top_class, "default_platform"): + platform_name = top_class.default_platform + else: + raise ValueError("Target has no default platform, specify a platform with -p your_platform") + else: + platform_name = args.platform + platform_module = misoc_import("mibuild.platforms", external_platform, platform_name) + platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option) + platform = platform_module.Platform(**platform_kwargs) + if args.external: + platform.soc_ext_path = os.path.abspath(args.external) + + build_name = args.target + "-" + top_class.__name__.lower() + "-" + platform_name + top_kwargs = dict((k, autotype(v)) for k, v in args.target_option) + soc = top_class(platform, **top_kwargs) + soc.finalize() + memory_regions = soc.get_memory_regions() + csr_regions = soc.get_csr_regions() + + # decode actions + action_list = ["clean", "build-bitstream", "build-headers", "build-csr-csv", "build-bios", + "load-bitstream", "flash-bitstream", "flash-bios", "all"] + actions = {k: False for k in action_list} + for action in args.action: + if action in actions: + actions[action] = True + else: + print("Unknown action: {}. Valid actions are:".format(action)) + for a in action_list: + print(" "+a) + sys.exit(1) + + print("""\ __ ___ _ ____ _____ / |/ / (_) / __/__ / ___/ / /|_/ / / / _\ \/ _ \/ /__ @@ -116,29 +116,29 @@ Subtarget: {} CPU type: {} ===========================""".format(platform_name, args.target, top_class.__name__, soc.cpu_type)) - # dependencies - if actions["all"]: - actions["clean"] = True - actions["build-bitstream"] = True - actions["build-bios"] = True - if not actions["load-bitstream"]: - actions["flash-bitstream"] = True - if not soc.integrated_rom_size: - actions["flash-bios"] = True - if actions["build-bitstream"] and soc.integrated_rom_size: - actions["build-bios"] = True - if actions["build-bios"]: - actions["build-headers"] = True - - if actions["clean"]: - subprocess.call(["rm", "-rf", "build/*"]) - subprocess.call(["make", "-C", os.path.join("software", "libcompiler-rt"), "clean"]) - subprocess.call(["make", "-C", os.path.join("software", "libbase"), "clean"]) - subprocess.call(["make", "-C", os.path.join("software", "libnet"), "clean"]) - subprocess.call(["make", "-C", os.path.join("software", "bios"), "clean"]) - - if actions["build-headers"]: - boilerplate = """/* + # dependencies + if actions["all"]: + actions["clean"] = True + actions["build-bitstream"] = True + actions["build-bios"] = True + if not actions["load-bitstream"]: + actions["flash-bitstream"] = True + if not soc.integrated_rom_size: + actions["flash-bios"] = True + if actions["build-bitstream"] and soc.integrated_rom_size: + actions["build-bios"] = True + if actions["build-bios"]: + actions["build-headers"] = True + + if actions["clean"]: + subprocess.call(["rm", "-rf", "build/*"]) + subprocess.call(["make", "-C", os.path.join("software", "libcompiler-rt"), "clean"]) + subprocess.call(["make", "-C", os.path.join("software", "libbase"), "clean"]) + subprocess.call(["make", "-C", os.path.join("software", "libnet"), "clean"]) + subprocess.call(["make", "-C", os.path.join("software", "bios"), "clean"]) + + if actions["build-headers"]: + boilerplate = """/* * Platform: {} * Target: {} * Subtarget: {} @@ -146,70 +146,70 @@ CPU type: {} */ """.format(platform_name, args.target, top_class.__name__, soc.cpu_type) - genhdir = os.path.join("software", "include", "generated") - if soc.cpu_type != "none": - cpu_mak = cpuif.get_cpu_mak(soc.cpu_type) - write_to_file(os.path.join(genhdir, "cpu.mak"), cpu_mak) - linker_output_format = cpuif.get_linker_output_format(soc.cpu_type) - write_to_file(os.path.join(genhdir, "output_format.ld"), linker_output_format) - - linker_regions = cpuif.get_linker_regions(memory_regions) - write_to_file(os.path.join(genhdir, "regions.ld"), boilerplate + linker_regions) - - for sdram_phy in ["sdrphy", "ddrphy"]: - if hasattr(soc, sdram_phy): - sdram_phy_header = initsequence.get_sdram_phy_header(getattr(soc, sdram_phy).settings) - write_to_file(os.path.join(genhdir, "sdram_phy.h"), boilerplate + sdram_phy_header) - mem_header = cpuif.get_mem_header(memory_regions, getattr(soc, "flash_boot_address", None)) - write_to_file(os.path.join(genhdir, "mem.h"), boilerplate + mem_header) - csr_header = cpuif.get_csr_header(csr_regions, soc.get_constants()) - write_to_file(os.path.join(genhdir, "csr.h"), boilerplate + csr_header) - - if actions["build-csr-csv"]: - csr_csv = cpuif.get_csr_csv(csr_regions) - write_to_file(args.csr_csv, csr_csv) - - if actions["build-bios"]: - ret = subprocess.call(["make", "-C", os.path.join("software", "bios")]) - if ret: - raise OSError("BIOS build failed") - - bios_file = os.path.join("software", "bios", "bios.bin") - - if actions["build-bitstream"]: - if soc.integrated_rom_size: - with open(bios_file, "rb") as boot_file: - boot_data = [] - while True: - w = boot_file.read(4) - if not w: - break - boot_data.append(struct.unpack(">I", w)[0]) - soc.init_rom(boot_data) - - for decorator in args.decorate: - soc = getattr(simplify, decorator)(soc) - build_kwargs = dict((k, autotype(v)) for k, v in args.build_option) - vns = platform.build(soc, build_name=build_name, **build_kwargs) - soc.do_exit(vns) - - if actions["load-bitstream"]: - prog = platform.create_programmer() - prog.load_bitstream(os.path.join("build", build_name + platform.bitstream_ext)) - - if actions["flash-bitstream"]: - prog = platform.create_programmer() - prog.set_flash_proxy_dir(args.flash_proxy_dir) - if prog.needs_bitreverse: - flashbit = os.path.join("build", build_name + ".fpg") - subprocess.call([os.path.join("tools", "byteswap"), - os.path.join("build", build_name + ".bin"), - flashbit]) - else: - flashbit = os.path.join("build", build_name + ".bin") - prog.flash(0, flashbit) - - if actions["flash-bios"]: - prog = platform.create_programmer() - prog.set_flash_proxy_dir(args.flash_proxy_dir) - prog.flash(soc.cpu_reset_address, bios_file) + genhdir = os.path.join("software", "include", "generated") + if soc.cpu_type != "none": + cpu_mak = cpuif.get_cpu_mak(soc.cpu_type) + write_to_file(os.path.join(genhdir, "cpu.mak"), cpu_mak) + linker_output_format = cpuif.get_linker_output_format(soc.cpu_type) + write_to_file(os.path.join(genhdir, "output_format.ld"), linker_output_format) + + linker_regions = cpuif.get_linker_regions(memory_regions) + write_to_file(os.path.join(genhdir, "regions.ld"), boilerplate + linker_regions) + + for sdram_phy in ["sdrphy", "ddrphy"]: + if hasattr(soc, sdram_phy): + sdram_phy_header = initsequence.get_sdram_phy_header(getattr(soc, sdram_phy).settings) + write_to_file(os.path.join(genhdir, "sdram_phy.h"), boilerplate + sdram_phy_header) + mem_header = cpuif.get_mem_header(memory_regions, getattr(soc, "flash_boot_address", None)) + write_to_file(os.path.join(genhdir, "mem.h"), boilerplate + mem_header) + csr_header = cpuif.get_csr_header(csr_regions, soc.get_constants()) + write_to_file(os.path.join(genhdir, "csr.h"), boilerplate + csr_header) + + if actions["build-csr-csv"]: + csr_csv = cpuif.get_csr_csv(csr_regions) + write_to_file(args.csr_csv, csr_csv) + + if actions["build-bios"]: + ret = subprocess.call(["make", "-C", os.path.join("software", "bios")]) + if ret: + raise OSError("BIOS build failed") + + bios_file = os.path.join("software", "bios", "bios.bin") + + if actions["build-bitstream"]: + if soc.integrated_rom_size: + with open(bios_file, "rb") as boot_file: + boot_data = [] + while True: + w = boot_file.read(4) + if not w: + break + boot_data.append(struct.unpack(">I", w)[0]) + soc.init_rom(boot_data) + + for decorator in args.decorate: + soc = getattr(simplify, decorator)(soc) + build_kwargs = dict((k, autotype(v)) for k, v in args.build_option) + vns = platform.build(soc, build_name=build_name, **build_kwargs) + soc.do_exit(vns) + + if actions["load-bitstream"]: + prog = platform.create_programmer() + prog.load_bitstream(os.path.join("build", build_name + platform.bitstream_ext)) + + if actions["flash-bitstream"]: + prog = platform.create_programmer() + prog.set_flash_proxy_dir(args.flash_proxy_dir) + if prog.needs_bitreverse: + flashbit = os.path.join("build", build_name + ".fpg") + subprocess.call([os.path.join("tools", "byteswap"), + os.path.join("build", build_name + ".bin"), + flashbit]) + else: + flashbit = os.path.join("build", build_name + ".bin") + prog.flash(0, flashbit) + + if actions["flash-bios"]: + prog = platform.create_programmer() + prog.set_flash_proxy_dir(args.flash_proxy_dir) + prog.flash(soc.cpu_reset_address, bios_file) diff --git a/misoc_import.py b/misoc_import.py index cba769ce..51868a34 100644 --- a/misoc_import.py +++ b/misoc_import.py @@ -1,15 +1,15 @@ import sys, importlib def misoc_import(default, external, name): - if external: - try: - del sys.modules[name] # force external path search - except KeyError: - pass - loader = importlib.find_loader(name, [external]) - if loader is None: - # try internal import - return importlib.import_module(default + "." + name) - return loader.load_module() - else: - return importlib.import_module(default + "." + name) + if external: + try: + del sys.modules[name] # force external path search + except KeyError: + pass + loader = importlib.find_loader(name, [external]) + if loader is None: + # try internal import + return importlib.import_module(default + "." + name) + return loader.load_module() + else: + return importlib.import_module(default + "." + name) diff --git a/misoclib/com/gpio/__init__.py b/misoclib/com/gpio/__init__.py index e8ae09db..f5fc17ad 100644 --- a/misoclib/com/gpio/__init__.py +++ b/misoclib/com/gpio/__init__.py @@ -3,25 +3,25 @@ from migen.genlib.cdc import MultiReg from migen.bank.description import * class GPIOIn(Module, AutoCSR): - def __init__(self, signal): - self._in = CSRStatus(flen(signal)) - self.specials += MultiReg(signal, self._in.status) + def __init__(self, signal): + self._in = CSRStatus(flen(signal)) + self.specials += MultiReg(signal, self._in.status) class GPIOOut(Module, AutoCSR): - def __init__(self, signal): - self._out = CSRStorage(flen(signal)) - self.comb += signal.eq(self._out.storage) + def __init__(self, signal): + self._out = CSRStorage(flen(signal)) + self.comb += signal.eq(self._out.storage) class GPIOInOut(Module): - def __init__(self, in_signal, out_signal): - self.submodules.gpio_in = GPIOIn(in_signal) - self.submodules.gpio_out = GPIOOut(out_signal) + def __init__(self, in_signal, out_signal): + self.submodules.gpio_in = GPIOIn(in_signal) + self.submodules.gpio_out = GPIOOut(out_signal) - def get_csrs(self): - return self.gpio_in.get_csrs() + self.gpio_out.get_csrs() + def get_csrs(self): + return self.gpio_in.get_csrs() + self.gpio_out.get_csrs() class Blinker(Module): - def __init__(self, signal, divbits=26): - counter = Signal(divbits) - self.comb += signal.eq(counter[divbits-1]) - self.sync += counter.eq(counter + 1) + def __init__(self, signal, divbits=26): + counter = Signal(divbits) + self.comb += signal.eq(counter[divbits-1]) + self.sync += counter.eq(counter + 1) diff --git a/misoclib/com/spi/__init__.py b/misoclib/com/spi/__init__.py index 7c153123..4080e5d4 100644 --- a/misoclib/com/spi/__init__.py +++ b/misoclib/com/spi/__init__.py @@ -3,151 +3,151 @@ from migen.bank.description import * from migen.genlib.fsm import FSM, NextState class SPIMaster(Module, AutoCSR): - def __init__(self, pads, width=24, div=2, cpha=1): - self.pads = pads - - self._ctrl = CSR() - self._length = CSRStorage(8) - self._status = CSRStatus() - if hasattr(pads, "mosi"): - self._mosi = CSRStorage(width) - if hasattr(pads, "miso"): - self._miso = CSRStatus(width) - - self.irq = Signal() - - ### - - # ctrl - start = Signal() - length = self._length.storage - enable_cs = Signal() - enable_shift = Signal() - done = Signal() - - self.comb += [ - start.eq(self._ctrl.re & self._ctrl.r[0]), - self._status.status.eq(done) - ] - - # clk - i = Signal(max=div) - clk_en = Signal() - set_clk = Signal() - clr_clk = Signal() - self.sync += [ - If(set_clk, - pads.clk.eq(enable_cs) - ), - If(clr_clk, - pads.clk.eq(0), - i.eq(0) - ).Else( - i.eq(i + 1), - ) - ] - - self.comb +=[ - set_clk.eq(i==div//2-1), - clr_clk.eq(i==div-1) - ] - - # fsm - cnt = Signal(8) - clr_cnt = Signal() - inc_cnt = Signal() - self.sync += \ - If(clr_cnt, - cnt.eq(0) - ).Elif(inc_cnt, - cnt.eq(cnt+1) - ) - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - fsm.act("IDLE", - If(start, - NextState("WAIT_CLK") - ), - done.eq(1), - clr_cnt.eq(1) - ) - fsm.act("WAIT_CLK", - If(clr_clk, - NextState("SHIFT") - ), - ) - fsm.act("SHIFT", - If(cnt == length, - NextState("END") - ).Else( - inc_cnt.eq(clr_clk), - ), - enable_cs.eq(1), - enable_shift.eq(1), - ) - fsm.act("END", - If(set_clk, - NextState("IDLE") - ), - enable_shift.eq(1), - self.irq.eq(1) - ) - - # miso - if hasattr(pads, "miso"): - miso = Signal() - sr_miso = Signal(width) - - # (cpha = 1: capture on clk falling edge) - if cpha: - self.sync += \ - If(enable_shift, - If(clr_clk, - miso.eq(pads.miso), - ).Elif(set_clk, - sr_miso.eq(Cat(miso, sr_miso[:-1])) - ) - ) - # (cpha = 0: capture on clk rising edge) - else: - self.sync += \ - If(enable_shift, - If(set_clk, - miso.eq(pads.miso), - ).Elif(clr_clk, - sr_miso.eq(Cat(miso, sr_miso[:-1])) - ) - ) - self.comb += self._miso.status.eq(sr_miso) - - # mosi - if hasattr(pads, "mosi"): - mosi = Signal() - sr_mosi = Signal(width) - - # (cpha = 1: propagated on clk rising edge) - if cpha: - self.sync += \ - If(start, - sr_mosi.eq(self._mosi.storage) - ).Elif(clr_clk & enable_shift, - sr_mosi.eq(Cat(Signal(), sr_mosi[:-1])) - ).Elif(set_clk, - pads.mosi.eq(sr_mosi[-1]) - ) - - # (cpha = 0: propagated on clk falling edge) - else: - self.sync += [ - If(start, - sr_mosi.eq(self._mosi.storage) - ).Elif(set_clk & enable_shift, - sr_mosi.eq(Cat(Signal(), sr_mosi[:-1])) - ).Elif(clr_clk, - pads.mosi.eq(sr_mosi[-1]) - ) - ] - - # cs_n - self.comb += pads.cs_n.eq(~enable_cs) + def __init__(self, pads, width=24, div=2, cpha=1): + self.pads = pads + + self._ctrl = CSR() + self._length = CSRStorage(8) + self._status = CSRStatus() + if hasattr(pads, "mosi"): + self._mosi = CSRStorage(width) + if hasattr(pads, "miso"): + self._miso = CSRStatus(width) + + self.irq = Signal() + + ### + + # ctrl + start = Signal() + length = self._length.storage + enable_cs = Signal() + enable_shift = Signal() + done = Signal() + + self.comb += [ + start.eq(self._ctrl.re & self._ctrl.r[0]), + self._status.status.eq(done) + ] + + # clk + i = Signal(max=div) + clk_en = Signal() + set_clk = Signal() + clr_clk = Signal() + self.sync += [ + If(set_clk, + pads.clk.eq(enable_cs) + ), + If(clr_clk, + pads.clk.eq(0), + i.eq(0) + ).Else( + i.eq(i + 1), + ) + ] + + self.comb +=[ + set_clk.eq(i==div//2-1), + clr_clk.eq(i==div-1) + ] + + # fsm + cnt = Signal(8) + clr_cnt = Signal() + inc_cnt = Signal() + self.sync += \ + If(clr_cnt, + cnt.eq(0) + ).Elif(inc_cnt, + cnt.eq(cnt+1) + ) + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + If(start, + NextState("WAIT_CLK") + ), + done.eq(1), + clr_cnt.eq(1) + ) + fsm.act("WAIT_CLK", + If(clr_clk, + NextState("SHIFT") + ), + ) + fsm.act("SHIFT", + If(cnt == length, + NextState("END") + ).Else( + inc_cnt.eq(clr_clk), + ), + enable_cs.eq(1), + enable_shift.eq(1), + ) + fsm.act("END", + If(set_clk, + NextState("IDLE") + ), + enable_shift.eq(1), + self.irq.eq(1) + ) + + # miso + if hasattr(pads, "miso"): + miso = Signal() + sr_miso = Signal(width) + + # (cpha = 1: capture on clk falling edge) + if cpha: + self.sync += \ + If(enable_shift, + If(clr_clk, + miso.eq(pads.miso), + ).Elif(set_clk, + sr_miso.eq(Cat(miso, sr_miso[:-1])) + ) + ) + # (cpha = 0: capture on clk rising edge) + else: + self.sync += \ + If(enable_shift, + If(set_clk, + miso.eq(pads.miso), + ).Elif(clr_clk, + sr_miso.eq(Cat(miso, sr_miso[:-1])) + ) + ) + self.comb += self._miso.status.eq(sr_miso) + + # mosi + if hasattr(pads, "mosi"): + mosi = Signal() + sr_mosi = Signal(width) + + # (cpha = 1: propagated on clk rising edge) + if cpha: + self.sync += \ + If(start, + sr_mosi.eq(self._mosi.storage) + ).Elif(clr_clk & enable_shift, + sr_mosi.eq(Cat(Signal(), sr_mosi[:-1])) + ).Elif(set_clk, + pads.mosi.eq(sr_mosi[-1]) + ) + + # (cpha = 0: propagated on clk falling edge) + else: + self.sync += [ + If(start, + sr_mosi.eq(self._mosi.storage) + ).Elif(set_clk & enable_shift, + sr_mosi.eq(Cat(Signal(), sr_mosi[:-1])) + ).Elif(clr_clk, + pads.mosi.eq(sr_mosi[-1]) + ) + ] + + # cs_n + self.comb += pads.cs_n.eq(~enable_cs) diff --git a/misoclib/com/spi/test/spi_master_tb.py b/misoclib/com/spi/test/spi_master_tb.py index 3459a56f..a4f48b7d 100644 --- a/misoclib/com/spi/test/spi_master_tb.py +++ b/misoclib/com/spi/test/spi_master_tb.py @@ -5,80 +5,80 @@ from migen.sim.generic import run_simulation from misoclib.com.spi import SPIMaster class SPISlave(Module): - def __init__(self, pads, width): - self.pads = pads - self.width = width + def __init__(self, pads, width): + self.pads = pads + self.width = width - ### + ### - self.mosi = 0 - self.miso = 0 + self.mosi = 0 + self.miso = 0 - self.last_cs_n = 1 - self.last_clk = 0 + self.last_cs_n = 1 + self.last_clk = 0 - def get_mosi(self): - return self.mosi + def get_mosi(self): + return self.mosi - def set_miso(self, value): - self.miso = value + def set_miso(self, value): + self.miso = value - def do_simulation(self, selfp): - # detect edges - cs_n_rising = 0 - cs_n_falling = 0 - clk_rising = 0 - clk_falling = 0 - if selfp.pads.cs_n and not self.last_cs_n: - cs_n_rising = 1 - if not selfp.pads.cs_n and self.last_cs_n: - cs_n_falling = 1 - if selfp.pads.clk and not self.last_clk: - clk_rising = 1 - if not selfp.pads.clk and self.last_clk: - clk_falling = 1 + def do_simulation(self, selfp): + # detect edges + cs_n_rising = 0 + cs_n_falling = 0 + clk_rising = 0 + clk_falling = 0 + if selfp.pads.cs_n and not self.last_cs_n: + cs_n_rising = 1 + if not selfp.pads.cs_n and self.last_cs_n: + cs_n_falling = 1 + if selfp.pads.clk and not self.last_clk: + clk_rising = 1 + if not selfp.pads.clk and self.last_clk: + clk_falling = 1 - # input mosi - if clk_falling and not selfp.pads.cs_n: - self.mosi = self.mosi << 1 - self.mosi |= selfp.pads.mosi + # input mosi + if clk_falling and not selfp.pads.cs_n: + self.mosi = self.mosi << 1 + self.mosi |= selfp.pads.mosi - # output miso - if (clk_rising and not selfp.pads.cs_n): - selfp.pads.miso = (self.miso >> (self.width-1)) & 0x1 - self.miso = self.miso << 1 + # output miso + if (clk_rising and not selfp.pads.cs_n): + selfp.pads.miso = (self.miso >> (self.width-1)) & 0x1 + self.miso = self.miso << 1 - # save signal states - self.last_cs_n = selfp.pads.cs_n - self.last_clk = selfp.pads.clk + # save signal states + self.last_cs_n = selfp.pads.cs_n + self.last_clk = selfp.pads.clk def spi_access(selfp, length, mosi): - selfp.spi_master._mosi.storage = mosi - yield - selfp.spi_master._ctrl.r = (length << 8) | 1 - selfp.spi_master._ctrl.re = 1 - yield - selfp.spi_master._ctrl.r = 0 - selfp.spi_master._ctrl.re = 0 - yield - while not (selfp.spi_master._status.status & 0x1): - yield + selfp.spi_master._mosi.storage = mosi + yield + selfp.spi_master._ctrl.r = (length << 8) | 1 + selfp.spi_master._ctrl.re = 1 + yield + selfp.spi_master._ctrl.r = 0 + selfp.spi_master._ctrl.re = 0 + yield + while not (selfp.spi_master._status.status & 0x1): + yield class TB(Module): - def __init__(self): - pads = Record([("cs_n", 1), ("clk", 1), ("mosi", 1), ("miso", 1)]) - self.submodules.spi_master = SPIMaster(pads, 24, 4) - self.submodules.spi_slave = SPISlave(pads, 24) - - def gen_simulation(self, selfp): - for i in range(16): - yield - self.spi_slave.set_miso(0x123457) - yield from spi_access(selfp, 8, 0x123457) - print("{:08x}".format(self.spi_slave.get_mosi())) - print("{:08x}".format(selfp.spi_master._miso.status)) + def __init__(self): + pads = Record([("cs_n", 1), ("clk", 1), ("mosi", 1), ("miso", 1)]) + self.submodules.spi_master = SPIMaster(pads, 24, 4) + self.submodules.spi_slave = SPISlave(pads, 24) + + def gen_simulation(self, selfp): + for i in range(16): + yield + self.spi_slave.set_miso(0x123457) + yield from spi_access(selfp, 8, 0x123457) + print("{:08x}".format(self.spi_slave.get_mosi())) + print("{:08x}".format(selfp.spi_master._miso.status)) if __name__ == "__main__": - run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True) \ No newline at end of file + run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True) \ No newline at end of file diff --git a/misoclib/com/uart/__init__.py b/misoclib/com/uart/__init__.py index a07462a7..1a225301 100644 --- a/misoclib/com/uart/__init__.py +++ b/misoclib/com/uart/__init__.py @@ -5,27 +5,27 @@ from migen.genlib.record import Record from migen.flow.actor import Sink, Source class UART(Module, AutoCSR): - def __init__(self, phy): - self._rxtx = CSR(8) + def __init__(self, phy): + self._rxtx = CSR(8) - self.submodules.ev = EventManager() - self.ev.tx = EventSourcePulse() - self.ev.rx = EventSourcePulse() - self.ev.finalize() - ### - self.sync += [ - If(self._rxtx.re, - phy.sink.stb.eq(1), - phy.sink.data.eq(self._rxtx.r), - ).Elif(phy.sink.ack, - phy.sink.stb.eq(0) - ), - If(phy.source.stb, - self._rxtx.w.eq(phy.source.data) - ) - ] - self.comb += [ - self.ev.tx.trigger.eq(phy.sink.stb & phy.sink.ack), - self.ev.rx.trigger.eq(phy.source.stb & phy.source.ack), - phy.source.ack.eq(~self.ev.rx.pending) - ] + self.submodules.ev = EventManager() + self.ev.tx = EventSourcePulse() + self.ev.rx = EventSourcePulse() + self.ev.finalize() + ### + self.sync += [ + If(self._rxtx.re, + phy.sink.stb.eq(1), + phy.sink.data.eq(self._rxtx.r), + ).Elif(phy.sink.ack, + phy.sink.stb.eq(0) + ), + If(phy.source.stb, + self._rxtx.w.eq(phy.source.data) + ) + ] + self.comb += [ + self.ev.tx.trigger.eq(phy.sink.stb & phy.sink.ack), + self.ev.rx.trigger.eq(phy.source.stb & phy.source.ack), + phy.source.ack.eq(~self.ev.rx.pending) + ] diff --git a/misoclib/com/uart/phy/__init__.py b/misoclib/com/uart/phy/__init__.py index 171cb423..67188c75 100644 --- a/misoclib/com/uart/phy/__init__.py +++ b/misoclib/com/uart/phy/__init__.py @@ -2,10 +2,10 @@ from misoclib.com.liteeth.common import * from misoclib.com.liteeth.generic import * def UARTPHY(pads, *args, **kwargs): - # Autodetect PHY - if hasattr(pads, "source_stb"): - from misoclib.com.uart.phy.sim import UARTPHYSim - return UARTPHYSim(pads, *args, **kwargs) - else: - from misoclib.com.uart.phy.serial import UARTPHYSerial - return UARTPHYSerial(pads, *args, **kwargs) + # Autodetect PHY + if hasattr(pads, "source_stb"): + from misoclib.com.uart.phy.sim import UARTPHYSim + return UARTPHYSim(pads, *args, **kwargs) + else: + from misoclib.com.uart.phy.serial import UARTPHYSerial + return UARTPHYSerial(pads, *args, **kwargs) diff --git a/misoclib/com/uart/phy/serial.py b/misoclib/com/uart/phy/serial.py index 8ca91b8e..086494b2 100644 --- a/misoclib/com/uart/phy/serial.py +++ b/misoclib/com/uart/phy/serial.py @@ -4,98 +4,98 @@ from migen.bank.description import * from migen.flow.actor import Sink, Source class UARTPHYSerialRX(Module): - def __init__(self, pads, tuning_word): - self.source = Source([("data", 8)]) - ### - uart_clk_rxen = Signal() - phase_accumulator_rx = Signal(32) + def __init__(self, pads, tuning_word): + self.source = Source([("data", 8)]) + ### + uart_clk_rxen = Signal() + phase_accumulator_rx = Signal(32) - rx = Signal() - self.specials += MultiReg(pads.rx, rx) - rx_r = Signal() - rx_reg = Signal(8) - rx_bitcount = Signal(4) - rx_busy = Signal() - rx_done = self.source.stb - rx_data = self.source.data - self.sync += [ - rx_done.eq(0), - rx_r.eq(rx), - If(~rx_busy, - If(~rx & rx_r, # look for start bit - rx_busy.eq(1), - rx_bitcount.eq(0), - ) - ).Else( - If(uart_clk_rxen, - rx_bitcount.eq(rx_bitcount + 1), - If(rx_bitcount == 0, - If(rx, # verify start bit - rx_busy.eq(0) - ) - ).Elif(rx_bitcount == 9, - rx_busy.eq(0), - If(rx, # verify stop bit - rx_data.eq(rx_reg), - rx_done.eq(1) - ) - ).Else( - rx_reg.eq(Cat(rx_reg[1:], rx)) - ) - ) - ) - ] - self.sync += \ - If(rx_busy, - Cat(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word) - ).Else( - Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31) - ) + rx = Signal() + self.specials += MultiReg(pads.rx, rx) + rx_r = Signal() + rx_reg = Signal(8) + rx_bitcount = Signal(4) + rx_busy = Signal() + rx_done = self.source.stb + rx_data = self.source.data + self.sync += [ + rx_done.eq(0), + rx_r.eq(rx), + If(~rx_busy, + If(~rx & rx_r, # look for start bit + rx_busy.eq(1), + rx_bitcount.eq(0), + ) + ).Else( + If(uart_clk_rxen, + rx_bitcount.eq(rx_bitcount + 1), + If(rx_bitcount == 0, + If(rx, # verify start bit + rx_busy.eq(0) + ) + ).Elif(rx_bitcount == 9, + rx_busy.eq(0), + If(rx, # verify stop bit + rx_data.eq(rx_reg), + rx_done.eq(1) + ) + ).Else( + rx_reg.eq(Cat(rx_reg[1:], rx)) + ) + ) + ) + ] + self.sync += \ + If(rx_busy, + Cat(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word) + ).Else( + Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31) + ) class UARTPHYSerialTX(Module): - def __init__(self, pads, tuning_word): - self.sink = Sink([("data", 8)]) - ### - uart_clk_txen = Signal() - phase_accumulator_tx = Signal(32) + def __init__(self, pads, tuning_word): + self.sink = Sink([("data", 8)]) + ### + uart_clk_txen = Signal() + phase_accumulator_tx = Signal(32) - pads.tx.reset = 1 + pads.tx.reset = 1 - tx_reg = Signal(8) - tx_bitcount = Signal(4) - tx_busy = Signal() - self.sync += [ - self.sink.ack.eq(0), - If(self.sink.stb & ~tx_busy & ~self.sink.ack, - tx_reg.eq(self.sink.data), - tx_bitcount.eq(0), - tx_busy.eq(1), - pads.tx.eq(0) - ).Elif(uart_clk_txen & tx_busy, - tx_bitcount.eq(tx_bitcount + 1), - If(tx_bitcount == 8, - pads.tx.eq(1) - ).Elif(tx_bitcount == 9, - pads.tx.eq(1), - tx_busy.eq(0), - self.sink.ack.eq(1), - ).Else( - pads.tx.eq(tx_reg[0]), - tx_reg.eq(Cat(tx_reg[1:], 0)) - ) - ) - ] - self.sync += [ - If(tx_busy, - Cat(phase_accumulator_tx, uart_clk_txen).eq(phase_accumulator_tx + tuning_word) - ).Else( - Cat(phase_accumulator_tx, uart_clk_txen).eq(0) - ) - ] + tx_reg = Signal(8) + tx_bitcount = Signal(4) + tx_busy = Signal() + self.sync += [ + self.sink.ack.eq(0), + If(self.sink.stb & ~tx_busy & ~self.sink.ack, + tx_reg.eq(self.sink.data), + tx_bitcount.eq(0), + tx_busy.eq(1), + pads.tx.eq(0) + ).Elif(uart_clk_txen & tx_busy, + tx_bitcount.eq(tx_bitcount + 1), + If(tx_bitcount == 8, + pads.tx.eq(1) + ).Elif(tx_bitcount == 9, + pads.tx.eq(1), + tx_busy.eq(0), + self.sink.ack.eq(1), + ).Else( + pads.tx.eq(tx_reg[0]), + tx_reg.eq(Cat(tx_reg[1:], 0)) + ) + ) + ] + self.sync += [ + If(tx_busy, + Cat(phase_accumulator_tx, uart_clk_txen).eq(phase_accumulator_tx + tuning_word) + ).Else( + Cat(phase_accumulator_tx, uart_clk_txen).eq(0) + ) + ] class UARTPHYSerial(Module, AutoCSR): - def __init__(self, pads, clk_freq, baudrate=115200): - self._tuning_word = CSRStorage(32, reset=int((baudrate/clk_freq)*2**32)) - self.submodules.tx = UARTPHYSerialTX(pads, self._tuning_word.storage) - self.submodules.rx = UARTPHYSerialRX(pads, self._tuning_word.storage) - self.sink, self.source = self.tx.sink, self.rx.source + def __init__(self, pads, clk_freq, baudrate=115200): + self._tuning_word = CSRStorage(32, reset=int((baudrate/clk_freq)*2**32)) + self.submodules.tx = UARTPHYSerialTX(pads, self._tuning_word.storage) + self.submodules.rx = UARTPHYSerialRX(pads, self._tuning_word.storage) + self.sink, self.source = self.tx.sink, self.rx.source diff --git a/misoclib/com/uart/phy/sim.py b/misoclib/com/uart/phy/sim.py index faae3d6e..346284f4 100644 --- a/misoclib/com/uart/phy/sim.py +++ b/misoclib/com/uart/phy/sim.py @@ -4,27 +4,27 @@ from migen.fhdl.std import * from migen.flow.actor import Sink, Source class UARTPHYSim(Module): - def __init__(self, pads, *args, **kwargs): - self.sink = Sink([("data", 8)]) - self.source = Source([("data", 8)]) + def __init__(self, pads, *args, **kwargs): + self.sink = Sink([("data", 8)]) + self.source = Source([("data", 8)]) - self.comb += [ - pads.source_stb.eq(self.sink.stb), - pads.source_data.eq(self.sink.data), - self.sink.ack.eq(pads.source_ack), + self.comb += [ + pads.source_stb.eq(self.sink.stb), + pads.source_data.eq(self.sink.data), + self.sink.ack.eq(pads.source_ack), - self.source.stb.eq(pads.sink_stb), - self.source.data.eq(pads.sink_data), - pads.sink_ack.eq(self.source.ack) - ] + self.source.stb.eq(pads.sink_stb), + self.source.data.eq(pads.sink_data), + pads.sink_ack.eq(self.source.ack) + ] - m, s = pty.openpty() - name = os.ttyname(s) - print("UART tty: "+name) - time.sleep(0.5) # pause for user - f = open("/tmp/simserial", "w") - f.write(os.ttyname(s)) - f.close() + m, s = pty.openpty() + name = os.ttyname(s) + print("UART tty: "+name) + time.sleep(0.5) # pause for user + f = open("/tmp/simserial", "w") + f.write(os.ttyname(s)) + f.close() - def do_exit(self, *args, **kwargs): - os.remove("/tmp/simserial") + def do_exit(self, *args, **kwargs): + os.remove("/tmp/simserial") diff --git a/misoclib/com/uart/test/test_serial_phy.py b/misoclib/com/uart/test/test_serial_phy.py index e7185c9a..dc90d8ee 100644 --- a/misoclib/com/uart/test/test_serial_phy.py +++ b/misoclib/com/uart/test/test_serial_phy.py @@ -1,96 +1,96 @@ # XXX Adapt test to new architecture class UARTTB(Module): - def __init__(self): - self.clk_freq = 83333333 - self.baud = 3000000 - self.pads = Record([("rx", 1), ("tx", 1)]) - self.submodules.slave = UART(self.pads, self.clk_freq, self.baud) - - def wait_for(self, ns_time): - freq_in_ghz = self.clk_freq/(10**9) - period = 1/freq_in_ghz - num_loops = int(ns_time/period) - for i in range(num_loops+1): - yield - - def gen_simulation(self, selfp): - baud_in_ghz = self.baud/(10**9) - uart_period = int(1/baud_in_ghz) - half_uart_period = int(1/(2*baud_in_ghz)) - - # Set TX an RX lines idle - selfp.pads.tx = 1 - selfp.pads.rx = 1 - yield - - # First send a few characters - - tx_string = "01234" - print("Sending string: " + tx_string) - for c in tx_string: - selfp.slave._r_rxtx.r = ord(c) - selfp.slave._r_rxtx.re = 1 - yield - selfp.slave._r_rxtx.re = 0 - - yield from self.wait_for(half_uart_period) - - if selfp.pads.tx: - print("FAILURE: no start bit sent") - - val = 0 - for i in range(8): - yield from self.wait_for(uart_period) - val >>= 1 - if selfp.pads.tx: - val |= 0x80 - - yield from self.wait_for(uart_period) - - if selfp.pads.tx == 0: - print("FAILURE: no stop bit sent") - - if ord(c) != val: - print("FAILURE: sent decimal value "+str(val)+" (char "+chr(val)+") instead of "+c) - else: - print("SUCCESS: sent "+c) - while selfp.slave.ev.tx.trigger != 1: - yield - - # Then receive a character - - rx_string = '5' - print("Receiving character "+rx_string) - rx_value = ord(rx_string) - for i in range(11): - if (i == 0): - # start bit - selfp.pads.rx = 0 - elif (i == 9): - # stop bit - selfp.pads.rx = 1 - elif (i == 10): - selfp.pads.rx = 1 - break - else: - selfp.pads.rx = 1 if (rx_value & 1) else 0 - rx_value >>= 1 - yield from self.wait_for(uart_period) - - rx_value = ord(rx_string) - received_value = selfp.slave._r_rxtx.w - if (received_value == rx_value): - print("RX SUCCESS: ") - else: - print("RX FAILURE: ") - - print("received "+chr(received_value)) - - while True: - yield + def __init__(self): + self.clk_freq = 83333333 + self.baud = 3000000 + self.pads = Record([("rx", 1), ("tx", 1)]) + self.submodules.slave = UART(self.pads, self.clk_freq, self.baud) + + def wait_for(self, ns_time): + freq_in_ghz = self.clk_freq/(10**9) + period = 1/freq_in_ghz + num_loops = int(ns_time/period) + for i in range(num_loops+1): + yield + + def gen_simulation(self, selfp): + baud_in_ghz = self.baud/(10**9) + uart_period = int(1/baud_in_ghz) + half_uart_period = int(1/(2*baud_in_ghz)) + + # Set TX an RX lines idle + selfp.pads.tx = 1 + selfp.pads.rx = 1 + yield + + # First send a few characters + + tx_string = "01234" + print("Sending string: " + tx_string) + for c in tx_string: + selfp.slave._r_rxtx.r = ord(c) + selfp.slave._r_rxtx.re = 1 + yield + selfp.slave._r_rxtx.re = 0 + + yield from self.wait_for(half_uart_period) + + if selfp.pads.tx: + print("FAILURE: no start bit sent") + + val = 0 + for i in range(8): + yield from self.wait_for(uart_period) + val >>= 1 + if selfp.pads.tx: + val |= 0x80 + + yield from self.wait_for(uart_period) + + if selfp.pads.tx == 0: + print("FAILURE: no stop bit sent") + + if ord(c) != val: + print("FAILURE: sent decimal value "+str(val)+" (char "+chr(val)+") instead of "+c) + else: + print("SUCCESS: sent "+c) + while selfp.slave.ev.tx.trigger != 1: + yield + + # Then receive a character + + rx_string = '5' + print("Receiving character "+rx_string) + rx_value = ord(rx_string) + for i in range(11): + if (i == 0): + # start bit + selfp.pads.rx = 0 + elif (i == 9): + # stop bit + selfp.pads.rx = 1 + elif (i == 10): + selfp.pads.rx = 1 + break + else: + selfp.pads.rx = 1 if (rx_value & 1) else 0 + rx_value >>= 1 + yield from self.wait_for(uart_period) + + rx_value = ord(rx_string) + received_value = selfp.slave._r_rxtx.w + if (received_value == rx_value): + print("RX SUCCESS: ") + else: + print("RX FAILURE: ") + + print("received "+chr(received_value)) + + while True: + yield if __name__ == "__main__": - from migen.sim.generic import Simulator, TopLevel - from migen.sim import icarus - with Simulator(UARTTB(), TopLevel("top.vcd", clk_period=int(1/0.08333333)), icarus.Runner(keep_files=False)) as s: - s.run(20000) + from migen.sim.generic import Simulator, TopLevel + from migen.sim import icarus + with Simulator(UARTTB(), TopLevel("top.vcd", clk_period=int(1/0.08333333)), icarus.Runner(keep_files=False)) as s: + s.run(20000) diff --git a/misoclib/cpu/lm32/__init__.py b/misoclib/cpu/lm32/__init__.py index ac6b3764..9f60d8e2 100644 --- a/misoclib/cpu/lm32/__init__.py +++ b/misoclib/cpu/lm32/__init__.py @@ -4,59 +4,59 @@ from migen.fhdl.std import * from migen.bus import wishbone class LM32(Module): - def __init__(self, platform, eba_reset): - self.ibus = i = wishbone.Interface() - self.dbus = d = wishbone.Interface() - self.interrupt = Signal(32) - - ### - - i_adr_o = Signal(32) - d_adr_o = Signal(32) - self.specials += Instance("lm32_cpu", - p_eba_reset=Instance.PreformattedParam("32'h{:08x}".format(eba_reset)), - - i_clk_i=ClockSignal(), - i_rst_i=ResetSignal(), - - i_interrupt=self.interrupt, - - o_I_ADR_O=i_adr_o, - o_I_DAT_O=i.dat_w, - o_I_SEL_O=i.sel, - o_I_CYC_O=i.cyc, - o_I_STB_O=i.stb, - o_I_WE_O=i.we, - o_I_CTI_O=i.cti, - o_I_BTE_O=i.bte, - i_I_DAT_I=i.dat_r, - i_I_ACK_I=i.ack, - i_I_ERR_I=i.err, - i_I_RTY_I=0, - - o_D_ADR_O=d_adr_o, - o_D_DAT_O=d.dat_w, - o_D_SEL_O=d.sel, - o_D_CYC_O=d.cyc, - o_D_STB_O=d.stb, - o_D_WE_O=d.we, - o_D_CTI_O=d.cti, - o_D_BTE_O=d.bte, - i_D_DAT_I=d.dat_r, - i_D_ACK_I=d.ack, - i_D_ERR_I=d.err, - i_D_RTY_I=0) - - self.comb += [ - self.ibus.adr.eq(i_adr_o[2:]), - self.dbus.adr.eq(d_adr_o[2:]) - ] - - # add Verilog sources - platform.add_sources(os.path.join("extcores", "lm32", "submodule", "rtl"), - "lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v", - "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v", - "lm32_shifter.v", "lm32_multiplier.v", "lm32_mc_arithmetic.v", - "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v", - "lm32_dcache.v", "lm32_debug.v", "lm32_itlb.v", "lm32_dtlb.v") - platform.add_verilog_include_path(os.path.join("extcores", "lm32")) \ No newline at end of file + def __init__(self, platform, eba_reset): + self.ibus = i = wishbone.Interface() + self.dbus = d = wishbone.Interface() + self.interrupt = Signal(32) + + ### + + i_adr_o = Signal(32) + d_adr_o = Signal(32) + self.specials += Instance("lm32_cpu", + p_eba_reset=Instance.PreformattedParam("32'h{:08x}".format(eba_reset)), + + i_clk_i=ClockSignal(), + i_rst_i=ResetSignal(), + + i_interrupt=self.interrupt, + + o_I_ADR_O=i_adr_o, + o_I_DAT_O=i.dat_w, + o_I_SEL_O=i.sel, + o_I_CYC_O=i.cyc, + o_I_STB_O=i.stb, + o_I_WE_O=i.we, + o_I_CTI_O=i.cti, + o_I_BTE_O=i.bte, + i_I_DAT_I=i.dat_r, + i_I_ACK_I=i.ack, + i_I_ERR_I=i.err, + i_I_RTY_I=0, + + o_D_ADR_O=d_adr_o, + o_D_DAT_O=d.dat_w, + o_D_SEL_O=d.sel, + o_D_CYC_O=d.cyc, + o_D_STB_O=d.stb, + o_D_WE_O=d.we, + o_D_CTI_O=d.cti, + o_D_BTE_O=d.bte, + i_D_DAT_I=d.dat_r, + i_D_ACK_I=d.ack, + i_D_ERR_I=d.err, + i_D_RTY_I=0) + + self.comb += [ + self.ibus.adr.eq(i_adr_o[2:]), + self.dbus.adr.eq(d_adr_o[2:]) + ] + + # add Verilog sources + platform.add_sources(os.path.join("extcores", "lm32", "submodule", "rtl"), + "lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v", + "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v", + "lm32_shifter.v", "lm32_multiplier.v", "lm32_mc_arithmetic.v", + "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v", + "lm32_dcache.v", "lm32_debug.v", "lm32_itlb.v", "lm32_dtlb.v") + platform.add_verilog_include_path(os.path.join("extcores", "lm32")) \ No newline at end of file diff --git a/misoclib/cpu/mor1kx/__init__.py b/misoclib/cpu/mor1kx/__init__.py index bc7ef281..d45ca413 100644 --- a/misoclib/cpu/mor1kx/__init__.py +++ b/misoclib/cpu/mor1kx/__init__.py @@ -4,75 +4,75 @@ from migen.fhdl.std import * from migen.bus import wishbone class MOR1KX(Module): - def __init__(self, platform, reset_pc): - self.ibus = i = wishbone.Interface() - self.dbus = d = wishbone.Interface() - self.interrupt = Signal(32) + def __init__(self, platform, reset_pc): + self.ibus = i = wishbone.Interface() + self.dbus = d = wishbone.Interface() + self.interrupt = Signal(32) - ### + ### - i_adr_o = Signal(32) - d_adr_o = Signal(32) - self.specials += Instance("mor1kx", - p_FEATURE_INSTRUCTIONCACHE="ENABLED", - p_OPTION_ICACHE_BLOCK_WIDTH=4, - p_OPTION_ICACHE_SET_WIDTH=8, - p_OPTION_ICACHE_WAYS=1, - p_OPTION_ICACHE_LIMIT_WIDTH=31, - p_FEATURE_DATACACHE="ENABLED", - p_OPTION_DCACHE_BLOCK_WIDTH=4, - p_OPTION_DCACHE_SET_WIDTH=8, - p_OPTION_DCACHE_WAYS=1, - p_OPTION_DCACHE_LIMIT_WIDTH=31, - p_FEATURE_TIMER="NONE", - p_OPTION_PIC_TRIGGER="LEVEL", - p_FEATURE_SYSCALL="NONE", - p_FEATURE_TRAP="NONE", - p_FEATURE_RANGE="NONE", - p_FEATURE_OVERFLOW="NONE", - p_FEATURE_ADDC="NONE", - p_FEATURE_CMOV="NONE", - p_FEATURE_FFL1="NONE", - p_OPTION_CPU0="CAPPUCCINO", - p_OPTION_RESET_PC=reset_pc, - p_IBUS_WB_TYPE="B3_REGISTERED_FEEDBACK", - p_DBUS_WB_TYPE="B3_REGISTERED_FEEDBACK", + i_adr_o = Signal(32) + d_adr_o = Signal(32) + self.specials += Instance("mor1kx", + p_FEATURE_INSTRUCTIONCACHE="ENABLED", + p_OPTION_ICACHE_BLOCK_WIDTH=4, + p_OPTION_ICACHE_SET_WIDTH=8, + p_OPTION_ICACHE_WAYS=1, + p_OPTION_ICACHE_LIMIT_WIDTH=31, + p_FEATURE_DATACACHE="ENABLED", + p_OPTION_DCACHE_BLOCK_WIDTH=4, + p_OPTION_DCACHE_SET_WIDTH=8, + p_OPTION_DCACHE_WAYS=1, + p_OPTION_DCACHE_LIMIT_WIDTH=31, + p_FEATURE_TIMER="NONE", + p_OPTION_PIC_TRIGGER="LEVEL", + p_FEATURE_SYSCALL="NONE", + p_FEATURE_TRAP="NONE", + p_FEATURE_RANGE="NONE", + p_FEATURE_OVERFLOW="NONE", + p_FEATURE_ADDC="NONE", + p_FEATURE_CMOV="NONE", + p_FEATURE_FFL1="NONE", + p_OPTION_CPU0="CAPPUCCINO", + p_OPTION_RESET_PC=reset_pc, + p_IBUS_WB_TYPE="B3_REGISTERED_FEEDBACK", + p_DBUS_WB_TYPE="B3_REGISTERED_FEEDBACK", - i_clk=ClockSignal(), - i_rst=ResetSignal(), + i_clk=ClockSignal(), + i_rst=ResetSignal(), - i_irq_i=self.interrupt, + i_irq_i=self.interrupt, - o_iwbm_adr_o=i_adr_o, - o_iwbm_dat_o=i.dat_w, - o_iwbm_sel_o=i.sel, - o_iwbm_cyc_o=i.cyc, - o_iwbm_stb_o=i.stb, - o_iwbm_we_o=i.we, - o_iwbm_cti_o=i.cti, - o_iwbm_bte_o=i.bte, - i_iwbm_dat_i=i.dat_r, - i_iwbm_ack_i=i.ack, - i_iwbm_err_i=i.err, - i_iwbm_rty_i=0, + o_iwbm_adr_o=i_adr_o, + o_iwbm_dat_o=i.dat_w, + o_iwbm_sel_o=i.sel, + o_iwbm_cyc_o=i.cyc, + o_iwbm_stb_o=i.stb, + o_iwbm_we_o=i.we, + o_iwbm_cti_o=i.cti, + o_iwbm_bte_o=i.bte, + i_iwbm_dat_i=i.dat_r, + i_iwbm_ack_i=i.ack, + i_iwbm_err_i=i.err, + i_iwbm_rty_i=0, - o_dwbm_adr_o=d_adr_o, - o_dwbm_dat_o=d.dat_w, - o_dwbm_sel_o=d.sel, - o_dwbm_cyc_o=d.cyc, - o_dwbm_stb_o=d.stb, - o_dwbm_we_o=d.we, - o_dwbm_cti_o=d.cti, - o_dwbm_bte_o=d.bte, - i_dwbm_dat_i=d.dat_r, - i_dwbm_ack_i=d.ack, - i_dwbm_err_i=d.err, - i_dwbm_rty_i=0) + o_dwbm_adr_o=d_adr_o, + o_dwbm_dat_o=d.dat_w, + o_dwbm_sel_o=d.sel, + o_dwbm_cyc_o=d.cyc, + o_dwbm_stb_o=d.stb, + o_dwbm_we_o=d.we, + o_dwbm_cti_o=d.cti, + o_dwbm_bte_o=d.bte, + i_dwbm_dat_i=d.dat_r, + i_dwbm_ack_i=d.ack, + i_dwbm_err_i=d.err, + i_dwbm_rty_i=0) - self.comb += [ - self.ibus.adr.eq(i_adr_o[2:]), - self.dbus.adr.eq(d_adr_o[2:]) - ] + self.comb += [ + self.ibus.adr.eq(i_adr_o[2:]), + self.dbus.adr.eq(d_adr_o[2:]) + ] - # add Verilog sources - platform.add_source_dir(os.path.join("extcores", "mor1kx", "submodule", "rtl", "verilog")) + # add Verilog sources + platform.add_source_dir(os.path.join("extcores", "mor1kx", "submodule", "rtl", "verilog")) diff --git a/misoclib/cpu/peripherals/identifier/__init__.py b/misoclib/cpu/peripherals/identifier/__init__.py index 1f7a65a7..8153f610 100644 --- a/misoclib/cpu/peripherals/identifier/__init__.py +++ b/misoclib/cpu/peripherals/identifier/__init__.py @@ -4,18 +4,18 @@ from migen.bank.description import * from misoclib.cpu.peripherals.identifier import git class Identifier(Module, AutoCSR): - def __init__(self, sysid, frequency, revision=None): - self._sysid = CSRStatus(16) - self._revision = CSRStatus(32) - self._frequency = CSRStatus(32) + def __init__(self, sysid, frequency, revision=None): + self._sysid = CSRStatus(16) + self._revision = CSRStatus(32) + self._frequency = CSRStatus(32) - ### + ### - if revision is None: - revision = git.get_id() + if revision is None: + revision = git.get_id() - self.comb += [ - self._sysid.status.eq(sysid), - self._revision.status.eq(revision), - self._frequency.status.eq(frequency) - ] + self.comb += [ + self._sysid.status.eq(sysid), + self._revision.status.eq(revision), + self._frequency.status.eq(frequency) + ] diff --git a/misoclib/cpu/peripherals/identifier/git.py b/misoclib/cpu/peripherals/identifier/git.py index 19b902bd..4a90fffc 100644 --- a/misoclib/cpu/peripherals/identifier/git.py +++ b/misoclib/cpu/peripherals/identifier/git.py @@ -1,5 +1,5 @@ import subprocess def get_id(): - output = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii") - return int(output[:8], 16) + output = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii") + return int(output[:8], 16) diff --git a/misoclib/cpu/peripherals/timer/__init__.py b/misoclib/cpu/peripherals/timer/__init__.py index 2ab77ead..c8ff24a0 100644 --- a/misoclib/cpu/peripherals/timer/__init__.py +++ b/misoclib/cpu/peripherals/timer/__init__.py @@ -3,31 +3,31 @@ from migen.bank.description import * from migen.bank.eventmanager import * class Timer(Module, AutoCSR): - def __init__(self, width=32): - self._load = CSRStorage(width) - self._reload = CSRStorage(width) - self._en = CSRStorage() - self._update_value = CSR() - self._value = CSRStatus(width) + def __init__(self, width=32): + self._load = CSRStorage(width) + self._reload = CSRStorage(width) + self._en = CSRStorage() + self._update_value = CSR() + self._value = CSRStatus(width) - self.submodules.ev = EventManager() - self.ev.zero = EventSourceProcess() - self.ev.finalize() + self.submodules.ev = EventManager() + self.ev.zero = EventSourceProcess() + self.ev.finalize() - ### + ### - value = Signal(width) - self.sync += [ - If(self._en.storage, - If(value == 0, - # set reload to 0 to disable reloading - value.eq(self._reload.storage) - ).Else( - value.eq(value - 1) - ) - ).Else( - value.eq(self._load.storage) - ), - If(self._update_value.re, self._value.status.eq(value)) - ] - self.comb += self.ev.zero.trigger.eq(value != 0) + value = Signal(width) + self.sync += [ + If(self._en.storage, + If(value == 0, + # set reload to 0 to disable reloading + value.eq(self._reload.storage) + ).Else( + value.eq(value - 1) + ) + ).Else( + value.eq(self._load.storage) + ), + If(self._update_value.re, self._value.status.eq(value)) + ] + self.comb += self.ev.zero.trigger.eq(value != 0) diff --git a/misoclib/mem/flash/norflash16/__init__.py b/misoclib/mem/flash/norflash16/__init__.py index 12ae1e71..226196cf 100644 --- a/misoclib/mem/flash/norflash16/__init__.py +++ b/misoclib/mem/flash/norflash16/__init__.py @@ -3,100 +3,100 @@ from migen.bus import wishbone from migen.genlib.fsm import FSM, NextState class NorFlash16(Module): - def __init__(self, pads, rd_timing, wr_timing): - self.bus = wishbone.Interface() + def __init__(self, pads, rd_timing, wr_timing): + self.bus = wishbone.Interface() - ### + ### - data = TSTriple(16) - lsb = Signal() + data = TSTriple(16) + lsb = Signal() - self.specials += data.get_tristate(pads.d) - self.comb += [ - data.oe.eq(pads.oe_n), - pads.ce_n.eq(0) - ] + self.specials += data.get_tristate(pads.d) + self.comb += [ + data.oe.eq(pads.oe_n), + pads.ce_n.eq(0) + ] - load_lo = Signal() - load_hi = Signal() - store = Signal() + load_lo = Signal() + load_hi = Signal() + store = Signal() - pads.oe_n.reset, pads.we_n.reset = 1, 1 - self.sync += [ - pads.oe_n.eq(1), - pads.we_n.eq(1), + pads.oe_n.reset, pads.we_n.reset = 1, 1 + self.sync += [ + pads.oe_n.eq(1), + pads.we_n.eq(1), - # Register data/address to avoid off-chip glitches - If(self.bus.cyc & self.bus.stb, - pads.adr.eq(Cat(lsb, self.bus.adr)), - If(self.bus.we, - # Only 16-bit writes are supported. Assume sel=0011 or 1100. - If(self.bus.sel[0], - data.o.eq(self.bus.dat_w[:16]) - ).Else( - data.o.eq(self.bus.dat_w[16:]) - ) - ).Else( - pads.oe_n.eq(0) - ) - ), + # Register data/address to avoid off-chip glitches + If(self.bus.cyc & self.bus.stb, + pads.adr.eq(Cat(lsb, self.bus.adr)), + If(self.bus.we, + # Only 16-bit writes are supported. Assume sel=0011 or 1100. + If(self.bus.sel[0], + data.o.eq(self.bus.dat_w[:16]) + ).Else( + data.o.eq(self.bus.dat_w[16:]) + ) + ).Else( + pads.oe_n.eq(0) + ) + ), - If(load_lo, self.bus.dat_r[:16].eq(data.i)), - If(load_hi, self.bus.dat_r[16:].eq(data.i)), - If(store, pads.we_n.eq(0)) - ] + If(load_lo, self.bus.dat_r[:16].eq(data.i)), + If(load_hi, self.bus.dat_r[16:].eq(data.i)), + If(store, pads.we_n.eq(0)) + ] - # Typical timing of the flash chips: - # - 110ns address to output - # - 50ns write pulse width - counter = Signal(max=max(rd_timing, wr_timing)+1) - counter_en = Signal() - counter_wr_mode = Signal() - counter_done = Signal() - self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing)) - self.sync += If(counter_en & ~counter_done, - counter.eq(counter + 1) - ).Else( - counter.eq(0) - ) + # Typical timing of the flash chips: + # - 110ns address to output + # - 50ns write pulse width + counter = Signal(max=max(rd_timing, wr_timing)+1) + counter_en = Signal() + counter_wr_mode = Signal() + counter_done = Signal() + self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing)) + self.sync += If(counter_en & ~counter_done, + counter.eq(counter + 1) + ).Else( + counter.eq(0) + ) - fsm = FSM() - self.submodules += fsm + fsm = FSM() + self.submodules += fsm - fsm.act("IDLE", - If(self.bus.cyc & self.bus.stb, - If(self.bus.we, - NextState("WR") - ).Else( - NextState("RD_HI") - ) - ) - ) - fsm.act("RD_HI", - lsb.eq(0), - counter_en.eq(1), - If(counter_done, - load_hi.eq(1), - NextState("RD_LO") - ) - ) - fsm.act("RD_LO", - lsb.eq(1), - counter_en.eq(1), - If(counter_done, - load_lo.eq(1), - NextState("ACK") - ) - ) - fsm.act("WR", - # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0] - lsb.eq(self.bus.sel[0]), - counter_wr_mode.eq(1), - counter_en.eq(1), - store.eq(1), - If(counter_done, NextState("ACK")) - ) - fsm.act("ACK", - self.bus.ack.eq(1), - NextState("IDLE") - ) + fsm.act("IDLE", + If(self.bus.cyc & self.bus.stb, + If(self.bus.we, + NextState("WR") + ).Else( + NextState("RD_HI") + ) + ) + ) + fsm.act("RD_HI", + lsb.eq(0), + counter_en.eq(1), + If(counter_done, + load_hi.eq(1), + NextState("RD_LO") + ) + ) + fsm.act("RD_LO", + lsb.eq(1), + counter_en.eq(1), + If(counter_done, + load_lo.eq(1), + NextState("ACK") + ) + ) + fsm.act("WR", + # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0] + lsb.eq(self.bus.sel[0]), + counter_wr_mode.eq(1), + counter_en.eq(1), + store.eq(1), + If(counter_done, NextState("ACK")) + ) + fsm.act("ACK", + self.bus.ack.eq(1), + NextState("IDLE") + ) diff --git a/misoclib/mem/flash/spiflash/__init__.py b/misoclib/mem/flash/spiflash/__init__.py index 0d8cc890..4edd2535 100644 --- a/misoclib/mem/flash/spiflash/__init__.py +++ b/misoclib/mem/flash/spiflash/__init__.py @@ -10,169 +10,169 @@ _DIOFR = 0xbb _QIOFR = 0xeb def _format_cmd(cmd, spi_width): - """ - `cmd` is the read instruction. Since everything is transmitted on all - dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq - width even if dq1-dq3 are don't care during the command phase: - For example, for N25Q128, 0xeb is the quad i/o fast read, and - extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff - """ - c = 2**(8*spi_width)-1 - for b in range(8): - if not (cmd>>b)%2: - c &= ~(1<<(b*spi_width)) - return c + """ + `cmd` is the read instruction. Since everything is transmitted on all + dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq + width even if dq1-dq3 are don't care during the command phase: + For example, for N25Q128, 0xeb is the quad i/o fast read, and + extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff + """ + c = 2**(8*spi_width)-1 + for b in range(8): + if not (cmd>>b)%2: + c &= ~(1<<(b*spi_width)) + return c class SpiFlash(Module, AutoCSR): - def __init__(self, pads, dummy=15, div=2, with_bitbang=True): - """ - Simple SPI flash, e.g. N25Q128 on the LX9 Microboard. - - Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast - Read). Only supports mode0 (cpol=0, cpha=0). - Optionally supports software bitbanging (for write, erase, or other commands). - """ - self.bus = bus = wishbone.Interface() - spi_width = flen(pads.dq) - if with_bitbang: - self.bitbang = CSRStorage(4) - self.miso = CSRStatus() - self.bitbang_en = CSRStorage() - - ### - - cs_n = Signal(reset=1) - clk = Signal() - dq_oe = Signal() - wbone_width = flen(bus.dat_r) - - - read_cmd_params = { - 4: (_format_cmd(_QIOFR, 4), 4*8), - 2: (_format_cmd(_DIOFR, 2), 2*8), - 1: (_format_cmd(_FAST_READ, 1), 1*8) - } - read_cmd, cmd_width = read_cmd_params[spi_width] - addr_width = 24 - - pads.cs_n.reset = 1 - - dq = TSTriple(spi_width) - self.specials.dq = dq.get_tristate(pads.dq) - - sr = Signal(max(cmd_width, addr_width, wbone_width)) - dqs = Replicate(1, spi_width-1) - - self.comb += bus.dat_r.eq(sr) - - hw_read_logic = [ - pads.clk.eq(clk), - pads.cs_n.eq(cs_n), - dq.o.eq(sr[-spi_width:]), - dq.oe.eq(dq_oe) - ] - - if with_bitbang: - bitbang_logic = [ - pads.clk.eq(self.bitbang.storage[1]), - pads.cs_n.eq(self.bitbang.storage[2]), - dq.o.eq(Cat(self.bitbang.storage[0], dqs)), - If(self.bitbang.storage[3], - dq.oe.eq(0) - ).Else( - dq.oe.eq(1) - ), - If(self.bitbang.storage[1], - self.miso.status.eq(dq.i[-1]) - ) - ] - - self.comb += \ - If(self.bitbang_en.storage, - bitbang_logic - ).Else( - hw_read_logic - ) - else: - self.comb += hw_read_logic - - if div < 2: - raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) - else: - i = Signal(max=div) - dqi = Signal(spi_width) - self.sync += [ - If(i == div//2 - 1, - clk.eq(1), - dqi.eq(dq.i), - ), - If(i == div - 1, - i.eq(0), - clk.eq(0), - sr.eq(Cat(dqi, sr[:-spi_width])) - ).Else( - i.eq(i + 1), - ), - ] - - # spi is byte-addressed, prefix by zeros - z = Replicate(0, log2_int(wbone_width//8)) - - seq = [ - (cmd_width//spi_width*div, - [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), - (addr_width//spi_width*div, - [sr[-addr_width:].eq(Cat(z, bus.adr))]), - ((dummy + wbone_width//spi_width)*div, - [dq_oe.eq(0)]), - (1, - [bus.ack.eq(1), cs_n.eq(1)]), - (div, # tSHSL! - [bus.ack.eq(0)]), - (0, - []), - ] - - # accumulate timeline deltas - t, tseq = 0, [] - for dt, a in seq: - tseq.append((t, a)) - t += dt - - self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) + def __init__(self, pads, dummy=15, div=2, with_bitbang=True): + """ + Simple SPI flash, e.g. N25Q128 on the LX9 Microboard. + + Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast + Read). Only supports mode0 (cpol=0, cpha=0). + Optionally supports software bitbanging (for write, erase, or other commands). + """ + self.bus = bus = wishbone.Interface() + spi_width = flen(pads.dq) + if with_bitbang: + self.bitbang = CSRStorage(4) + self.miso = CSRStatus() + self.bitbang_en = CSRStorage() + + ### + + cs_n = Signal(reset=1) + clk = Signal() + dq_oe = Signal() + wbone_width = flen(bus.dat_r) + + + read_cmd_params = { + 4: (_format_cmd(_QIOFR, 4), 4*8), + 2: (_format_cmd(_DIOFR, 2), 2*8), + 1: (_format_cmd(_FAST_READ, 1), 1*8) + } + read_cmd, cmd_width = read_cmd_params[spi_width] + addr_width = 24 + + pads.cs_n.reset = 1 + + dq = TSTriple(spi_width) + self.specials.dq = dq.get_tristate(pads.dq) + + sr = Signal(max(cmd_width, addr_width, wbone_width)) + dqs = Replicate(1, spi_width-1) + + self.comb += bus.dat_r.eq(sr) + + hw_read_logic = [ + pads.clk.eq(clk), + pads.cs_n.eq(cs_n), + dq.o.eq(sr[-spi_width:]), + dq.oe.eq(dq_oe) + ] + + if with_bitbang: + bitbang_logic = [ + pads.clk.eq(self.bitbang.storage[1]), + pads.cs_n.eq(self.bitbang.storage[2]), + dq.o.eq(Cat(self.bitbang.storage[0], dqs)), + If(self.bitbang.storage[3], + dq.oe.eq(0) + ).Else( + dq.oe.eq(1) + ), + If(self.bitbang.storage[1], + self.miso.status.eq(dq.i[-1]) + ) + ] + + self.comb += \ + If(self.bitbang_en.storage, + bitbang_logic + ).Else( + hw_read_logic + ) + else: + self.comb += hw_read_logic + + if div < 2: + raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) + else: + i = Signal(max=div) + dqi = Signal(spi_width) + self.sync += [ + If(i == div//2 - 1, + clk.eq(1), + dqi.eq(dq.i), + ), + If(i == div - 1, + i.eq(0), + clk.eq(0), + sr.eq(Cat(dqi, sr[:-spi_width])) + ).Else( + i.eq(i + 1), + ), + ] + + # spi is byte-addressed, prefix by zeros + z = Replicate(0, log2_int(wbone_width//8)) + + seq = [ + (cmd_width//spi_width*div, + [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), + (addr_width//spi_width*div, + [sr[-addr_width:].eq(Cat(z, bus.adr))]), + ((dummy + wbone_width//spi_width)*div, + [dq_oe.eq(0)]), + (1, + [bus.ack.eq(1), cs_n.eq(1)]), + (div, # tSHSL! + [bus.ack.eq(0)]), + (0, + []), + ] + + # accumulate timeline deltas + t, tseq = 0, [] + for dt, a in seq: + tseq.append((t, a)) + t += dt + + self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) class SpiFlashTB(Module): - def __init__(self): - self.submodules.master = wishbone.Initiator(self.gen_reads()) - self.pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)]) - self.submodules.slave = SpiFlash(self.pads) - self.submodules.tap = wishbone.Tap(self.slave.bus) - self.submodules.intercon = wishbone.InterconnectPointToPoint( - self.master.bus, self.slave.bus) - self.cycle = 0 - - def gen_reads(self): - for a in range(10): - t = TRead(a) - yield t - print("read {} in {} cycles(s)".format(t.data, t.latency)) - - def do_simulation(self, selfp): - if selfp.pads.cs_n: - self.cycle = 0 - else: - self.cycle += 1 - if not selfp.slave.dq.oe: - selfp.slave.dq.i = self.cycle & 0xf - do_simulation.passive = True + def __init__(self): + self.submodules.master = wishbone.Initiator(self.gen_reads()) + self.pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)]) + self.submodules.slave = SpiFlash(self.pads) + self.submodules.tap = wishbone.Tap(self.slave.bus) + self.submodules.intercon = wishbone.InterconnectPointToPoint( + self.master.bus, self.slave.bus) + self.cycle = 0 + + def gen_reads(self): + for a in range(10): + t = TRead(a) + yield t + print("read {} in {} cycles(s)".format(t.data, t.latency)) + + def do_simulation(self, selfp): + if selfp.pads.cs_n: + self.cycle = 0 + else: + self.cycle += 1 + if not selfp.slave.dq.oe: + selfp.slave.dq.i = self.cycle & 0xf + do_simulation.passive = True if __name__ == "__main__": - from migen.sim.generic import run_simulation - from migen.fhdl import verilog + from migen.sim.generic import run_simulation + from migen.fhdl import verilog - pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)]) - s = SpiFlash(pads) - print(verilog.convert(s, ios={pads.clk, pads.cs_n, pads.dq, s.bus.adr, - s.bus.dat_r, s.bus.cyc, s.bus.ack, s.bus.stb})) + pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)]) + s = SpiFlash(pads) + print(verilog.convert(s, ios={pads.clk, pads.cs_n, pads.dq, s.bus.adr, + s.bus.dat_r, s.bus.cyc, s.bus.ack, s.bus.stb})) - run_simulation(SpiFlashTB(), vcd_name="spiflash.vcd") + run_simulation(SpiFlashTB(), vcd_name="spiflash.vcd") diff --git a/misoclib/mem/sdram/__init__.py b/misoclib/mem/sdram/__init__.py index c80205a6..b327bb08 100644 --- a/misoclib/mem/sdram/__init__.py +++ b/misoclib/mem/sdram/__init__.py @@ -2,10 +2,10 @@ from collections import namedtuple PhySettingsT = namedtuple("PhySettings", "memtype dfi_databits nphases rdphase wrphase rdcmdphase wrcmdphase cl cwl read_latency write_latency") def PhySettings(memtype, dfi_databits, nphases, rdphase, wrphase, rdcmdphase, wrcmdphase, cl, read_latency, write_latency, cwl=0): - return PhySettingsT(memtype, dfi_databits, nphases, rdphase, wrphase, rdcmdphase, wrcmdphase, cl, cwl, read_latency, write_latency) + return PhySettingsT(memtype, dfi_databits, nphases, rdphase, wrphase, rdcmdphase, wrcmdphase, cl, cwl, read_latency, write_latency) GeomSettingsT = namedtuple("_GeomSettings", "bankbits rowbits colbits addressbits") def GeomSettings(bankbits, rowbits, colbits): - return GeomSettingsT(bankbits, rowbits, colbits, max(rowbits, colbits)) + return GeomSettingsT(bankbits, rowbits, colbits, max(rowbits, colbits)) TimingSettings = namedtuple("TimingSettings", "tRP tRCD tWR tWTR tREFI tRFC") diff --git a/misoclib/mem/sdram/core/__init__.py b/misoclib/mem/sdram/core/__init__.py index 7af08c1d..65a433d7 100644 --- a/misoclib/mem/sdram/core/__init__.py +++ b/misoclib/mem/sdram/core/__init__.py @@ -7,23 +7,23 @@ from misoclib.mem.sdram.core import minicon, lasmicon from misoclib.mem.sdram.core import lasmixbar class SDRAMCore(Module, AutoCSR): - def __init__(self, phy, geom_settings, timing_settings, controller_settings, **kwargs): - # DFI - self.submodules.dfii = dfii.DFIInjector(geom_settings.addressbits, geom_settings.bankbits, - phy.settings.dfi_databits, phy.settings.nphases) - self.comb += Record.connect(self.dfii.master, phy.dfi) + def __init__(self, phy, geom_settings, timing_settings, controller_settings, **kwargs): + # DFI + self.submodules.dfii = dfii.DFIInjector(geom_settings.addressbits, geom_settings.bankbits, + phy.settings.dfi_databits, phy.settings.nphases) + self.comb += Record.connect(self.dfii.master, phy.dfi) - # LASMICON - if isinstance(controller_settings, lasmicon.LASMIconSettings): - self.submodules.controller = controller = lasmicon.LASMIcon(phy.settings, geom_settings, timing_settings, - controller_settings, **kwargs) - self.comb += Record.connect(controller.dfi, self.dfii.slave) + # LASMICON + if isinstance(controller_settings, lasmicon.LASMIconSettings): + self.submodules.controller = controller = lasmicon.LASMIcon(phy.settings, geom_settings, timing_settings, + controller_settings, **kwargs) + self.comb += Record.connect(controller.dfi, self.dfii.slave) - self.submodules.crossbar = lasmixbar.LASMIxbar([controller.lasmic], controller.nrowbits) + self.submodules.crossbar = lasmixbar.LASMIxbar([controller.lasmic], controller.nrowbits) - # MINICON - elif isinstance(controller_settings, minicon.MiniconSettings): - self.submodules.controller = controller = minicon.Minicon(phy.settings, geom_settings, timing_settings) - self.comb += Record.connect(controller.dfi, self.dfii.slave) - else: - raise ValueError("Unsupported SDRAM controller type") + # MINICON + elif isinstance(controller_settings, minicon.MiniconSettings): + self.submodules.controller = controller = minicon.Minicon(phy.settings, geom_settings, timing_settings) + self.comb += Record.connect(controller.dfi, self.dfii.slave) + else: + raise ValueError("Unsupported SDRAM controller type") diff --git a/misoclib/mem/sdram/core/lasmibus.py b/misoclib/mem/sdram/core/lasmibus.py index 7578d0ec..2585ace4 100644 --- a/misoclib/mem/sdram/core/lasmibus.py +++ b/misoclib/mem/sdram/core/lasmibus.py @@ -5,155 +5,155 @@ from migen.genlib.record import * from migen.genlib.misc import optree class Interface(Record): - def __init__(self, aw, dw, nbanks, req_queue_size, read_latency, write_latency): - self.aw = aw - self.dw = dw - self.nbanks = nbanks - self.req_queue_size = req_queue_size - self.read_latency = read_latency - self.write_latency = write_latency - - bank_layout = [ - ("adr", aw, DIR_M_TO_S), - ("we", 1, DIR_M_TO_S), - ("stb", 1, DIR_M_TO_S), - ("req_ack", 1, DIR_S_TO_M), - ("dat_w_ack", 1, DIR_S_TO_M), - ("dat_r_ack", 1, DIR_S_TO_M), - ("lock", 1, DIR_S_TO_M) - ] - if nbanks > 1: - layout = [("bank"+str(i), bank_layout) for i in range(nbanks)] - else: - layout = bank_layout - layout += [ - ("dat_w", dw, DIR_M_TO_S), - ("dat_we", dw//8, DIR_M_TO_S), - ("dat_r", dw, DIR_S_TO_M) - ] - Record.__init__(self, layout) + def __init__(self, aw, dw, nbanks, req_queue_size, read_latency, write_latency): + self.aw = aw + self.dw = dw + self.nbanks = nbanks + self.req_queue_size = req_queue_size + self.read_latency = read_latency + self.write_latency = write_latency + + bank_layout = [ + ("adr", aw, DIR_M_TO_S), + ("we", 1, DIR_M_TO_S), + ("stb", 1, DIR_M_TO_S), + ("req_ack", 1, DIR_S_TO_M), + ("dat_w_ack", 1, DIR_S_TO_M), + ("dat_r_ack", 1, DIR_S_TO_M), + ("lock", 1, DIR_S_TO_M) + ] + if nbanks > 1: + layout = [("bank"+str(i), bank_layout) for i in range(nbanks)] + else: + layout = bank_layout + layout += [ + ("dat_w", dw, DIR_M_TO_S), + ("dat_we", dw//8, DIR_M_TO_S), + ("dat_r", dw, DIR_S_TO_M) + ] + Record.__init__(self, layout) class Initiator(Module): - def __init__(self, generator, bus): - self.generator = generator - self.bus = bus - self.transaction_start = 0 - self.transaction = None - self.transaction_end = None - - def do_simulation(self, selfp): - selfp.bus.dat_w = 0 - selfp.bus.dat_we = 0 - - if self.transaction is not None: - if selfp.bus.req_ack: - selfp.bus.stb = 0 - if selfp.bus.dat_ack: - if isinstance(self.transaction, TRead): - self.transaction_end = selfp.simulator.cycle_counter + self.bus.read_latency - else: - self.transaction_end = selfp.simulator.cycle_counter + self.bus.write_latency - 1 - - if self.transaction is None or selfp.simulator.cycle_counter == self.transaction_end: - if self.transaction is not None: - self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1 - if isinstance(self.transaction, TRead): - self.transaction.data = selfp.bus.dat_r - else: - selfp.bus.dat_w = self.transaction.data - selfp.bus.dat_we = self.transaction.sel - try: - self.transaction = next(self.generator) - except StopIteration: - raise StopSimulation - if self.transaction is not None: - self.transaction_start = selfp.simulator.cycle_counter - selfp.bus.stb = 1 - selfp.bus.adr = self.transaction.address - if isinstance(self.transaction, TRead): - selfp.bus.we = 0 - else: - selfp.bus.we = 1 + def __init__(self, generator, bus): + self.generator = generator + self.bus = bus + self.transaction_start = 0 + self.transaction = None + self.transaction_end = None + + def do_simulation(self, selfp): + selfp.bus.dat_w = 0 + selfp.bus.dat_we = 0 + + if self.transaction is not None: + if selfp.bus.req_ack: + selfp.bus.stb = 0 + if selfp.bus.dat_ack: + if isinstance(self.transaction, TRead): + self.transaction_end = selfp.simulator.cycle_counter + self.bus.read_latency + else: + self.transaction_end = selfp.simulator.cycle_counter + self.bus.write_latency - 1 + + if self.transaction is None or selfp.simulator.cycle_counter == self.transaction_end: + if self.transaction is not None: + self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1 + if isinstance(self.transaction, TRead): + self.transaction.data = selfp.bus.dat_r + else: + selfp.bus.dat_w = self.transaction.data + selfp.bus.dat_we = self.transaction.sel + try: + self.transaction = next(self.generator) + except StopIteration: + raise StopSimulation + if self.transaction is not None: + self.transaction_start = selfp.simulator.cycle_counter + selfp.bus.stb = 1 + selfp.bus.adr = self.transaction.address + if isinstance(self.transaction, TRead): + selfp.bus.we = 0 + else: + selfp.bus.we = 1 class TargetModel: - def __init__(self): - self.last_bank = 0 - - def read(self, bank, address): - return 0 - - def write(self, bank, address, data, we): - pass - - # Round-robin scheduling - def select_bank(self, pending_banks): - if not pending_banks: - return -1 - self.last_bank += 1 - if self.last_bank > max(pending_banks): - self.last_bank = 0 - while self.last_bank not in pending_banks: - self.last_bank += 1 - return self.last_bank + def __init__(self): + self.last_bank = 0 + + def read(self, bank, address): + return 0 + + def write(self, bank, address, data, we): + pass + + # Round-robin scheduling + def select_bank(self, pending_banks): + if not pending_banks: + return -1 + self.last_bank += 1 + if self.last_bank > max(pending_banks): + self.last_bank = 0 + while self.last_bank not in pending_banks: + self.last_bank += 1 + return self.last_bank class _ReqFIFO(Module): - def __init__(self, req_queue_size, bank): - self.req_queue_size = req_queue_size - self.bank = bank - self.contents = [] - - def do_simulation(self, selfp): - if len(self.contents) < self.req_queue_size: - if selfp.bank.stb: - self.contents.append((selfp.bank.we, selfp.bank.adr)) - selfp.bank.req_ack = 1 - else: - selfp.bank.req_ack = 0 - selfp.bank.lock = bool(self.contents) - do_simulation.passive = True + def __init__(self, req_queue_size, bank): + self.req_queue_size = req_queue_size + self.bank = bank + self.contents = [] + + def do_simulation(self, selfp): + if len(self.contents) < self.req_queue_size: + if selfp.bank.stb: + self.contents.append((selfp.bank.we, selfp.bank.adr)) + selfp.bank.req_ack = 1 + else: + selfp.bank.req_ack = 0 + selfp.bank.lock = bool(self.contents) + do_simulation.passive = True class Target(Module): - def __init__(self, model, *ifargs, **ifkwargs): - self.model = model - self.bus = Interface(*ifargs, **ifkwargs) - self.req_fifos = [_ReqFIFO(self.bus.req_queue_size, getattr(self.bus, "bank"+str(nb))) - for nb in range(self.bus.nbanks)] - self.submodules += self.req_fifos - self.rd_pipeline = [None]*self.bus.read_latency - self.wr_pipeline = [None]*(self.bus.write_latency + 1) - - def do_simulation(self, selfp): - # determine banks with pending requests - pending_banks = set(nb for nb, rf in enumerate(self.req_fifos) if rf.contents) - - # issue new transactions - selected_bank_n = self.model.select_bank(pending_banks) - selected_transaction = None - for nb in range(self.bus.nbanks): - bank = getattr(selfp.bus, "bank"+str(nb)) - if nb == selected_bank_n: - bank.dat_ack = 1 - selected_transaction = self.req_fifos[nb].contents.pop(0) - else: - bank.dat_ack = 0 - - rd_transaction = None - wr_transaction = None - if selected_bank_n >= 0: - we, adr = selected_transaction - if we: - wr_transaction = selected_bank_n, adr - else: - rd_transaction = selected_bank_n, adr - - # data pipeline - self.rd_pipeline.append(rd_transaction) - self.wr_pipeline.append(wr_transaction) - done_rd_transaction = self.rd_pipeline.pop(0) - done_wr_transaction = self.wr_pipeline.pop(0) - if done_rd_transaction is not None: - selfp.bus.dat_r = self.model.read(done_rd_transaction[0], done_rd_transaction[1]) - if done_wr_transaction is not None: - self.model.write(done_wr_transaction[0], done_wr_transaction[1], - selfp.bus.dat_w, selfp.bus.dat_we) - do_simulation.passive = True + def __init__(self, model, *ifargs, **ifkwargs): + self.model = model + self.bus = Interface(*ifargs, **ifkwargs) + self.req_fifos = [_ReqFIFO(self.bus.req_queue_size, getattr(self.bus, "bank"+str(nb))) + for nb in range(self.bus.nbanks)] + self.submodules += self.req_fifos + self.rd_pipeline = [None]*self.bus.read_latency + self.wr_pipeline = [None]*(self.bus.write_latency + 1) + + def do_simulation(self, selfp): + # determine banks with pending requests + pending_banks = set(nb for nb, rf in enumerate(self.req_fifos) if rf.contents) + + # issue new transactions + selected_bank_n = self.model.select_bank(pending_banks) + selected_transaction = None + for nb in range(self.bus.nbanks): + bank = getattr(selfp.bus, "bank"+str(nb)) + if nb == selected_bank_n: + bank.dat_ack = 1 + selected_transaction = self.req_fifos[nb].contents.pop(0) + else: + bank.dat_ack = 0 + + rd_transaction = None + wr_transaction = None + if selected_bank_n >= 0: + we, adr = selected_transaction + if we: + wr_transaction = selected_bank_n, adr + else: + rd_transaction = selected_bank_n, adr + + # data pipeline + self.rd_pipeline.append(rd_transaction) + self.wr_pipeline.append(wr_transaction) + done_rd_transaction = self.rd_pipeline.pop(0) + done_wr_transaction = self.wr_pipeline.pop(0) + if done_rd_transaction is not None: + selfp.bus.dat_r = self.model.read(done_rd_transaction[0], done_rd_transaction[1]) + if done_wr_transaction is not None: + self.model.write(done_wr_transaction[0], done_wr_transaction[1], + selfp.bus.dat_w, selfp.bus.dat_we) + do_simulation.passive = True diff --git a/misoclib/mem/sdram/core/lasmicon/__init__.py b/misoclib/mem/sdram/core/lasmicon/__init__.py index e61973ca..b3a37e25 100644 --- a/misoclib/mem/sdram/core/lasmicon/__init__.py +++ b/misoclib/mem/sdram/core/lasmicon/__init__.py @@ -7,55 +7,55 @@ from misoclib.mem.sdram.core.lasmicon.bankmachine import * from misoclib.mem.sdram.core.lasmicon.multiplexer import * class LASMIconSettings: - def __init__(self, req_queue_size=8, - read_time=32, write_time=16, - l2_size=8192, - with_bandwidth=False, - with_memtest=False, - with_refresh=True): - self.req_queue_size = req_queue_size - self.read_time = read_time - self.write_time = write_time - self.l2_size = l2_size - if with_memtest: - self.with_bandwidth = True - else: - self.with_bandwidth = with_bandwidth - self.with_memtest = with_memtest - self.with_refresh = with_refresh + def __init__(self, req_queue_size=8, + read_time=32, write_time=16, + l2_size=8192, + with_bandwidth=False, + with_memtest=False, + with_refresh=True): + self.req_queue_size = req_queue_size + self.read_time = read_time + self.write_time = write_time + self.l2_size = l2_size + if with_memtest: + self.with_bandwidth = True + else: + self.with_bandwidth = with_bandwidth + self.with_memtest = with_memtest + self.with_refresh = with_refresh class LASMIcon(Module): - def __init__(self, phy_settings, geom_settings, timing_settings, controller_settings, **kwargs): - if phy_settings.memtype in ["SDR"]: - burst_length = phy_settings.nphases*1 # command multiplication*SDR - elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]: - burst_length = phy_settings.nphases*2 # command multiplication*DDR - address_align = log2_int(burst_length) + def __init__(self, phy_settings, geom_settings, timing_settings, controller_settings, **kwargs): + if phy_settings.memtype in ["SDR"]: + burst_length = phy_settings.nphases*1 # command multiplication*SDR + elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]: + burst_length = phy_settings.nphases*2 # command multiplication*DDR + address_align = log2_int(burst_length) - self.dfi = dfi.Interface(geom_settings.addressbits, - geom_settings.bankbits, - phy_settings.dfi_databits, - phy_settings.nphases) - self.lasmic = lasmibus.Interface( - aw=geom_settings.rowbits + geom_settings.colbits - address_align, - dw=phy_settings.dfi_databits*phy_settings.nphases, - nbanks=2**geom_settings.bankbits, - req_queue_size=controller_settings.req_queue_size, - read_latency=phy_settings.read_latency+1, - write_latency=phy_settings.write_latency+1) - self.nrowbits = geom_settings.colbits - address_align + self.dfi = dfi.Interface(geom_settings.addressbits, + geom_settings.bankbits, + phy_settings.dfi_databits, + phy_settings.nphases) + self.lasmic = lasmibus.Interface( + aw=geom_settings.rowbits + geom_settings.colbits - address_align, + dw=phy_settings.dfi_databits*phy_settings.nphases, + nbanks=2**geom_settings.bankbits, + req_queue_size=controller_settings.req_queue_size, + read_latency=phy_settings.read_latency+1, + write_latency=phy_settings.write_latency+1) + self.nrowbits = geom_settings.colbits - address_align - ### + ### - self.submodules.refresher = Refresher(geom_settings.addressbits, geom_settings.bankbits, - timing_settings.tRP, timing_settings.tREFI, timing_settings.tRFC, enabled=controller_settings.with_refresh) - self.submodules.bank_machines = [BankMachine(geom_settings, timing_settings, controller_settings, address_align, i, - getattr(self.lasmic, "bank"+str(i))) - for i in range(2**geom_settings.bankbits)] - self.submodules.multiplexer = Multiplexer(phy_settings, geom_settings, timing_settings, controller_settings, - self.bank_machines, self.refresher, - self.dfi, self.lasmic, - **kwargs) + self.submodules.refresher = Refresher(geom_settings.addressbits, geom_settings.bankbits, + timing_settings.tRP, timing_settings.tREFI, timing_settings.tRFC, enabled=controller_settings.with_refresh) + self.submodules.bank_machines = [BankMachine(geom_settings, timing_settings, controller_settings, address_align, i, + getattr(self.lasmic, "bank"+str(i))) + for i in range(2**geom_settings.bankbits)] + self.submodules.multiplexer = Multiplexer(phy_settings, geom_settings, timing_settings, controller_settings, + self.bank_machines, self.refresher, + self.dfi, self.lasmic, + **kwargs) - def get_csrs(self): - return self.multiplexer.get_csrs() + def get_csrs(self): + return self.multiplexer.get_csrs() diff --git a/misoclib/mem/sdram/core/lasmicon/bankmachine.py b/misoclib/mem/sdram/core/lasmicon/bankmachine.py index 5a1728a1..6bdc1a69 100644 --- a/misoclib/mem/sdram/core/lasmicon/bankmachine.py +++ b/misoclib/mem/sdram/core/lasmicon/bankmachine.py @@ -7,139 +7,139 @@ from migen.genlib.fifo import SyncFIFO from misoclib.mem.sdram.core.lasmicon.multiplexer import * class _AddressSlicer: - def __init__(self, colbits, address_align): - self.colbits = colbits - self.address_align = address_align + def __init__(self, colbits, address_align): + self.colbits = colbits + self.address_align = address_align - def row(self, address): - split = self.colbits - self.address_align - if isinstance(address, int): - return address >> split - else: - return address[split:] + def row(self, address): + split = self.colbits - self.address_align + if isinstance(address, int): + return address >> split + else: + return address[split:] - def col(self, address): - split = self.colbits - self.address_align - if isinstance(address, int): - return (address & (2**split - 1)) << self.address_align - else: - return Cat(Replicate(0, self.address_align), address[:split]) + def col(self, address): + split = self.colbits - self.address_align + if isinstance(address, int): + return (address & (2**split - 1)) << self.address_align + else: + return Cat(Replicate(0, self.address_align), address[:split]) class BankMachine(Module): - def __init__(self, geom_settings, timing_settings, controller_settings, address_align, bankn, req): - self.refresh_req = Signal() - self.refresh_gnt = Signal() - self.cmd = CommandRequestRW(geom_settings.addressbits, geom_settings.bankbits) + def __init__(self, geom_settings, timing_settings, controller_settings, address_align, bankn, req): + self.refresh_req = Signal() + self.refresh_gnt = Signal() + self.cmd = CommandRequestRW(geom_settings.addressbits, geom_settings.bankbits) - ### + ### - # Request FIFO - self.submodules.req_fifo = SyncFIFO([("we", 1), ("adr", flen(req.adr))], controller_settings.req_queue_size) - self.comb += [ - self.req_fifo.din.we.eq(req.we), - self.req_fifo.din.adr.eq(req.adr), - self.req_fifo.we.eq(req.stb), - req.req_ack.eq(self.req_fifo.writable), + # Request FIFO + self.submodules.req_fifo = SyncFIFO([("we", 1), ("adr", flen(req.adr))], controller_settings.req_queue_size) + self.comb += [ + self.req_fifo.din.we.eq(req.we), + self.req_fifo.din.adr.eq(req.adr), + self.req_fifo.we.eq(req.stb), + req.req_ack.eq(self.req_fifo.writable), - self.req_fifo.re.eq(req.dat_w_ack | req.dat_r_ack), - req.lock.eq(self.req_fifo.readable) - ] - reqf = self.req_fifo.dout + self.req_fifo.re.eq(req.dat_w_ack | req.dat_r_ack), + req.lock.eq(self.req_fifo.readable) + ] + reqf = self.req_fifo.dout - slicer = _AddressSlicer(geom_settings.colbits, address_align) + slicer = _AddressSlicer(geom_settings.colbits, address_align) - # Row tracking - has_openrow = Signal() - openrow = Signal(geom_settings.rowbits) - hit = Signal() - self.comb += hit.eq(openrow == slicer.row(reqf.adr)) - track_open = Signal() - track_close = Signal() - self.sync += [ - If(track_open, - has_openrow.eq(1), - openrow.eq(slicer.row(reqf.adr)) - ), - If(track_close, - has_openrow.eq(0) - ) - ] + # Row tracking + has_openrow = Signal() + openrow = Signal(geom_settings.rowbits) + hit = Signal() + self.comb += hit.eq(openrow == slicer.row(reqf.adr)) + track_open = Signal() + track_close = Signal() + self.sync += [ + If(track_open, + has_openrow.eq(1), + openrow.eq(slicer.row(reqf.adr)) + ), + If(track_close, + has_openrow.eq(0) + ) + ] - # Address generation - s_row_adr = Signal() - self.comb += [ - self.cmd.ba.eq(bankn), - If(s_row_adr, - self.cmd.a.eq(slicer.row(reqf.adr)) - ).Else( - self.cmd.a.eq(slicer.col(reqf.adr)) - ) - ] + # Address generation + s_row_adr = Signal() + self.comb += [ + self.cmd.ba.eq(bankn), + If(s_row_adr, + self.cmd.a.eq(slicer.row(reqf.adr)) + ).Else( + self.cmd.a.eq(slicer.col(reqf.adr)) + ) + ] - # Respect write-to-precharge specification - precharge_ok = Signal() - t_unsafe_precharge = 2 + timing_settings.tWR - 1 - unsafe_precharge_count = Signal(max=t_unsafe_precharge+1) - self.comb += precharge_ok.eq(unsafe_precharge_count == 0) - self.sync += [ - If(self.cmd.stb & self.cmd.ack & self.cmd.is_write, - unsafe_precharge_count.eq(t_unsafe_precharge) - ).Elif(~precharge_ok, - unsafe_precharge_count.eq(unsafe_precharge_count-1) - ) - ] + # Respect write-to-precharge specification + precharge_ok = Signal() + t_unsafe_precharge = 2 + timing_settings.tWR - 1 + unsafe_precharge_count = Signal(max=t_unsafe_precharge+1) + self.comb += precharge_ok.eq(unsafe_precharge_count == 0) + self.sync += [ + If(self.cmd.stb & self.cmd.ack & self.cmd.is_write, + unsafe_precharge_count.eq(t_unsafe_precharge) + ).Elif(~precharge_ok, + unsafe_precharge_count.eq(unsafe_precharge_count-1) + ) + ] - # Control and command generation FSM - fsm = FSM() - self.submodules += fsm - fsm.act("REGULAR", - If(self.refresh_req, - NextState("REFRESH") - ).Elif(self.req_fifo.readable, - If(has_openrow, - If(hit, - # NB: write-to-read specification is enforced by multiplexer - self.cmd.stb.eq(1), - req.dat_w_ack.eq(self.cmd.ack & reqf.we), - req.dat_r_ack.eq(self.cmd.ack & ~reqf.we), - self.cmd.is_read.eq(~reqf.we), - self.cmd.is_write.eq(reqf.we), - self.cmd.cas_n.eq(0), - self.cmd.we_n.eq(~reqf.we) - ).Else( - NextState("PRECHARGE") - ) - ).Else( - NextState("ACTIVATE") - ) - ) - ) - fsm.act("PRECHARGE", - # Notes: - # 1. we are presenting the column address, A10 is always low - # 2. since we always go to the ACTIVATE state, we do not need - # to assert track_close. - If(precharge_ok, - self.cmd.stb.eq(1), - If(self.cmd.ack, NextState("TRP")), - self.cmd.ras_n.eq(0), - self.cmd.we_n.eq(0), - self.cmd.is_cmd.eq(1) - ) - ) - fsm.act("ACTIVATE", - s_row_adr.eq(1), - track_open.eq(1), - self.cmd.stb.eq(1), - self.cmd.is_cmd.eq(1), - If(self.cmd.ack, NextState("TRCD")), - self.cmd.ras_n.eq(0) - ) - fsm.act("REFRESH", - self.refresh_gnt.eq(precharge_ok), - track_close.eq(1), - self.cmd.is_cmd.eq(1), - If(~self.refresh_req, NextState("REGULAR")) - ) - fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1) - fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD-1) + # Control and command generation FSM + fsm = FSM() + self.submodules += fsm + fsm.act("REGULAR", + If(self.refresh_req, + NextState("REFRESH") + ).Elif(self.req_fifo.readable, + If(has_openrow, + If(hit, + # NB: write-to-read specification is enforced by multiplexer + self.cmd.stb.eq(1), + req.dat_w_ack.eq(self.cmd.ack & reqf.we), + req.dat_r_ack.eq(self.cmd.ack & ~reqf.we), + self.cmd.is_read.eq(~reqf.we), + self.cmd.is_write.eq(reqf.we), + self.cmd.cas_n.eq(0), + self.cmd.we_n.eq(~reqf.we) + ).Else( + NextState("PRECHARGE") + ) + ).Else( + NextState("ACTIVATE") + ) + ) + ) + fsm.act("PRECHARGE", + # Notes: + # 1. we are presenting the column address, A10 is always low + # 2. since we always go to the ACTIVATE state, we do not need + # to assert track_close. + If(precharge_ok, + self.cmd.stb.eq(1), + If(self.cmd.ack, NextState("TRP")), + self.cmd.ras_n.eq(0), + self.cmd.we_n.eq(0), + self.cmd.is_cmd.eq(1) + ) + ) + fsm.act("ACTIVATE", + s_row_adr.eq(1), + track_open.eq(1), + self.cmd.stb.eq(1), + self.cmd.is_cmd.eq(1), + If(self.cmd.ack, NextState("TRCD")), + self.cmd.ras_n.eq(0) + ) + fsm.act("REFRESH", + self.refresh_gnt.eq(precharge_ok), + track_close.eq(1), + self.cmd.is_cmd.eq(1), + If(~self.refresh_req, NextState("REGULAR")) + ) + fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1) + fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD-1) diff --git a/misoclib/mem/sdram/core/lasmicon/multiplexer.py b/misoclib/mem/sdram/core/lasmicon/multiplexer.py index 7a9f3a3e..f1a811d3 100644 --- a/misoclib/mem/sdram/core/lasmicon/multiplexer.py +++ b/misoclib/mem/sdram/core/lasmicon/multiplexer.py @@ -7,217 +7,217 @@ from migen.bank.description import AutoCSR from misoclib.mem.sdram.core.lasmicon.perf import Bandwidth class CommandRequest: - def __init__(self, a, ba): - self.a = Signal(a) - self.ba = Signal(ba) - self.cas_n = Signal(reset=1) - self.ras_n = Signal(reset=1) - self.we_n = Signal(reset=1) + def __init__(self, a, ba): + self.a = Signal(a) + self.ba = Signal(ba) + self.cas_n = Signal(reset=1) + self.ras_n = Signal(reset=1) + self.we_n = Signal(reset=1) class CommandRequestRW(CommandRequest): - def __init__(self, a, ba): - CommandRequest.__init__(self, a, ba) - self.stb = Signal() - self.ack = Signal() - self.is_cmd = Signal() - self.is_read = Signal() - self.is_write = Signal() + def __init__(self, a, ba): + CommandRequest.__init__(self, a, ba) + self.stb = Signal() + self.ack = Signal() + self.is_cmd = Signal() + self.is_read = Signal() + self.is_write = Signal() class _CommandChooser(Module): - def __init__(self, requests): - self.want_reads = Signal() - self.want_writes = Signal() - self.want_cmds = Signal() - # NB: cas_n/ras_n/we_n are 1 when stb is inactive - self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba)) - - ### - - rr = RoundRobin(len(requests), SP_CE) - self.submodules += rr - - self.comb += [rr.request[i].eq(req.stb & ((req.is_cmd & self.want_cmds) | ((req.is_read == self.want_reads) | (req.is_write == self.want_writes)))) - for i, req in enumerate(requests)] - - stb = Signal() - self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant]) - for name in ["a", "ba", "is_read", "is_write", "is_cmd"]: - choices = Array(getattr(req, name) for req in requests) - self.comb += getattr(self.cmd, name).eq(choices[rr.grant]) - for name in ["cas_n", "ras_n", "we_n"]: - # we should only assert those signals when stb is 1 - choices = Array(getattr(req, name) for req in requests) - self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant])) - self.comb += self.cmd.stb.eq(stb \ - & ((self.cmd.is_cmd & self.want_cmds) | ((self.cmd.is_read == self.want_reads) \ - & (self.cmd.is_write == self.want_writes)))) - - self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1)) - for i, req in enumerate(requests)] - self.comb += rr.ce.eq(self.cmd.ack) + def __init__(self, requests): + self.want_reads = Signal() + self.want_writes = Signal() + self.want_cmds = Signal() + # NB: cas_n/ras_n/we_n are 1 when stb is inactive + self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba)) + + ### + + rr = RoundRobin(len(requests), SP_CE) + self.submodules += rr + + self.comb += [rr.request[i].eq(req.stb & ((req.is_cmd & self.want_cmds) | ((req.is_read == self.want_reads) | (req.is_write == self.want_writes)))) + for i, req in enumerate(requests)] + + stb = Signal() + self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant]) + for name in ["a", "ba", "is_read", "is_write", "is_cmd"]: + choices = Array(getattr(req, name) for req in requests) + self.comb += getattr(self.cmd, name).eq(choices[rr.grant]) + for name in ["cas_n", "ras_n", "we_n"]: + # we should only assert those signals when stb is 1 + choices = Array(getattr(req, name) for req in requests) + self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant])) + self.comb += self.cmd.stb.eq(stb \ + & ((self.cmd.is_cmd & self.want_cmds) | ((self.cmd.is_read == self.want_reads) \ + & (self.cmd.is_write == self.want_writes)))) + + self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1)) + for i, req in enumerate(requests)] + self.comb += rr.ce.eq(self.cmd.ack) class _Steerer(Module): - def __init__(self, commands, dfi): - ncmd = len(commands) - nph = len(dfi.phases) - self.sel = [Signal(max=ncmd) for i in range(nph)] - - ### - - def stb_and(cmd, attr): - if not hasattr(cmd, "stb"): - return 0 - else: - return cmd.stb & getattr(cmd, attr) - for phase, sel in zip(dfi.phases, self.sel): - self.comb += [ - phase.cke.eq(1), - phase.cs_n.eq(0) - ] - if hasattr(phase, "odt"): - self.comb += phase.odt.eq(1) - if hasattr(phase, "reset_n"): - self.comb += phase.reset_n.eq(1) - self.sync += [ - phase.address.eq(Array(cmd.a for cmd in commands)[sel]), - phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]), - phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]), - phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]), - phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]), - phase.rddata_en.eq(Array(stb_and(cmd, "is_read") for cmd in commands)[sel]), - phase.wrdata_en.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel]) - ] + def __init__(self, commands, dfi): + ncmd = len(commands) + nph = len(dfi.phases) + self.sel = [Signal(max=ncmd) for i in range(nph)] + + ### + + def stb_and(cmd, attr): + if not hasattr(cmd, "stb"): + return 0 + else: + return cmd.stb & getattr(cmd, attr) + for phase, sel in zip(dfi.phases, self.sel): + self.comb += [ + phase.cke.eq(1), + phase.cs_n.eq(0) + ] + if hasattr(phase, "odt"): + self.comb += phase.odt.eq(1) + if hasattr(phase, "reset_n"): + self.comb += phase.reset_n.eq(1) + self.sync += [ + phase.address.eq(Array(cmd.a for cmd in commands)[sel]), + phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]), + phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]), + phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]), + phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]), + phase.rddata_en.eq(Array(stb_and(cmd, "is_read") for cmd in commands)[sel]), + phase.wrdata_en.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel]) + ] class Multiplexer(Module, AutoCSR): - def __init__(self, phy_settings, geom_settings, timing_settings, controller_settings, bank_machines, refresher, dfi, lasmic, - with_bandwidth=False): - assert(phy_settings.nphases == len(dfi.phases)) - self.phy_settings = phy_settings - - # Command choosing - requests = [bm.cmd for bm in bank_machines] - self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests) - self.submodules.choose_req = choose_req = _CommandChooser(requests) - self.comb += [ - choose_cmd.want_reads.eq(0), - choose_cmd.want_writes.eq(0) - ] - if phy_settings.nphases == 1: - self.comb += [ - choose_cmd.want_cmds.eq(1), - choose_req.want_cmds.eq(1) - ] - - # Command steering - nop = CommandRequest(geom_settings.addressbits, geom_settings.bankbits) - commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st - (STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4) - steerer = _Steerer(commands, dfi) - self.submodules += steerer - - # Read/write turnaround - read_available = Signal() - write_available = Signal() - self.comb += [ - read_available.eq(optree("|", [req.stb & req.is_read for req in requests])), - write_available.eq(optree("|", [req.stb & req.is_write for req in requests])) - ] - - def anti_starvation(timeout): - en = Signal() - max_time = Signal() - if timeout: - t = timeout - 1 - time = Signal(max=t+1) - self.comb += max_time.eq(time == 0) - self.sync += If(~en, - time.eq(t) - ).Elif(~max_time, - time.eq(time - 1) - ) - else: - self.comb += max_time.eq(0) - return en, max_time - read_time_en, max_read_time = anti_starvation(controller_settings.read_time) - write_time_en, max_write_time = anti_starvation(controller_settings.write_time) - - # Refresh - self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines] - go_to_refresh = Signal() - self.comb += go_to_refresh.eq(optree("&", [bm.refresh_gnt for bm in bank_machines])) - - # Datapath - all_rddata = [p.rddata for p in dfi.phases] - all_wrdata = [p.wrdata for p in dfi.phases] - all_wrdata_mask = [p.wrdata_mask for p in dfi.phases] - self.comb += [ - lasmic.dat_r.eq(Cat(*all_rddata)), - Cat(*all_wrdata).eq(lasmic.dat_w), - Cat(*all_wrdata_mask).eq(~lasmic.dat_we) - ] - - # Control FSM - fsm = FSM() - self.submodules += fsm - - def steerer_sel(steerer, phy_settings, r_w_n): - r = [] - for i in range(phy_settings.nphases): - s = steerer.sel[i].eq(STEER_NOP) - if r_w_n == "read": - if i == phy_settings.rdphase: - s = steerer.sel[i].eq(STEER_REQ) - elif i == phy_settings.rdcmdphase: - s = steerer.sel[i].eq(STEER_CMD) - elif r_w_n == "write": - if i == phy_settings.wrphase: - s = steerer.sel[i].eq(STEER_REQ) - elif i == phy_settings.wrcmdphase: - s = steerer.sel[i].eq(STEER_CMD) - else: - raise ValueError - r.append(s) - return r - - fsm.act("READ", - read_time_en.eq(1), - choose_req.want_reads.eq(1), - choose_cmd.cmd.ack.eq(1), - choose_req.cmd.ack.eq(1), - steerer_sel(steerer, phy_settings, "read"), - If(write_available, - # TODO: switch only after several cycles of ~read_available? - If(~read_available | max_read_time, NextState("RTW")) - ), - If(go_to_refresh, NextState("REFRESH")) - ) - fsm.act("WRITE", - write_time_en.eq(1), - choose_req.want_writes.eq(1), - choose_cmd.cmd.ack.eq(1), - choose_req.cmd.ack.eq(1), - steerer_sel(steerer, phy_settings, "write"), - If(read_available, - If(~write_available | max_write_time, NextState("WTR")) - ), - If(go_to_refresh, NextState("REFRESH")) - ) - fsm.act("REFRESH", - steerer.sel[0].eq(STEER_REFRESH), - If(~refresher.req, NextState("READ")) - ) - fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases - fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1) - # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog - fsm.finalize() - self.comb += refresher.ack.eq(fsm.state == fsm.encoding["REFRESH"]) - - self.with_bandwidth = with_bandwidth - - def add_bandwidth(self): - self.with_bandwidth = True - - def do_finalize(self): - if self.with_bandwidth: - data_width = self.phy_settings.dfi_databits*self.phy_settings.nphases - self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width) + def __init__(self, phy_settings, geom_settings, timing_settings, controller_settings, bank_machines, refresher, dfi, lasmic, + with_bandwidth=False): + assert(phy_settings.nphases == len(dfi.phases)) + self.phy_settings = phy_settings + + # Command choosing + requests = [bm.cmd for bm in bank_machines] + self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests) + self.submodules.choose_req = choose_req = _CommandChooser(requests) + self.comb += [ + choose_cmd.want_reads.eq(0), + choose_cmd.want_writes.eq(0) + ] + if phy_settings.nphases == 1: + self.comb += [ + choose_cmd.want_cmds.eq(1), + choose_req.want_cmds.eq(1) + ] + + # Command steering + nop = CommandRequest(geom_settings.addressbits, geom_settings.bankbits) + commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st + (STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4) + steerer = _Steerer(commands, dfi) + self.submodules += steerer + + # Read/write turnaround + read_available = Signal() + write_available = Signal() + self.comb += [ + read_available.eq(optree("|", [req.stb & req.is_read for req in requests])), + write_available.eq(optree("|", [req.stb & req.is_write for req in requests])) + ] + + def anti_starvation(timeout): + en = Signal() + max_time = Signal() + if timeout: + t = timeout - 1 + time = Signal(max=t+1) + self.comb += max_time.eq(time == 0) + self.sync += If(~en, + time.eq(t) + ).Elif(~max_time, + time.eq(time - 1) + ) + else: + self.comb += max_time.eq(0) + return en, max_time + read_time_en, max_read_time = anti_starvation(controller_settings.read_time) + write_time_en, max_write_time = anti_starvation(controller_settings.write_time) + + # Refresh + self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines] + go_to_refresh = Signal() + self.comb += go_to_refresh.eq(optree("&", [bm.refresh_gnt for bm in bank_machines])) + + # Datapath + all_rddata = [p.rddata for p in dfi.phases] + all_wrdata = [p.wrdata for p in dfi.phases] + all_wrdata_mask = [p.wrdata_mask for p in dfi.phases] + self.comb += [ + lasmic.dat_r.eq(Cat(*all_rddata)), + Cat(*all_wrdata).eq(lasmic.dat_w), + Cat(*all_wrdata_mask).eq(~lasmic.dat_we) + ] + + # Control FSM + fsm = FSM() + self.submodules += fsm + + def steerer_sel(steerer, phy_settings, r_w_n): + r = [] + for i in range(phy_settings.nphases): + s = steerer.sel[i].eq(STEER_NOP) + if r_w_n == "read": + if i == phy_settings.rdphase: + s = steerer.sel[i].eq(STEER_REQ) + elif i == phy_settings.rdcmdphase: + s = steerer.sel[i].eq(STEER_CMD) + elif r_w_n == "write": + if i == phy_settings.wrphase: + s = steerer.sel[i].eq(STEER_REQ) + elif i == phy_settings.wrcmdphase: + s = steerer.sel[i].eq(STEER_CMD) + else: + raise ValueError + r.append(s) + return r + + fsm.act("READ", + read_time_en.eq(1), + choose_req.want_reads.eq(1), + choose_cmd.cmd.ack.eq(1), + choose_req.cmd.ack.eq(1), + steerer_sel(steerer, phy_settings, "read"), + If(write_available, + # TODO: switch only after several cycles of ~read_available? + If(~read_available | max_read_time, NextState("RTW")) + ), + If(go_to_refresh, NextState("REFRESH")) + ) + fsm.act("WRITE", + write_time_en.eq(1), + choose_req.want_writes.eq(1), + choose_cmd.cmd.ack.eq(1), + choose_req.cmd.ack.eq(1), + steerer_sel(steerer, phy_settings, "write"), + If(read_available, + If(~write_available | max_write_time, NextState("WTR")) + ), + If(go_to_refresh, NextState("REFRESH")) + ) + fsm.act("REFRESH", + steerer.sel[0].eq(STEER_REFRESH), + If(~refresher.req, NextState("READ")) + ) + fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases + fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1) + # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog + fsm.finalize() + self.comb += refresher.ack.eq(fsm.state == fsm.encoding["REFRESH"]) + + self.with_bandwidth = with_bandwidth + + def add_bandwidth(self): + self.with_bandwidth = True + + def do_finalize(self): + if self.with_bandwidth: + data_width = self.phy_settings.dfi_databits*self.phy_settings.nphases + self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width) diff --git a/misoclib/mem/sdram/core/lasmicon/perf.py b/misoclib/mem/sdram/core/lasmicon/perf.py index 41fd5325..377f6b1e 100644 --- a/misoclib/mem/sdram/core/lasmicon/perf.py +++ b/misoclib/mem/sdram/core/lasmicon/perf.py @@ -2,44 +2,44 @@ from migen.fhdl.std import * from migen.bank.description import * class Bandwidth(Module, AutoCSR): - def __init__(self, cmd, data_width, period_bits=24): - self._update = CSR() - self._nreads = CSRStatus(period_bits) - self._nwrites = CSRStatus(period_bits) - self._data_width = CSRStatus(bits_for(data_width), reset=data_width) + def __init__(self, cmd, data_width, period_bits=24): + self._update = CSR() + self._nreads = CSRStatus(period_bits) + self._nwrites = CSRStatus(period_bits) + self._data_width = CSRStatus(bits_for(data_width), reset=data_width) - ### + ### - cmd_stb = Signal() - cmd_ack = Signal() - cmd_is_read = Signal() - cmd_is_write = Signal() - self.sync += [ - cmd_stb.eq(cmd.stb), - cmd_ack.eq(cmd.ack), - cmd_is_read.eq(cmd.is_read), - cmd_is_write.eq(cmd.is_write) - ] + cmd_stb = Signal() + cmd_ack = Signal() + cmd_is_read = Signal() + cmd_is_write = Signal() + self.sync += [ + cmd_stb.eq(cmd.stb), + cmd_ack.eq(cmd.ack), + cmd_is_read.eq(cmd.is_read), + cmd_is_write.eq(cmd.is_write) + ] - counter = Signal(period_bits) - period = Signal() - nreads = Signal(period_bits) - nwrites = Signal(period_bits) - nreads_r = Signal(period_bits) - nwrites_r = Signal(period_bits) - self.sync += [ - Cat(counter, period).eq(counter + 1), - If(period, - nreads_r.eq(nreads), - nwrites_r.eq(nwrites), - nreads.eq(0), - nwrites.eq(0) - ).Elif(cmd_stb & cmd_ack, - If(cmd_is_read, nreads.eq(nreads + 1)), - If(cmd_is_write, nwrites.eq(nwrites + 1)), - ), - If(self._update.re, - self._nreads.status.eq(nreads_r), - self._nwrites.status.eq(nwrites_r) - ) - ] + counter = Signal(period_bits) + period = Signal() + nreads = Signal(period_bits) + nwrites = Signal(period_bits) + nreads_r = Signal(period_bits) + nwrites_r = Signal(period_bits) + self.sync += [ + Cat(counter, period).eq(counter + 1), + If(period, + nreads_r.eq(nreads), + nwrites_r.eq(nwrites), + nreads.eq(0), + nwrites.eq(0) + ).Elif(cmd_stb & cmd_ack, + If(cmd_is_read, nreads.eq(nreads + 1)), + If(cmd_is_write, nwrites.eq(nwrites + 1)), + ), + If(self._update.re, + self._nreads.status.eq(nreads_r), + self._nwrites.status.eq(nwrites_r) + ) + ] diff --git a/misoclib/mem/sdram/core/lasmicon/refresher.py b/misoclib/mem/sdram/core/lasmicon/refresher.py index c3f90670..98946998 100644 --- a/misoclib/mem/sdram/core/lasmicon/refresher.py +++ b/misoclib/mem/sdram/core/lasmicon/refresher.py @@ -5,65 +5,65 @@ from migen.genlib.fsm import FSM from misoclib.mem.sdram.core.lasmicon.multiplexer import * class Refresher(Module): - def __init__(self, a, ba, tRP, tREFI, tRFC, enabled=True): - self.req = Signal() - self.ack = Signal() # 1st command 1 cycle after assertion of ack - self.cmd = CommandRequest(a, ba) + def __init__(self, a, ba, tRP, tREFI, tRFC, enabled=True): + self.req = Signal() + self.ack = Signal() # 1st command 1 cycle after assertion of ack + self.cmd = CommandRequest(a, ba) - ### + ### - if enabled: - # Refresh sequence generator: - # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done - seq_start = Signal() - seq_done = Signal() - self.sync += [ - self.cmd.a.eq(2**10), - self.cmd.ba.eq(0), - self.cmd.cas_n.eq(1), - self.cmd.ras_n.eq(1), - self.cmd.we_n.eq(1), - seq_done.eq(0) - ] - self.sync += timeline(seq_start, [ - (1, [ - self.cmd.ras_n.eq(0), - self.cmd.we_n.eq(0) - ]), - (1+tRP, [ - self.cmd.cas_n.eq(0), - self.cmd.ras_n.eq(0) - ]), - (1+tRP+tRFC, [ - seq_done.eq(1) - ]) - ]) + if enabled: + # Refresh sequence generator: + # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done + seq_start = Signal() + seq_done = Signal() + self.sync += [ + self.cmd.a.eq(2**10), + self.cmd.ba.eq(0), + self.cmd.cas_n.eq(1), + self.cmd.ras_n.eq(1), + self.cmd.we_n.eq(1), + seq_done.eq(0) + ] + self.sync += timeline(seq_start, [ + (1, [ + self.cmd.ras_n.eq(0), + self.cmd.we_n.eq(0) + ]), + (1+tRP, [ + self.cmd.cas_n.eq(0), + self.cmd.ras_n.eq(0) + ]), + (1+tRP+tRFC, [ + seq_done.eq(1) + ]) + ]) - # Periodic refresh counter - counter = Signal(max=tREFI) - start = Signal() - self.sync += [ - start.eq(0), - If(counter == 0, - start.eq(1), - counter.eq(tREFI - 1) - ).Else( - counter.eq(counter - 1) - ) - ] + # Periodic refresh counter + counter = Signal(max=tREFI) + start = Signal() + self.sync += [ + start.eq(0), + If(counter == 0, + start.eq(1), + counter.eq(tREFI - 1) + ).Else( + counter.eq(counter - 1) + ) + ] - # Control FSM - fsm = FSM() - self.submodules += fsm - fsm.act("IDLE", If(start, NextState("WAIT_GRANT"))) - fsm.act("WAIT_GRANT", - self.req.eq(1), - If(self.ack, - seq_start.eq(1), - NextState("WAIT_SEQ") - ) - ) - fsm.act("WAIT_SEQ", - self.req.eq(1), - If(seq_done, NextState("IDLE")) - ) + # Control FSM + fsm = FSM() + self.submodules += fsm + fsm.act("IDLE", If(start, NextState("WAIT_GRANT"))) + fsm.act("WAIT_GRANT", + self.req.eq(1), + If(self.ack, + seq_start.eq(1), + NextState("WAIT_SEQ") + ) + ) + fsm.act("WAIT_SEQ", + self.req.eq(1), + If(seq_done, NextState("IDLE")) + ) diff --git a/misoclib/mem/sdram/core/lasmixbar.py b/misoclib/mem/sdram/core/lasmixbar.py index d4da8093..4bd70ff1 100644 --- a/misoclib/mem/sdram/core/lasmixbar.py +++ b/misoclib/mem/sdram/core/lasmixbar.py @@ -6,171 +6,171 @@ from migen.genlib.misc import optree from misoclib.mem.sdram.core.lasmibus import Interface def _getattr_all(l, attr): - it = iter(l) - r = getattr(next(it), attr) - for e in it: - if getattr(e, attr) != r: - raise ValueError - return r + it = iter(l) + r = getattr(next(it), attr) + for e in it: + if getattr(e, attr) != r: + raise ValueError + return r class LASMIxbar(Module): - def __init__(self, controllers, cba_shift): - self._controllers = controllers - self._cba_shift = cba_shift - - self._rca_bits = _getattr_all(controllers, "aw") - self._dw = _getattr_all(controllers, "dw") - self._nbanks = _getattr_all(controllers, "nbanks") - self._req_queue_size = _getattr_all(controllers, "req_queue_size") - self._read_latency = _getattr_all(controllers, "read_latency") - self._write_latency = _getattr_all(controllers, "write_latency") - - self._bank_bits = log2_int(self._nbanks, False) - self._controller_bits = log2_int(len(self._controllers), False) - - self._masters = [] - - def get_master(self): - if self.finalized: - raise FinalizeError - lasmi_master = Interface(self._rca_bits + self._bank_bits + self._controller_bits, - self._dw, 1, self._req_queue_size, self._read_latency, self._write_latency) - self._masters.append(lasmi_master) - return lasmi_master - - def do_finalize(self): - nmasters = len(self._masters) - - m_ca, m_ba, m_rca = self._split_master_addresses(self._controller_bits, - self._bank_bits, self._rca_bits, self._cba_shift) - - for nc, controller in enumerate(self._controllers): - if self._controller_bits: - controller_selected = [ca == nc for ca in m_ca] - else: - controller_selected = [1]*nmasters - master_req_acks = [0]*nmasters - master_dat_w_acks = [0]*nmasters - master_dat_r_acks = [0]*nmasters - - rrs = [roundrobin.RoundRobin(nmasters, roundrobin.SP_CE) for n in range(self._nbanks)] - self.submodules += rrs - for nb, rr in enumerate(rrs): - bank = getattr(controller, "bank"+str(nb)) - - # for each master, determine if another bank locks it - master_locked = [] - for nm, master in enumerate(self._masters): - locked = 0 - for other_nb, other_rr in enumerate(rrs): - if other_nb != nb: - other_bank = getattr(controller, "bank"+str(other_nb)) - locked = locked | (other_bank.lock & (other_rr.grant == nm)) - master_locked.append(locked) - - # arbitrate - bank_selected = [cs & (ba == nb) & ~locked for cs, ba, locked in zip(controller_selected, m_ba, master_locked)] - bank_requested = [bs & master.stb for bs, master in zip(bank_selected, self._masters)] - self.comb += [ - rr.request.eq(Cat(*bank_requested)), - rr.ce.eq(~bank.stb & ~bank.lock) - ] - - # route requests - self.comb += [ - bank.adr.eq(Array(m_rca)[rr.grant]), - bank.we.eq(Array(self._masters)[rr.grant].we), - bank.stb.eq(Array(bank_requested)[rr.grant]) - ] - master_req_acks = [master_req_ack | ((rr.grant == nm) & bank_selected[nm] & bank.req_ack) - for nm, master_req_ack in enumerate(master_req_acks)] - master_dat_w_acks = [master_dat_w_ack | ((rr.grant == nm) & bank.dat_w_ack) - for nm, master_dat_w_ack in enumerate(master_dat_w_acks)] - master_dat_r_acks = [master_dat_r_ack | ((rr.grant == nm) & bank.dat_r_ack) - for nm, master_dat_r_ack in enumerate(master_dat_r_acks)] - - for nm, master_dat_w_ack in enumerate(master_dat_w_acks): - for i in range(self._write_latency): - new_master_dat_w_ack = Signal() - self.sync += new_master_dat_w_ack.eq(master_dat_w_ack) - master_dat_w_ack = new_master_dat_w_ack - master_dat_w_acks[nm] = master_dat_w_ack - - for nm, master_dat_r_ack in enumerate(master_dat_r_acks): - for i in range(self._read_latency): - new_master_dat_r_ack = Signal() - self.sync += new_master_dat_r_ack.eq(master_dat_r_ack) - master_dat_r_ack = new_master_dat_r_ack - master_dat_r_acks[nm] = master_dat_r_ack - - self.comb += [master.req_ack.eq(master_req_ack) for master, master_req_ack in zip(self._masters, master_req_acks)] - self.comb += [master.dat_w_ack.eq(master_dat_w_ack) for master, master_dat_w_ack in zip(self._masters, master_dat_w_acks)] - self.comb += [master.dat_r_ack.eq(master_dat_r_ack) for master, master_dat_r_ack in zip(self._masters, master_dat_r_acks)] - - # route data writes - controller_selected_wl = controller_selected - for i in range(self._write_latency): - n_controller_selected_wl = [Signal() for i in range(nmasters)] - self.sync += [n.eq(o) for n, o in zip(n_controller_selected_wl, controller_selected_wl)] - controller_selected_wl = n_controller_selected_wl - dat_w_maskselect = [] - dat_we_maskselect = [] - for master, selected in zip(self._masters, controller_selected_wl): - o_dat_w = Signal(self._dw) - o_dat_we = Signal(self._dw//8) - self.comb += If(selected, - o_dat_w.eq(master.dat_w), - o_dat_we.eq(master.dat_we) - ) - dat_w_maskselect.append(o_dat_w) - dat_we_maskselect.append(o_dat_we) - self.comb += [ - controller.dat_w.eq(optree("|", dat_w_maskselect)), - controller.dat_we.eq(optree("|", dat_we_maskselect)) - ] - - # route data reads - if self._controller_bits: - for master in self._masters: - controller_sel = Signal(self._controller_bits) - for nc, controller in enumerate(self._controllers): - for nb in range(nbanks): - bank = getattr(controller, "bank"+str(nb)) - self.comb += If(bank.stb & bank.ack, controller_sel.eq(nc)) - for i in range(self._read_latency): - n_controller_sel = Signal(self._controller_bits) - self.sync += n_controller_sel.eq(controller_sel) - controller_sel = n_controller_sel - self.comb += master.dat_r.eq(Array(self._controllers)[controller_sel].dat_r) - else: - self.comb += [master.dat_r.eq(self._controllers[0].dat_r) for master in self._masters] - - def _split_master_addresses(self, controller_bits, bank_bits, rca_bits, cba_shift): - m_ca = [] # controller address - m_ba = [] # bank address - m_rca = [] # row and column address - for master in self._masters: - cba = Signal(self._controller_bits + self._bank_bits) - rca = Signal(self._rca_bits) - cba_upper = cba_shift + controller_bits + bank_bits - self.comb += cba.eq(master.adr[cba_shift:cba_upper]) - if cba_shift < self._rca_bits: - if cba_shift: - self.comb += rca.eq(Cat(master.adr[:cba_shift], master.adr[cba_upper:])) - else: - self.comb += rca.eq(master.adr[cba_upper:]) - else: - self.comb += rca.eq(master.adr[:cba_shift]) - - if self._controller_bits: - ca = Signal(self._controller_bits) - ba = Signal(self._bank_bits) - self.comb += Cat(ba, ca).eq(cba) - else: - ca = None - ba = cba - - m_ca.append(ca) - m_ba.append(ba) - m_rca.append(rca) - return m_ca, m_ba, m_rca + def __init__(self, controllers, cba_shift): + self._controllers = controllers + self._cba_shift = cba_shift + + self._rca_bits = _getattr_all(controllers, "aw") + self._dw = _getattr_all(controllers, "dw") + self._nbanks = _getattr_all(controllers, "nbanks") + self._req_queue_size = _getattr_all(controllers, "req_queue_size") + self._read_latency = _getattr_all(controllers, "read_latency") + self._write_latency = _getattr_all(controllers, "write_latency") + + self._bank_bits = log2_int(self._nbanks, False) + self._controller_bits = log2_int(len(self._controllers), False) + + self._masters = [] + + def get_master(self): + if self.finalized: + raise FinalizeError + lasmi_master = Interface(self._rca_bits + self._bank_bits + self._controller_bits, + self._dw, 1, self._req_queue_size, self._read_latency, self._write_latency) + self._masters.append(lasmi_master) + return lasmi_master + + def do_finalize(self): + nmasters = len(self._masters) + + m_ca, m_ba, m_rca = self._split_master_addresses(self._controller_bits, + self._bank_bits, self._rca_bits, self._cba_shift) + + for nc, controller in enumerate(self._controllers): + if self._controller_bits: + controller_selected = [ca == nc for ca in m_ca] + else: + controller_selected = [1]*nmasters + master_req_acks = [0]*nmasters + master_dat_w_acks = [0]*nmasters + master_dat_r_acks = [0]*nmasters + + rrs = [roundrobin.RoundRobin(nmasters, roundrobin.SP_CE) for n in range(self._nbanks)] + self.submodules += rrs + for nb, rr in enumerate(rrs): + bank = getattr(controller, "bank"+str(nb)) + + # for each master, determine if another bank locks it + master_locked = [] + for nm, master in enumerate(self._masters): + locked = 0 + for other_nb, other_rr in enumerate(rrs): + if other_nb != nb: + other_bank = getattr(controller, "bank"+str(other_nb)) + locked = locked | (other_bank.lock & (other_rr.grant == nm)) + master_locked.append(locked) + + # arbitrate + bank_selected = [cs & (ba == nb) & ~locked for cs, ba, locked in zip(controller_selected, m_ba, master_locked)] + bank_requested = [bs & master.stb for bs, master in zip(bank_selected, self._masters)] + self.comb += [ + rr.request.eq(Cat(*bank_requested)), + rr.ce.eq(~bank.stb & ~bank.lock) + ] + + # route requests + self.comb += [ + bank.adr.eq(Array(m_rca)[rr.grant]), + bank.we.eq(Array(self._masters)[rr.grant].we), + bank.stb.eq(Array(bank_requested)[rr.grant]) + ] + master_req_acks = [master_req_ack | ((rr.grant == nm) & bank_selected[nm] & bank.req_ack) + for nm, master_req_ack in enumerate(master_req_acks)] + master_dat_w_acks = [master_dat_w_ack | ((rr.grant == nm) & bank.dat_w_ack) + for nm, master_dat_w_ack in enumerate(master_dat_w_acks)] + master_dat_r_acks = [master_dat_r_ack | ((rr.grant == nm) & bank.dat_r_ack) + for nm, master_dat_r_ack in enumerate(master_dat_r_acks)] + + for nm, master_dat_w_ack in enumerate(master_dat_w_acks): + for i in range(self._write_latency): + new_master_dat_w_ack = Signal() + self.sync += new_master_dat_w_ack.eq(master_dat_w_ack) + master_dat_w_ack = new_master_dat_w_ack + master_dat_w_acks[nm] = master_dat_w_ack + + for nm, master_dat_r_ack in enumerate(master_dat_r_acks): + for i in range(self._read_latency): + new_master_dat_r_ack = Signal() + self.sync += new_master_dat_r_ack.eq(master_dat_r_ack) + master_dat_r_ack = new_master_dat_r_ack + master_dat_r_acks[nm] = master_dat_r_ack + + self.comb += [master.req_ack.eq(master_req_ack) for master, master_req_ack in zip(self._masters, master_req_acks)] + self.comb += [master.dat_w_ack.eq(master_dat_w_ack) for master, master_dat_w_ack in zip(self._masters, master_dat_w_acks)] + self.comb += [master.dat_r_ack.eq(master_dat_r_ack) for master, master_dat_r_ack in zip(self._masters, master_dat_r_acks)] + + # route data writes + controller_selected_wl = controller_selected + for i in range(self._write_latency): + n_controller_selected_wl = [Signal() for i in range(nmasters)] + self.sync += [n.eq(o) for n, o in zip(n_controller_selected_wl, controller_selected_wl)] + controller_selected_wl = n_controller_selected_wl + dat_w_maskselect = [] + dat_we_maskselect = [] + for master, selected in zip(self._masters, controller_selected_wl): + o_dat_w = Signal(self._dw) + o_dat_we = Signal(self._dw//8) + self.comb += If(selected, + o_dat_w.eq(master.dat_w), + o_dat_we.eq(master.dat_we) + ) + dat_w_maskselect.append(o_dat_w) + dat_we_maskselect.append(o_dat_we) + self.comb += [ + controller.dat_w.eq(optree("|", dat_w_maskselect)), + controller.dat_we.eq(optree("|", dat_we_maskselect)) + ] + + # route data reads + if self._controller_bits: + for master in self._masters: + controller_sel = Signal(self._controller_bits) + for nc, controller in enumerate(self._controllers): + for nb in range(nbanks): + bank = getattr(controller, "bank"+str(nb)) + self.comb += If(bank.stb & bank.ack, controller_sel.eq(nc)) + for i in range(self._read_latency): + n_controller_sel = Signal(self._controller_bits) + self.sync += n_controller_sel.eq(controller_sel) + controller_sel = n_controller_sel + self.comb += master.dat_r.eq(Array(self._controllers)[controller_sel].dat_r) + else: + self.comb += [master.dat_r.eq(self._controllers[0].dat_r) for master in self._masters] + + def _split_master_addresses(self, controller_bits, bank_bits, rca_bits, cba_shift): + m_ca = [] # controller address + m_ba = [] # bank address + m_rca = [] # row and column address + for master in self._masters: + cba = Signal(self._controller_bits + self._bank_bits) + rca = Signal(self._rca_bits) + cba_upper = cba_shift + controller_bits + bank_bits + self.comb += cba.eq(master.adr[cba_shift:cba_upper]) + if cba_shift < self._rca_bits: + if cba_shift: + self.comb += rca.eq(Cat(master.adr[:cba_shift], master.adr[cba_upper:])) + else: + self.comb += rca.eq(master.adr[cba_upper:]) + else: + self.comb += rca.eq(master.adr[:cba_shift]) + + if self._controller_bits: + ca = Signal(self._controller_bits) + ba = Signal(self._bank_bits) + self.comb += Cat(ba, ca).eq(cba) + else: + ca = None + ba = cba + + m_ca.append(ca) + m_ba.append(ba) + m_rca.append(rca) + return m_ca, m_ba, m_rca diff --git a/misoclib/mem/sdram/core/minicon/__init__.py b/misoclib/mem/sdram/core/minicon/__init__.py index 16d4cf59..f68de824 100644 --- a/misoclib/mem/sdram/core/minicon/__init__.py +++ b/misoclib/mem/sdram/core/minicon/__init__.py @@ -5,193 +5,193 @@ from migen.genlib.fsm import FSM, NextState from misoclib.mem.sdram.phy import dfi as dfibus class _AddressSlicer: - def __init__(self, colbits, bankbits, rowbits, address_align): - self.colbits = colbits - self.bankbits = bankbits - self.rowbits = rowbits - self.max_a = colbits + rowbits + bankbits - self.address_align = address_align - - def row(self, address): - split = self.bankbits + self.colbits - if isinstance(address, int): - return address >> split - else: - return address[split:self.max_a] - - def bank(self, address): - mask = 2**(self.bankbits + self.colbits) - 1 - shift = self.colbits - if isinstance(address, int): - return (address & mask) >> shift - else: - return address[self.colbits:self.colbits+self.bankbits] - - def col(self, address): - split = self.colbits - if isinstance(address, int): - return (address & (2**split - 1)) << self.address_align - else: - return Cat(Replicate(0, self.address_align), address[:split]) + def __init__(self, colbits, bankbits, rowbits, address_align): + self.colbits = colbits + self.bankbits = bankbits + self.rowbits = rowbits + self.max_a = colbits + rowbits + bankbits + self.address_align = address_align + + def row(self, address): + split = self.bankbits + self.colbits + if isinstance(address, int): + return address >> split + else: + return address[split:self.max_a] + + def bank(self, address): + mask = 2**(self.bankbits + self.colbits) - 1 + shift = self.colbits + if isinstance(address, int): + return (address & mask) >> shift + else: + return address[self.colbits:self.colbits+self.bankbits] + + def col(self, address): + split = self.colbits + if isinstance(address, int): + return (address & (2**split - 1)) << self.address_align + else: + return Cat(Replicate(0, self.address_align), address[:split]) class MiniconSettings: - def __init__(self): - pass + def __init__(self): + pass class Minicon(Module): - def __init__(self, phy_settings, geom_settings, timing_settings): - if phy_settings.memtype in ["SDR"]: - burst_length = phy_settings.nphases*1 # command multiplication*SDR - elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]: - burst_length = phy_settings.nphases*2 # command multiplication*DDR - address_align = log2_int(burst_length) - - nbanks = range(2**geom_settings.bankbits) - A10_ENABLED = 0 - COLUMN = 1 - ROW = 2 - rdphase = phy_settings.rdphase - wrphase = phy_settings.wrphase - - self.dfi = dfi = dfibus.Interface(geom_settings.addressbits, - geom_settings.bankbits, - phy_settings.dfi_databits, - phy_settings.nphases) - - self.bus = bus = wishbone.Interface(data_width=phy_settings.nphases*flen(dfi.phases[rdphase].rddata)) - slicer = _AddressSlicer(geom_settings.colbits, geom_settings.bankbits, geom_settings.rowbits, address_align) - refresh_req = Signal() - refresh_ack = Signal() - refresh_counter = Signal(max=timing_settings.tREFI+1) - hit = Signal() - row_open = Signal() - row_closeall = Signal() - addr_sel = Signal(max=3, reset=A10_ENABLED) - has_curbank_openrow = Signal() - - # Extra bit means row is active when asserted - self.openrow = openrow = Array(Signal(geom_settings.rowbits + 1) for b in nbanks) - - self.comb += [ - hit.eq(openrow[slicer.bank(bus.adr)] == Cat(slicer.row(bus.adr), 1)), - has_curbank_openrow.eq(openrow[slicer.bank(bus.adr)][-1]), - bus.dat_r.eq(Cat(phase.rddata for phase in dfi.phases)), - Cat(phase.wrdata for phase in dfi.phases).eq(bus.dat_w), - Cat(phase.wrdata_mask for phase in dfi.phases).eq(~bus.sel), - ] - - for phase in dfi.phases: - self.comb += [ - phase.cke.eq(1), - phase.cs_n.eq(0), - phase.address.eq(Array([2**10, slicer.col(bus.adr), slicer.row(bus.adr)])[addr_sel]), - phase.bank.eq(slicer.bank(bus.adr)) - ] - - for b in nbanks: - self.sync += [ - If(row_open & (b == slicer.bank(bus.adr)), - openrow[b].eq(Cat(slicer.row(bus.adr), 1)), - ), - If(row_closeall, - openrow[b][-1].eq(0) - ) - ] - - self.sync += [ - If(refresh_ack, - refresh_req.eq(0) - ), - If(refresh_counter == 0, - refresh_counter.eq(timing_settings.tREFI), - refresh_req.eq(1) - ).Else( - refresh_counter.eq(refresh_counter - 1) - ) - ] - - fsm = FSM() - self.submodules += fsm - fsm.act("IDLE", - If(refresh_req, - NextState("PRECHARGEALL") - ).Elif(bus.stb & bus.cyc, - If(hit & bus.we, - NextState("WRITE") - ), - If(hit & ~bus.we, - NextState("READ") - ), - If(has_curbank_openrow & ~hit, - NextState("PRECHARGE") - ), - If(~has_curbank_openrow, - NextState("ACTIVATE") - ), - ) - ) - fsm.act("READ", - # We output Column bits at address pins so A10 is 0 - # to disable row Auto-Precharge - dfi.phases[rdphase].ras_n.eq(1), - dfi.phases[rdphase].cas_n.eq(0), - dfi.phases[rdphase].we_n.eq(1), - dfi.phases[rdphase].rddata_en.eq(1), - addr_sel.eq(COLUMN), - NextState("READ-WAIT-ACK"), - ) - fsm.act("READ-WAIT-ACK", - If(dfi.phases[rdphase].rddata_valid, - NextState("IDLE"), - bus.ack.eq(1) - ).Else( - NextState("READ-WAIT-ACK") - ) - ) - fsm.act("WRITE", - dfi.phases[wrphase].ras_n.eq(1), - dfi.phases[wrphase].cas_n.eq(0), - dfi.phases[wrphase].we_n.eq(0), - dfi.phases[wrphase].wrdata_en.eq(1), - addr_sel.eq(COLUMN), - bus.ack.eq(1), - NextState("IDLE") - ) - fsm.act("PRECHARGEALL", - row_closeall.eq(1), - dfi.phases[rdphase].ras_n.eq(0), - dfi.phases[rdphase].cas_n.eq(1), - dfi.phases[rdphase].we_n.eq(0), - addr_sel.eq(A10_ENABLED), - NextState("PRE-REFRESH") - ) - fsm.act("PRECHARGE", - # Notes: - # 1. we are presenting the column address so that A10 is low - # 2. since we always go to the ACTIVATE state, we do not need - # to assert row_close because it will be reopen right after. - NextState("TRP"), - addr_sel.eq(COLUMN), - dfi.phases[rdphase].ras_n.eq(0), - dfi.phases[rdphase].cas_n.eq(1), - dfi.phases[rdphase].we_n.eq(0) - ) - fsm.act("ACTIVATE", - row_open.eq(1), - NextState("TRCD"), - dfi.phases[rdphase].ras_n.eq(0), - dfi.phases[rdphase].cas_n.eq(1), - dfi.phases[rdphase].we_n.eq(1), - addr_sel.eq(ROW) - ) - fsm.act("REFRESH", - refresh_ack.eq(1), - dfi.phases[rdphase].ras_n.eq(0), - dfi.phases[rdphase].cas_n.eq(0), - dfi.phases[rdphase].we_n.eq(1), - NextState("POST-REFRESH") - ) - fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1) - fsm.delayed_enter("PRE-REFRESH", "REFRESH", timing_settings.tRP-1) - fsm.delayed_enter("TRCD", "IDLE", timing_settings.tRCD-1) - fsm.delayed_enter("POST-REFRESH", "IDLE", timing_settings.tRFC-1) + def __init__(self, phy_settings, geom_settings, timing_settings): + if phy_settings.memtype in ["SDR"]: + burst_length = phy_settings.nphases*1 # command multiplication*SDR + elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]: + burst_length = phy_settings.nphases*2 # command multiplication*DDR + address_align = log2_int(burst_length) + + nbanks = range(2**geom_settings.bankbits) + A10_ENABLED = 0 + COLUMN = 1 + ROW = 2 + rdphase = phy_settings.rdphase + wrphase = phy_settings.wrphase + + self.dfi = dfi = dfibus.Interface(geom_settings.addressbits, + geom_settings.bankbits, + phy_settings.dfi_databits, + phy_settings.nphases) + + self.bus = bus = wishbone.Interface(data_width=phy_settings.nphases*flen(dfi.phases[rdphase].rddata)) + slicer = _AddressSlicer(geom_settings.colbits, geom_settings.bankbits, geom_settings.rowbits, address_align) + refresh_req = Signal() + refresh_ack = Signal() + refresh_counter = Signal(max=timing_settings.tREFI+1) + hit = Signal() + row_open = Signal() + row_closeall = Signal() + addr_sel = Signal(max=3, reset=A10_ENABLED) + has_curbank_openrow = Signal() + + # Extra bit means row is active when asserted + self.openrow = openrow = Array(Signal(geom_settings.rowbits + 1) for b in nbanks) + + self.comb += [ + hit.eq(openrow[slicer.bank(bus.adr)] == Cat(slicer.row(bus.adr), 1)), + has_curbank_openrow.eq(openrow[slicer.bank(bus.adr)][-1]), + bus.dat_r.eq(Cat(phase.rddata for phase in dfi.phases)), + Cat(phase.wrdata for phase in dfi.phases).eq(bus.dat_w), + Cat(phase.wrdata_mask for phase in dfi.phases).eq(~bus.sel), + ] + + for phase in dfi.phases: + self.comb += [ + phase.cke.eq(1), + phase.cs_n.eq(0), + phase.address.eq(Array([2**10, slicer.col(bus.adr), slicer.row(bus.adr)])[addr_sel]), + phase.bank.eq(slicer.bank(bus.adr)) + ] + + for b in nbanks: + self.sync += [ + If(row_open & (b == slicer.bank(bus.adr)), + openrow[b].eq(Cat(slicer.row(bus.adr), 1)), + ), + If(row_closeall, + openrow[b][-1].eq(0) + ) + ] + + self.sync += [ + If(refresh_ack, + refresh_req.eq(0) + ), + If(refresh_counter == 0, + refresh_counter.eq(timing_settings.tREFI), + refresh_req.eq(1) + ).Else( + refresh_counter.eq(refresh_counter - 1) + ) + ] + + fsm = FSM() + self.submodules += fsm + fsm.act("IDLE", + If(refresh_req, + NextState("PRECHARGEALL") + ).Elif(bus.stb & bus.cyc, + If(hit & bus.we, + NextState("WRITE") + ), + If(hit & ~bus.we, + NextState("READ") + ), + If(has_curbank_openrow & ~hit, + NextState("PRECHARGE") + ), + If(~has_curbank_openrow, + NextState("ACTIVATE") + ), + ) + ) + fsm.act("READ", + # We output Column bits at address pins so A10 is 0 + # to disable row Auto-Precharge + dfi.phases[rdphase].ras_n.eq(1), + dfi.phases[rdphase].cas_n.eq(0), + dfi.phases[rdphase].we_n.eq(1), + dfi.phases[rdphase].rddata_en.eq(1), + addr_sel.eq(COLUMN), + NextState("READ-WAIT-ACK"), + ) + fsm.act("READ-WAIT-ACK", + If(dfi.phases[rdphase].rddata_valid, + NextState("IDLE"), + bus.ack.eq(1) + ).Else( + NextState("READ-WAIT-ACK") + ) + ) + fsm.act("WRITE", + dfi.phases[wrphase].ras_n.eq(1), + dfi.phases[wrphase].cas_n.eq(0), + dfi.phases[wrphase].we_n.eq(0), + dfi.phases[wrphase].wrdata_en.eq(1), + addr_sel.eq(COLUMN), + bus.ack.eq(1), + NextState("IDLE") + ) + fsm.act("PRECHARGEALL", + row_closeall.eq(1), + dfi.phases[rdphase].ras_n.eq(0), + dfi.phases[rdphase].cas_n.eq(1), + dfi.phases[rdphase].we_n.eq(0), + addr_sel.eq(A10_ENABLED), + NextState("PRE-REFRESH") + ) + fsm.act("PRECHARGE", + # Notes: + # 1. we are presenting the column address so that A10 is low + # 2. since we always go to the ACTIVATE state, we do not need + # to assert row_close because it will be reopen right after. + NextState("TRP"), + addr_sel.eq(COLUMN), + dfi.phases[rdphase].ras_n.eq(0), + dfi.phases[rdphase].cas_n.eq(1), + dfi.phases[rdphase].we_n.eq(0) + ) + fsm.act("ACTIVATE", + row_open.eq(1), + NextState("TRCD"), + dfi.phases[rdphase].ras_n.eq(0), + dfi.phases[rdphase].cas_n.eq(1), + dfi.phases[rdphase].we_n.eq(1), + addr_sel.eq(ROW) + ) + fsm.act("REFRESH", + refresh_ack.eq(1), + dfi.phases[rdphase].ras_n.eq(0), + dfi.phases[rdphase].cas_n.eq(0), + dfi.phases[rdphase].we_n.eq(1), + NextState("POST-REFRESH") + ) + fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1) + fsm.delayed_enter("PRE-REFRESH", "REFRESH", timing_settings.tRP-1) + fsm.delayed_enter("TRCD", "IDLE", timing_settings.tRCD-1) + fsm.delayed_enter("POST-REFRESH", "IDLE", timing_settings.tRFC-1) diff --git a/misoclib/mem/sdram/frontend/dma_lasmi.py b/misoclib/mem/sdram/frontend/dma_lasmi.py index c027b2c1..785a6c4a 100644 --- a/misoclib/mem/sdram/frontend/dma_lasmi.py +++ b/misoclib/mem/sdram/frontend/dma_lasmi.py @@ -3,87 +3,87 @@ from migen.flow.actor import * from migen.genlib.fifo import SyncFIFO class Reader(Module): - def __init__(self, lasmim, fifo_depth=None): - self.address = Sink([("a", lasmim.aw)]) - self.data = Source([("d", lasmim.dw)]) - self.busy = Signal() - - ### - - if fifo_depth is None: - fifo_depth = lasmim.req_queue_size + lasmim.read_latency + 2 - - # request issuance - request_enable = Signal() - request_issued = Signal() - - self.comb += [ - lasmim.we.eq(0), - lasmim.stb.eq(self.address.stb & request_enable), - lasmim.adr.eq(self.address.a), - self.address.ack.eq(lasmim.req_ack & request_enable), - request_issued.eq(lasmim.stb & lasmim.req_ack) - ] - - # FIFO reservation level counter - # incremented when data is planned to be queued - # decremented when data is dequeued - data_dequeued = Signal() - rsv_level = Signal(max=fifo_depth+1) - self.sync += [ - If(request_issued, - If(~data_dequeued, rsv_level.eq(rsv_level + 1)) - ).Elif(data_dequeued, - rsv_level.eq(rsv_level - 1) - ) - ] - self.comb += [ - self.busy.eq(rsv_level != 0), - request_enable.eq(rsv_level != fifo_depth) - ] - - # FIFO - fifo = SyncFIFO(lasmim.dw, fifo_depth) - self.submodules += fifo - - self.comb += [ - fifo.din.eq(lasmim.dat_r), - fifo.we.eq(lasmim.dat_r_ack), - - self.data.stb.eq(fifo.readable), - fifo.re.eq(self.data.ack), - self.data.d.eq(fifo.dout), - data_dequeued.eq(self.data.stb & self.data.ack) - ] + def __init__(self, lasmim, fifo_depth=None): + self.address = Sink([("a", lasmim.aw)]) + self.data = Source([("d", lasmim.dw)]) + self.busy = Signal() + + ### + + if fifo_depth is None: + fifo_depth = lasmim.req_queue_size + lasmim.read_latency + 2 + + # request issuance + request_enable = Signal() + request_issued = Signal() + + self.comb += [ + lasmim.we.eq(0), + lasmim.stb.eq(self.address.stb & request_enable), + lasmim.adr.eq(self.address.a), + self.address.ack.eq(lasmim.req_ack & request_enable), + request_issued.eq(lasmim.stb & lasmim.req_ack) + ] + + # FIFO reservation level counter + # incremented when data is planned to be queued + # decremented when data is dequeued + data_dequeued = Signal() + rsv_level = Signal(max=fifo_depth+1) + self.sync += [ + If(request_issued, + If(~data_dequeued, rsv_level.eq(rsv_level + 1)) + ).Elif(data_dequeued, + rsv_level.eq(rsv_level - 1) + ) + ] + self.comb += [ + self.busy.eq(rsv_level != 0), + request_enable.eq(rsv_level != fifo_depth) + ] + + # FIFO + fifo = SyncFIFO(lasmim.dw, fifo_depth) + self.submodules += fifo + + self.comb += [ + fifo.din.eq(lasmim.dat_r), + fifo.we.eq(lasmim.dat_r_ack), + + self.data.stb.eq(fifo.readable), + fifo.re.eq(self.data.ack), + self.data.d.eq(fifo.dout), + data_dequeued.eq(self.data.stb & self.data.ack) + ] class Writer(Module): - def __init__(self, lasmim, fifo_depth=None): - self.address_data = Sink([("a", lasmim.aw), ("d", lasmim.dw)]) - self.busy = Signal() - - ### - - if fifo_depth is None: - fifo_depth = lasmim.req_queue_size + lasmim.write_latency + 2 - - fifo = SyncFIFO(lasmim.dw, fifo_depth) - self.submodules += fifo - - self.comb += [ - lasmim.we.eq(1), - lasmim.stb.eq(fifo.writable & self.address_data.stb), - lasmim.adr.eq(self.address_data.a), - self.address_data.ack.eq(fifo.writable & lasmim.req_ack), - fifo.we.eq(self.address_data.stb & lasmim.req_ack), - fifo.din.eq(self.address_data.d) - ] - - self.comb += [ - If(lasmim.dat_w_ack, - fifo.re.eq(1), - lasmim.dat_we.eq(2**(lasmim.dw//8)-1), - lasmim.dat_w.eq(fifo.dout) - ), - self.busy.eq(fifo.readable) - ] + def __init__(self, lasmim, fifo_depth=None): + self.address_data = Sink([("a", lasmim.aw), ("d", lasmim.dw)]) + self.busy = Signal() + + ### + + if fifo_depth is None: + fifo_depth = lasmim.req_queue_size + lasmim.write_latency + 2 + + fifo = SyncFIFO(lasmim.dw, fifo_depth) + self.submodules += fifo + + self.comb += [ + lasmim.we.eq(1), + lasmim.stb.eq(fifo.writable & self.address_data.stb), + lasmim.adr.eq(self.address_data.a), + self.address_data.ack.eq(fifo.writable & lasmim.req_ack), + fifo.we.eq(self.address_data.stb & lasmim.req_ack), + fifo.din.eq(self.address_data.d) + ] + + self.comb += [ + If(lasmim.dat_w_ack, + fifo.re.eq(1), + lasmim.dat_we.eq(2**(lasmim.dw//8)-1), + lasmim.dat_w.eq(fifo.dout) + ), + self.busy.eq(fifo.readable) + ] diff --git a/misoclib/mem/sdram/frontend/memtest.py b/misoclib/mem/sdram/frontend/memtest.py index 7627d817..ec255a89 100644 --- a/misoclib/mem/sdram/frontend/memtest.py +++ b/misoclib/mem/sdram/frontend/memtest.py @@ -8,106 +8,106 @@ from misoclib.mem.sdram.frontend import dma_lasmi @DecorateModule(InsertReset) @DecorateModule(InsertCE) class LFSR(Module): - def __init__(self, n_out, n_state=31, taps=[27, 30]): - self.o = Signal(n_out) + def __init__(self, n_out, n_state=31, taps=[27, 30]): + self.o = Signal(n_out) - ### + ### - state = Signal(n_state) - curval = [state[i] for i in range(n_state)] - curval += [0]*(n_out - n_state) - for i in range(n_out): - nv = ~optree("^", [curval[tap] for tap in taps]) - curval.insert(0, nv) - curval.pop() + state = Signal(n_state) + curval = [state[i] for i in range(n_state)] + curval += [0]*(n_out - n_state) + for i in range(n_out): + nv = ~optree("^", [curval[tap] for tap in taps]) + curval.insert(0, nv) + curval.pop() - self.sync += [ - state.eq(Cat(*curval[:n_state])), - self.o.eq(Cat(*curval)) - ] + self.sync += [ + state.eq(Cat(*curval[:n_state])), + self.o.eq(Cat(*curval)) + ] memtest_magic = 0x361f class MemtestWriter(Module): - def __init__(self, lasmim): - self._magic = CSRStatus(16) - self._reset = CSR() - self._shoot = CSR() - self.submodules._dma = DMAWriteController(dma_lasmi.Writer(lasmim), MODE_EXTERNAL) - - ### - - self.comb += self._magic.status.eq(memtest_magic) - - lfsr = LFSR(lasmim.dw) - self.submodules += lfsr - self.comb += lfsr.reset.eq(self._reset.re) - - en = Signal() - en_counter = Signal(lasmim.aw) - self.comb += en.eq(en_counter != 0) - self.sync += [ - If(self._shoot.re, - en_counter.eq(self._dma.length) - ).Elif(lfsr.ce, - en_counter.eq(en_counter - 1) - ) - ] - - self.comb += [ - self._dma.trigger.eq(self._shoot.re), - self._dma.data.stb.eq(en), - lfsr.ce.eq(en & self._dma.data.ack), - self._dma.data.d.eq(lfsr.o) - ] - - def get_csrs(self): - return [self._magic, self._reset, self._shoot] + self._dma.get_csrs() + def __init__(self, lasmim): + self._magic = CSRStatus(16) + self._reset = CSR() + self._shoot = CSR() + self.submodules._dma = DMAWriteController(dma_lasmi.Writer(lasmim), MODE_EXTERNAL) + + ### + + self.comb += self._magic.status.eq(memtest_magic) + + lfsr = LFSR(lasmim.dw) + self.submodules += lfsr + self.comb += lfsr.reset.eq(self._reset.re) + + en = Signal() + en_counter = Signal(lasmim.aw) + self.comb += en.eq(en_counter != 0) + self.sync += [ + If(self._shoot.re, + en_counter.eq(self._dma.length) + ).Elif(lfsr.ce, + en_counter.eq(en_counter - 1) + ) + ] + + self.comb += [ + self._dma.trigger.eq(self._shoot.re), + self._dma.data.stb.eq(en), + lfsr.ce.eq(en & self._dma.data.ack), + self._dma.data.d.eq(lfsr.o) + ] + + def get_csrs(self): + return [self._magic, self._reset, self._shoot] + self._dma.get_csrs() class MemtestReader(Module): - def __init__(self, lasmim): - self._magic = CSRStatus(16) - self._reset = CSR() - self._error_count = CSRStatus(lasmim.aw) - self.submodules._dma = DMAReadController(dma_lasmi.Reader(lasmim), MODE_SINGLE_SHOT) - - ### - - self.comb += self._magic.status.eq(memtest_magic) - - lfsr = LFSR(lasmim.dw) - self.submodules += lfsr - self.comb += lfsr.reset.eq(self._reset.re) - - self.comb += [ - lfsr.ce.eq(self._dma.data.stb), - self._dma.data.ack.eq(1) - ] - err_cnt = self._error_count.status - self.sync += [ - If(self._reset.re, - err_cnt.eq(0) - ).Elif(self._dma.data.stb, - If(self._dma.data.d != lfsr.o, err_cnt.eq(err_cnt + 1)) - ) - ] - - def get_csrs(self): - return [self._magic, self._reset, self._error_count] + self._dma.get_csrs() + def __init__(self, lasmim): + self._magic = CSRStatus(16) + self._reset = CSR() + self._error_count = CSRStatus(lasmim.aw) + self.submodules._dma = DMAReadController(dma_lasmi.Reader(lasmim), MODE_SINGLE_SHOT) + + ### + + self.comb += self._magic.status.eq(memtest_magic) + + lfsr = LFSR(lasmim.dw) + self.submodules += lfsr + self.comb += lfsr.reset.eq(self._reset.re) + + self.comb += [ + lfsr.ce.eq(self._dma.data.stb), + self._dma.data.ack.eq(1) + ] + err_cnt = self._error_count.status + self.sync += [ + If(self._reset.re, + err_cnt.eq(0) + ).Elif(self._dma.data.stb, + If(self._dma.data.d != lfsr.o, err_cnt.eq(err_cnt + 1)) + ) + ] + + def get_csrs(self): + return [self._magic, self._reset, self._error_count] + self._dma.get_csrs() class _LFSRTB(Module): - def __init__(self, *args, **kwargs): - self.submodules.dut = LFSR(*args, **kwargs) - self.comb += self.dut.ce.eq(1) + def __init__(self, *args, **kwargs): + self.submodules.dut = LFSR(*args, **kwargs) + self.comb += self.dut.ce.eq(1) - def do_simulation(self, selfp): - print("{0:032x}".format(selfp.dut.o)) + def do_simulation(self, selfp): + print("{0:032x}".format(selfp.dut.o)) if __name__ == "__main__": - from migen.fhdl import verilog - from migen.sim.generic import run_simulation + from migen.fhdl import verilog + from migen.sim.generic import run_simulation - lfsr = LFSR(3, 4, [3, 2]) - print(verilog.convert(lfsr, ios={lfsr.ce, lfsr.reset, lfsr.o})) + lfsr = LFSR(3, 4, [3, 2]) + print(verilog.convert(lfsr, ios={lfsr.ce, lfsr.reset, lfsr.o})) - run_simulation(_LFSRTB(128), ncycles=20) + run_simulation(_LFSRTB(128), ncycles=20) diff --git a/misoclib/mem/sdram/frontend/wishbone2lasmi.py b/misoclib/mem/sdram/frontend/wishbone2lasmi.py index 657c7867..ea849733 100644 --- a/misoclib/mem/sdram/frontend/wishbone2lasmi.py +++ b/misoclib/mem/sdram/frontend/wishbone2lasmi.py @@ -7,161 +7,161 @@ from migen.genlib.record import Record, layout_len # cachesize (in 32-bit words) is the size of the data store, must be a power of 2 class WB2LASMI(Module, AutoCSR): - def __init__(self, cachesize, lasmim): - self._cachesize = CSRStatus(8, reset=log2_int(cachesize)) - self.wishbone = wishbone.Interface() - - ### - - data_width = flen(self.wishbone.dat_r) - if lasmim.dw > data_width and (lasmim.dw % data_width) != 0: - raise ValueError("LASMI data width must be a multiple of {dw}".format(dw=data_width)) - if lasmim.dw < data_width and (data_width % lasmim.dw) != 0: - raise ValueError("WISHBONE data width must be a multiple of {dw}".format(dw=lasmim.dw)) - - # Split address: - # TAG | LINE NUMBER | LINE OFFSET - offsetbits = log2_int(max(lasmim.dw//data_width, 1)) - addressbits = lasmim.aw + offsetbits - linebits = log2_int(cachesize) - offsetbits - tagbits = addressbits - linebits - wordbits = log2_int(max(data_width//lasmim.dw, 1)) - adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) - word = Signal(wordbits) if wordbits else None - - # Data memory - data_mem = Memory(lasmim.dw*2**wordbits, 2**linebits) - data_port = data_mem.get_port(write_capable=True, we_granularity=8) - self.specials += data_mem, data_port - - write_from_lasmi = Signal() - write_to_lasmi = Signal() - if adr_offset is None: - adr_offset_r = None - else: - adr_offset_r = Signal(offsetbits) - self.sync += adr_offset_r.eq(adr_offset) - - self.comb += [ - data_port.adr.eq(adr_line), - If(write_from_lasmi, - displacer(lasmim.dat_r, word, data_port.dat_w), - displacer(Replicate(1, lasmim.dw//8), word, data_port.we) - ).Else( - data_port.dat_w.eq(Replicate(self.wishbone.dat_w, max(lasmim.dw//data_width, 1))), - If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, - displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) - ) - ), - If(write_to_lasmi, - chooser(data_port.dat_r, word, lasmim.dat_w), - lasmim.dat_we.eq(2**(lasmim.dw//8)-1) - ), - chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) - ] - - - # Tag memory - tag_layout = [("tag", tagbits), ("dirty", 1)] - tag_mem = Memory(layout_len(tag_layout), 2**linebits) - tag_port = tag_mem.get_port(write_capable=True) - self.specials += tag_mem, tag_port - tag_do = Record(tag_layout) - tag_di = Record(tag_layout) - self.comb += [ - tag_do.raw_bits().eq(tag_port.dat_r), - tag_port.dat_w.eq(tag_di.raw_bits()) - ] - - self.comb += [ - tag_port.adr.eq(adr_line), - tag_di.tag.eq(adr_tag) - ] - if word is not None: - self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag)) - else: - self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag)) - - # Lasmim word computation, word_clr and word_inc will be simplified - # at synthesis when wordbits=0 - word_clr = Signal() - word_inc = Signal() - if word is not None: - self.sync += \ - If(word_clr, - word.eq(0), - ).Elif(word_inc, - word.eq(word+1) - ) - - def word_is_last(word): - if word is not None: - return word == 2**wordbits-1 - else: - return 1 - - # Control FSM - assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1) - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - - fsm.act("IDLE", - If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT")) - ) - fsm.act("TEST_HIT", - word_clr.eq(1), - If(tag_do.tag == adr_tag, - self.wishbone.ack.eq(1), - If(self.wishbone.we, - tag_di.dirty.eq(1), - tag_port.we.eq(1) - ), - NextState("IDLE") - ).Else( - If(tag_do.dirty, - NextState("EVICT_REQUEST") - ).Else( - NextState("REFILL_WRTAG") - ) - ) - ) - - fsm.act("EVICT_REQUEST", - lasmim.stb.eq(1), - lasmim.we.eq(1), - If(lasmim.req_ack, NextState("EVICT_DATA")) - ) - fsm.act("EVICT_DATA", - If(lasmim.dat_w_ack, - write_to_lasmi.eq(1), - word_inc.eq(1), - If(word_is_last(word), - NextState("REFILL_WRTAG"), - ).Else( - NextState("EVICT_REQUEST") - ) - ) - ) - - fsm.act("REFILL_WRTAG", - # Write the tag first to set the LASMI address - tag_port.we.eq(1), - word_clr.eq(1), - NextState("REFILL_REQUEST") - ) - fsm.act("REFILL_REQUEST", - lasmim.stb.eq(1), - If(lasmim.req_ack, NextState("REFILL_DATA")) - ) - fsm.act("REFILL_DATA", - If(lasmim.dat_r_ack, - write_from_lasmi.eq(1), - word_inc.eq(1), - If(word_is_last(word), - NextState("TEST_HIT"), - ).Else( - NextState("REFILL_REQUEST") - ) - ) - ) + def __init__(self, cachesize, lasmim): + self._cachesize = CSRStatus(8, reset=log2_int(cachesize)) + self.wishbone = wishbone.Interface() + + ### + + data_width = flen(self.wishbone.dat_r) + if lasmim.dw > data_width and (lasmim.dw % data_width) != 0: + raise ValueError("LASMI data width must be a multiple of {dw}".format(dw=data_width)) + if lasmim.dw < data_width and (data_width % lasmim.dw) != 0: + raise ValueError("WISHBONE data width must be a multiple of {dw}".format(dw=lasmim.dw)) + + # Split address: + # TAG | LINE NUMBER | LINE OFFSET + offsetbits = log2_int(max(lasmim.dw//data_width, 1)) + addressbits = lasmim.aw + offsetbits + linebits = log2_int(cachesize) - offsetbits + tagbits = addressbits - linebits + wordbits = log2_int(max(data_width//lasmim.dw, 1)) + adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) + word = Signal(wordbits) if wordbits else None + + # Data memory + data_mem = Memory(lasmim.dw*2**wordbits, 2**linebits) + data_port = data_mem.get_port(write_capable=True, we_granularity=8) + self.specials += data_mem, data_port + + write_from_lasmi = Signal() + write_to_lasmi = Signal() + if adr_offset is None: + adr_offset_r = None + else: + adr_offset_r = Signal(offsetbits) + self.sync += adr_offset_r.eq(adr_offset) + + self.comb += [ + data_port.adr.eq(adr_line), + If(write_from_lasmi, + displacer(lasmim.dat_r, word, data_port.dat_w), + displacer(Replicate(1, lasmim.dw//8), word, data_port.we) + ).Else( + data_port.dat_w.eq(Replicate(self.wishbone.dat_w, max(lasmim.dw//data_width, 1))), + If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, + displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) + ) + ), + If(write_to_lasmi, + chooser(data_port.dat_r, word, lasmim.dat_w), + lasmim.dat_we.eq(2**(lasmim.dw//8)-1) + ), + chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) + ] + + + # Tag memory + tag_layout = [("tag", tagbits), ("dirty", 1)] + tag_mem = Memory(layout_len(tag_layout), 2**linebits) + tag_port = tag_mem.get_port(write_capable=True) + self.specials += tag_mem, tag_port + tag_do = Record(tag_layout) + tag_di = Record(tag_layout) + self.comb += [ + tag_do.raw_bits().eq(tag_port.dat_r), + tag_port.dat_w.eq(tag_di.raw_bits()) + ] + + self.comb += [ + tag_port.adr.eq(adr_line), + tag_di.tag.eq(adr_tag) + ] + if word is not None: + self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag)) + else: + self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag)) + + # Lasmim word computation, word_clr and word_inc will be simplified + # at synthesis when wordbits=0 + word_clr = Signal() + word_inc = Signal() + if word is not None: + self.sync += \ + If(word_clr, + word.eq(0), + ).Elif(word_inc, + word.eq(word+1) + ) + + def word_is_last(word): + if word is not None: + return word == 2**wordbits-1 + else: + return 1 + + # Control FSM + assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1) + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + + fsm.act("IDLE", + If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT")) + ) + fsm.act("TEST_HIT", + word_clr.eq(1), + If(tag_do.tag == adr_tag, + self.wishbone.ack.eq(1), + If(self.wishbone.we, + tag_di.dirty.eq(1), + tag_port.we.eq(1) + ), + NextState("IDLE") + ).Else( + If(tag_do.dirty, + NextState("EVICT_REQUEST") + ).Else( + NextState("REFILL_WRTAG") + ) + ) + ) + + fsm.act("EVICT_REQUEST", + lasmim.stb.eq(1), + lasmim.we.eq(1), + If(lasmim.req_ack, NextState("EVICT_DATA")) + ) + fsm.act("EVICT_DATA", + If(lasmim.dat_w_ack, + write_to_lasmi.eq(1), + word_inc.eq(1), + If(word_is_last(word), + NextState("REFILL_WRTAG"), + ).Else( + NextState("EVICT_REQUEST") + ) + ) + ) + + fsm.act("REFILL_WRTAG", + # Write the tag first to set the LASMI address + tag_port.we.eq(1), + word_clr.eq(1), + NextState("REFILL_REQUEST") + ) + fsm.act("REFILL_REQUEST", + lasmim.stb.eq(1), + If(lasmim.req_ack, NextState("REFILL_DATA")) + ) + fsm.act("REFILL_DATA", + If(lasmim.dat_r_ack, + write_from_lasmi.eq(1), + word_inc.eq(1), + If(word_is_last(word), + NextState("TEST_HIT"), + ).Else( + NextState("REFILL_REQUEST") + ) + ) + ) diff --git a/misoclib/mem/sdram/module.py b/misoclib/mem/sdram/module.py index af807b86..39b3fa23 100644 --- a/misoclib/mem/sdram/module.py +++ b/misoclib/mem/sdram/module.py @@ -20,158 +20,158 @@ from migen.fhdl.std import * from misoclib.mem import sdram class SDRAMModule: - def __init__(self, clk_freq, memtype, geom_settings, timing_settings): - self.clk_freq = clk_freq - self.memtype = memtype - self.geom_settings = sdram.GeomSettings( - bankbits=log2_int(geom_settings["nbanks"]), - rowbits=log2_int(geom_settings["nrows"]), - colbits=log2_int(geom_settings["ncols"]), - ) - self.timing_settings = sdram.TimingSettings( - tRP=self.ns(timing_settings["tRP"]), - tRCD=self.ns(timing_settings["tRCD"]), - tWR=self.ns(timing_settings["tWR"]), - tWTR=timing_settings["tWTR"], - tREFI=self.ns(timing_settings["tREFI"], False), - tRFC=self.ns(timing_settings["tRFC"]) - ) + def __init__(self, clk_freq, memtype, geom_settings, timing_settings): + self.clk_freq = clk_freq + self.memtype = memtype + self.geom_settings = sdram.GeomSettings( + bankbits=log2_int(geom_settings["nbanks"]), + rowbits=log2_int(geom_settings["nrows"]), + colbits=log2_int(geom_settings["ncols"]), + ) + self.timing_settings = sdram.TimingSettings( + tRP=self.ns(timing_settings["tRP"]), + tRCD=self.ns(timing_settings["tRCD"]), + tWR=self.ns(timing_settings["tWR"]), + tWTR=timing_settings["tWTR"], + tREFI=self.ns(timing_settings["tREFI"], False), + tRFC=self.ns(timing_settings["tRFC"]) + ) - def ns(self, t, margin=True): - clk_period_ns = 1000000000/self.clk_freq - if margin: - t += clk_period_ns/2 - return ceil(t/clk_period_ns) + def ns(self, t, margin=True): + clk_period_ns = 1000000000/self.clk_freq + if margin: + t += clk_period_ns/2 + return ceil(t/clk_period_ns) # SDR class IS42S16160(SDRAMModule): - geom_settings = { - "nbanks": 4, - "nrows": 8192, - "ncols": 512 - } - # Note: timings for -7 speedgrade (add support for others speedgrades) - timing_settings = { - "tRP": 20, - "tRCD": 20, - "tWR": 20, - "tWTR": 2, - "tREFI": 64*1000*1000/8192, - "tRFC": 70 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "SDR", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 4, + "nrows": 8192, + "ncols": 512 + } + # Note: timings for -7 speedgrade (add support for others speedgrades) + timing_settings = { + "tRP": 20, + "tRCD": 20, + "tWR": 20, + "tWTR": 2, + "tREFI": 64*1000*1000/8192, + "tRFC": 70 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "SDR", self.geom_settings, + self.timing_settings) class MT48LC4M16(SDRAMModule): - geom_settings = { - "nbanks": 4, - "nrows": 4096, - "ncols": 256 - } - timing_settings = { - "tRP": 15, - "tRCD": 15, - "tWR": 14, - "tWTR": 2, - "tREFI": 64*1000*1000/4096, - "tRFC": 66 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "SDR", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 4, + "nrows": 4096, + "ncols": 256 + } + timing_settings = { + "tRP": 15, + "tRCD": 15, + "tWR": 14, + "tWTR": 2, + "tREFI": 64*1000*1000/4096, + "tRFC": 66 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "SDR", self.geom_settings, + self.timing_settings) class AS4C16M16(SDRAMModule): - geom_settings = { - "nbanks": 4, - "nrows": 8192, - "ncols": 512 - } - # Note: timings for -6 speedgrade (add support for others speedgrades) - timing_settings = { - "tRP": 18, - "tRCD": 18, - "tWR": 12, - "tWTR": 2, - "tREFI": 64*1000*1000/8192, - "tRFC": 60 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "SDR", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 4, + "nrows": 8192, + "ncols": 512 + } + # Note: timings for -6 speedgrade (add support for others speedgrades) + timing_settings = { + "tRP": 18, + "tRCD": 18, + "tWR": 12, + "tWTR": 2, + "tREFI": 64*1000*1000/8192, + "tRFC": 60 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "SDR", self.geom_settings, + self.timing_settings) # DDR class MT46V32M16(SDRAMModule): - geom_settings = { - "nbanks": 4, - "nrows": 8192, - "ncols": 1024 - } - timing_settings = { - "tRP": 15, - "tRCD": 15, - "tWR": 15, - "tWTR": 2, - "tREFI": 64*1000*1000/8192, - "tRFC": 70 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "DDR", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 4, + "nrows": 8192, + "ncols": 1024 + } + timing_settings = { + "tRP": 15, + "tRCD": 15, + "tWR": 15, + "tWTR": 2, + "tREFI": 64*1000*1000/8192, + "tRFC": 70 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "DDR", self.geom_settings, + self.timing_settings) # LPDDR class MT46H32M16(SDRAMModule): - geom_settings = { - "nbanks": 4, - "nrows": 8192, - "ncols": 1024 - } - timing_settings = { - "tRP": 15, - "tRCD": 15, - "tWR": 15, - "tWTR": 2, - "tREFI": 64*1000*1000/8192, - "tRFC": 72 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "LPDDR", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 4, + "nrows": 8192, + "ncols": 1024 + } + timing_settings = { + "tRP": 15, + "tRCD": 15, + "tWR": 15, + "tWTR": 2, + "tREFI": 64*1000*1000/8192, + "tRFC": 72 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "LPDDR", self.geom_settings, + self.timing_settings) # DDR2 class MT47H128M8(SDRAMModule): - geom_settings = { - "nbanks": 8, - "nrows": 16384, - "ncols": 1024 - } - timing_settings = { - "tRP": 15, - "tRCD": 15, - "tWR": 15, - "tWTR": 2, - "tREFI": 7800, - "tRFC": 127.5 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "DDR2", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 8, + "nrows": 16384, + "ncols": 1024 + } + timing_settings = { + "tRP": 15, + "tRCD": 15, + "tWR": 15, + "tWTR": 2, + "tREFI": 7800, + "tRFC": 127.5 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "DDR2", self.geom_settings, + self.timing_settings) # DDR3 class MT8JTF12864(SDRAMModule): - geom_settings = { - "nbanks": 8, - "nrows": 16384, - "ncols": 1024 - } - timing_settings = { - "tRP": 15, - "tRCD": 15, - "tWR": 15, - "tWTR": 2, - "tREFI": 7800, - "tRFC": 70 - } - def __init__(self, clk_freq): - SDRAMModule.__init__(self, clk_freq, "DDR3", self.geom_settings, - self.timing_settings) + geom_settings = { + "nbanks": 8, + "nrows": 16384, + "ncols": 1024 + } + timing_settings = { + "tRP": 15, + "tRCD": 15, + "tWR": 15, + "tWTR": 2, + "tREFI": 7800, + "tRFC": 70 + } + def __init__(self, clk_freq): + SDRAMModule.__init__(self, clk_freq, "DDR3", self.geom_settings, + self.timing_settings) diff --git a/misoclib/mem/sdram/phy/dfi.py b/misoclib/mem/sdram/phy/dfi.py index fc025b4c..158cfffc 100644 --- a/misoclib/mem/sdram/phy/dfi.py +++ b/misoclib/mem/sdram/phy/dfi.py @@ -2,66 +2,66 @@ from migen.fhdl.std import * from migen.genlib.record import * def phase_cmd_description(addressbits, bankbits): - return [ - ("address", addressbits, DIR_M_TO_S), - ("bank", bankbits, DIR_M_TO_S), - ("cas_n", 1, DIR_M_TO_S), - ("cs_n", 1, DIR_M_TO_S), - ("ras_n", 1, DIR_M_TO_S), - ("we_n", 1, DIR_M_TO_S), - ("cke", 1, DIR_M_TO_S), - ("odt", 1, DIR_M_TO_S), - ("reset_n", 1, DIR_M_TO_S) - ] + return [ + ("address", addressbits, DIR_M_TO_S), + ("bank", bankbits, DIR_M_TO_S), + ("cas_n", 1, DIR_M_TO_S), + ("cs_n", 1, DIR_M_TO_S), + ("ras_n", 1, DIR_M_TO_S), + ("we_n", 1, DIR_M_TO_S), + ("cke", 1, DIR_M_TO_S), + ("odt", 1, DIR_M_TO_S), + ("reset_n", 1, DIR_M_TO_S) + ] def phase_wrdata_description(databits): - return [ - ("wrdata", databits, DIR_M_TO_S), - ("wrdata_en", 1, DIR_M_TO_S), - ("wrdata_mask", databits//8, DIR_M_TO_S) - ] + return [ + ("wrdata", databits, DIR_M_TO_S), + ("wrdata_en", 1, DIR_M_TO_S), + ("wrdata_mask", databits//8, DIR_M_TO_S) + ] def phase_rddata_description(databits): - return [ - ("rddata_en", 1, DIR_M_TO_S), - ("rddata", databits, DIR_S_TO_M), - ("rddata_valid", 1, DIR_S_TO_M) - ] + return [ + ("rddata_en", 1, DIR_M_TO_S), + ("rddata", databits, DIR_S_TO_M), + ("rddata_valid", 1, DIR_S_TO_M) + ] def phase_description(addressbits, bankbits, databits): - r = phase_cmd_description(addressbits, bankbits) - r += phase_wrdata_description(databits) - r += phase_rddata_description(databits) - return r + r = phase_cmd_description(addressbits, bankbits) + r += phase_wrdata_description(databits) + r += phase_rddata_description(databits) + return r class Interface(Record): - def __init__(self, addressbits, bankbits, databits, nphases=1): - layout = [("p"+str(i), phase_description(addressbits, bankbits, databits)) for i in range(nphases)] - Record.__init__(self, layout) - self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)] - for p in self.phases: - p.cas_n.reset = 1 - p.cs_n.reset = 1 - p.ras_n.reset = 1 - p.we_n.reset = 1 + def __init__(self, addressbits, bankbits, databits, nphases=1): + layout = [("p"+str(i), phase_description(addressbits, bankbits, databits)) for i in range(nphases)] + Record.__init__(self, layout) + self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)] + for p in self.phases: + p.cas_n.reset = 1 + p.cs_n.reset = 1 + p.ras_n.reset = 1 + p.we_n.reset = 1 - # Returns pairs (DFI-mandated signal name, Migen signal object) - def get_standard_names(self, m2s=True, s2m=True): - r = [] - add_suffix = len(self.phases) > 1 - for n, phase in enumerate(self.phases): - for field, size, direction in phase.layout: - if (m2s and direction == DIR_M_TO_S) or (s2m and direction == DIR_S_TO_M): - if add_suffix: - if direction == DIR_M_TO_S: - suffix = "_p" + str(n) - else: - suffix = "_w" + str(n) - else: - suffix = "" - r.append(("dfi_" + field + suffix, getattr(phase, field))) - return r + # Returns pairs (DFI-mandated signal name, Migen signal object) + def get_standard_names(self, m2s=True, s2m=True): + r = [] + add_suffix = len(self.phases) > 1 + for n, phase in enumerate(self.phases): + for field, size, direction in phase.layout: + if (m2s and direction == DIR_M_TO_S) or (s2m and direction == DIR_S_TO_M): + if add_suffix: + if direction == DIR_M_TO_S: + suffix = "_p" + str(n) + else: + suffix = "_w" + str(n) + else: + suffix = "" + r.append(("dfi_" + field + suffix, getattr(phase, field))) + return r class Interconnect(Module): - def __init__(self, master, slave): - self.comb += master.connect(slave) + def __init__(self, master, slave): + self.comb += master.connect(slave) diff --git a/misoclib/mem/sdram/phy/dfii.py b/misoclib/mem/sdram/phy/dfii.py index f5f5b09e..9f1af130 100644 --- a/misoclib/mem/sdram/phy/dfii.py +++ b/misoclib/mem/sdram/phy/dfii.py @@ -4,55 +4,55 @@ from migen.bank.description import * from misoclib.mem.sdram.phy import dfi class PhaseInjector(Module, AutoCSR): - def __init__(self, phase): - self._command = CSRStorage(6) # cs, we, cas, ras, wren, rden - self._command_issue = CSR() - self._address = CSRStorage(flen(phase.address)) - self._baddress = CSRStorage(flen(phase.bank)) - self._wrdata = CSRStorage(flen(phase.wrdata)) - self._rddata = CSRStatus(flen(phase.rddata)) - - ### - - self.comb += [ - If(self._command_issue.re, - phase.cs_n.eq(~self._command.storage[0]), - phase.we_n.eq(~self._command.storage[1]), - phase.cas_n.eq(~self._command.storage[2]), - phase.ras_n.eq(~self._command.storage[3]) - ).Else( - phase.cs_n.eq(1), - phase.we_n.eq(1), - phase.cas_n.eq(1), - phase.ras_n.eq(1) - ), - phase.address.eq(self._address.storage), - phase.bank.eq(self._baddress.storage), - phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]), - phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]), - phase.wrdata.eq(self._wrdata.storage), - phase.wrdata_mask.eq(0) - ] - self.sync += If(phase.rddata_valid, self._rddata.status.eq(phase.rddata)) + def __init__(self, phase): + self._command = CSRStorage(6) # cs, we, cas, ras, wren, rden + self._command_issue = CSR() + self._address = CSRStorage(flen(phase.address)) + self._baddress = CSRStorage(flen(phase.bank)) + self._wrdata = CSRStorage(flen(phase.wrdata)) + self._rddata = CSRStatus(flen(phase.rddata)) + + ### + + self.comb += [ + If(self._command_issue.re, + phase.cs_n.eq(~self._command.storage[0]), + phase.we_n.eq(~self._command.storage[1]), + phase.cas_n.eq(~self._command.storage[2]), + phase.ras_n.eq(~self._command.storage[3]) + ).Else( + phase.cs_n.eq(1), + phase.we_n.eq(1), + phase.cas_n.eq(1), + phase.ras_n.eq(1) + ), + phase.address.eq(self._address.storage), + phase.bank.eq(self._baddress.storage), + phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]), + phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]), + phase.wrdata.eq(self._wrdata.storage), + phase.wrdata_mask.eq(0) + ] + self.sync += If(phase.rddata_valid, self._rddata.status.eq(phase.rddata)) class DFIInjector(Module, AutoCSR): - def __init__(self, addressbits, bankbits, databits, nphases=1): - inti = dfi.Interface(addressbits, bankbits, databits, nphases) - self.slave = dfi.Interface(addressbits, bankbits, databits, nphases) - self.master = dfi.Interface(addressbits, bankbits, databits, nphases) - - self._control = CSRStorage(4) # sel, cke, odt, reset_n - - for n, phase in enumerate(inti.phases): - setattr(self.submodules, "pi" + str(n), PhaseInjector(phase)) - - ### - - self.comb += If(self._control.storage[0], - self.slave.connect(self.master) - ).Else( - inti.connect(self.master) - ) - self.comb += [phase.cke.eq(self._control.storage[1]) for phase in inti.phases] - self.comb += [phase.odt.eq(self._control.storage[2]) for phase in inti.phases if hasattr(phase, "odt")] - self.comb += [phase.reset_n.eq(self._control.storage[3]) for phase in inti.phases if hasattr(phase, "reset_n")] + def __init__(self, addressbits, bankbits, databits, nphases=1): + inti = dfi.Interface(addressbits, bankbits, databits, nphases) + self.slave = dfi.Interface(addressbits, bankbits, databits, nphases) + self.master = dfi.Interface(addressbits, bankbits, databits, nphases) + + self._control = CSRStorage(4) # sel, cke, odt, reset_n + + for n, phase in enumerate(inti.phases): + setattr(self.submodules, "pi" + str(n), PhaseInjector(phase)) + + ### + + self.comb += If(self._control.storage[0], + self.slave.connect(self.master) + ).Else( + inti.connect(self.master) + ) + self.comb += [phase.cke.eq(self._control.storage[1]) for phase in inti.phases] + self.comb += [phase.odt.eq(self._control.storage[2]) for phase in inti.phases if hasattr(phase, "odt")] + self.comb += [phase.reset_n.eq(self._control.storage[3]) for phase in inti.phases if hasattr(phase, "reset_n")] diff --git a/misoclib/mem/sdram/phy/gensdrphy.py b/misoclib/mem/sdram/phy/gensdrphy.py index 12a4f30c..10b348ff 100644 --- a/misoclib/mem/sdram/phy/gensdrphy.py +++ b/misoclib/mem/sdram/phy/gensdrphy.py @@ -29,67 +29,67 @@ from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class GENSDRPHY(Module): - def __init__(self, pads, module): - addressbits = flen(pads.a) - bankbits = flen(pads.ba) - databits = flen(pads.dq) + def __init__(self, pads, module): + addressbits = flen(pads.a) + bankbits = flen(pads.ba) + databits = flen(pads.dq) - self.settings = sdram.PhySettings( - memtype=module.memtype, - dfi_databits=databits, - nphases=1, - rdphase=0, - wrphase=0, - rdcmdphase=0, - wrcmdphase=0, - cl=2, - read_latency=4, - write_latency=0 - ) - self.module = module + self.settings = sdram.PhySettings( + memtype=module.memtype, + dfi_databits=databits, + nphases=1, + rdphase=0, + wrphase=0, + rdcmdphase=0, + wrcmdphase=0, + cl=2, + read_latency=4, + write_latency=0 + ) + self.module = module - self.dfi = Interface(addressbits, bankbits, databits) + self.dfi = Interface(addressbits, bankbits, databits) - ### + ### - # - # Command/address - # - self.sync += [ - pads.a.eq(self.dfi.p0.address), - pads.ba.eq(self.dfi.p0.bank), - pads.cke.eq(self.dfi.p0.cke), - pads.cas_n.eq(self.dfi.p0.cas_n), - pads.ras_n.eq(self.dfi.p0.ras_n), - pads.we_n.eq(self.dfi.p0.we_n) - ] - if hasattr(pads, "cs_n"): - self.sync += pads.cs_n.eq(self.dfi.p0.cs_n) + # + # Command/address + # + self.sync += [ + pads.a.eq(self.dfi.p0.address), + pads.ba.eq(self.dfi.p0.bank), + pads.cke.eq(self.dfi.p0.cke), + pads.cas_n.eq(self.dfi.p0.cas_n), + pads.ras_n.eq(self.dfi.p0.ras_n), + pads.we_n.eq(self.dfi.p0.we_n) + ] + if hasattr(pads, "cs_n"): + self.sync += pads.cs_n.eq(self.dfi.p0.cs_n) - # - # DQ/DQS/DM data - # - sd_dq_out = Signal(databits) - drive_dq = Signal() - self.sync += sd_dq_out.eq(self.dfi.p0.wrdata) - self.specials += Tristate(pads.dq, sd_dq_out, drive_dq) - self.sync += \ - If(self.dfi.p0.wrdata_en, - pads.dm.eq(self.dfi.p0.wrdata_mask) - ).Else( - pads.dm.eq(0) - ) - sd_dq_in_ps = Signal(databits) - self.sync.sys_ps += sd_dq_in_ps.eq(pads.dq) - self.sync += self.dfi.p0.rddata.eq(sd_dq_in_ps) + # + # DQ/DQS/DM data + # + sd_dq_out = Signal(databits) + drive_dq = Signal() + self.sync += sd_dq_out.eq(self.dfi.p0.wrdata) + self.specials += Tristate(pads.dq, sd_dq_out, drive_dq) + self.sync += \ + If(self.dfi.p0.wrdata_en, + pads.dm.eq(self.dfi.p0.wrdata_mask) + ).Else( + pads.dm.eq(0) + ) + sd_dq_in_ps = Signal(databits) + self.sync.sys_ps += sd_dq_in_ps.eq(pads.dq) + self.sync += self.dfi.p0.rddata.eq(sd_dq_in_ps) - # - # DQ/DM control - # - d_dfi_wrdata_en = Signal() - self.sync += d_dfi_wrdata_en.eq(self.dfi.p0.wrdata_en) - self.comb += drive_dq.eq(d_dfi_wrdata_en) + # + # DQ/DM control + # + d_dfi_wrdata_en = Signal() + self.sync += d_dfi_wrdata_en.eq(self.dfi.p0.wrdata_en) + self.comb += drive_dq.eq(d_dfi_wrdata_en) - rddata_sr = Signal(4) - self.comb += self.dfi.p0.rddata_valid.eq(rddata_sr[3]) - self.sync += rddata_sr.eq(Cat(self.dfi.p0.rddata_en, rddata_sr[:3])) + rddata_sr = Signal(4) + self.comb += self.dfi.p0.rddata_valid.eq(rddata_sr[3]) + self.sync += rddata_sr.eq(Cat(self.dfi.p0.rddata_en, rddata_sr[:3])) diff --git a/misoclib/mem/sdram/phy/initsequence.py b/misoclib/mem/sdram/phy/initsequence.py index 09e6ef3a..1f103d51 100644 --- a/misoclib/mem/sdram/phy/initsequence.py +++ b/misoclib/mem/sdram/phy/initsequence.py @@ -1,26 +1,26 @@ from migen.fhdl.std import log2_int def get_sdram_phy_header(sdram_phy_settings): - r = "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n" - r += "#include \n#include \n#include \n\n" + r = "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n" + r += "#include \n#include \n#include \n\n" - nphases = sdram_phy_settings.nphases - r += "#define DFII_NPHASES "+str(nphases)+"\n\n" + nphases = sdram_phy_settings.nphases + r += "#define DFII_NPHASES "+str(nphases)+"\n\n" - r += "static void cdelay(int i);\n" + r += "static void cdelay(int i);\n" - # commands_px functions - for n in range(nphases): - r += """ + # commands_px functions + for n in range(nphases): + r += """ static void command_p{n}(int cmd) {{ - sdram_dfii_pi{n}_command_write(cmd); - sdram_dfii_pi{n}_command_issue_write(1); + sdram_dfii_pi{n}_command_write(cmd); + sdram_dfii_pi{n}_command_issue_write(1); }}""".format(n=str(n)) - r += "\n\n" + r += "\n\n" - # rd/wr access macros - r += """ + # rd/wr access macros + r += """ #define sdram_dfii_pird_address_write(X) sdram_dfii_pi{rdphase}_address_write(X) #define sdram_dfii_piwr_address_write(X) sdram_dfii_pi{wrphase}_address_write(X) @@ -30,196 +30,196 @@ static void command_p{n}(int cmd) #define command_prd(X) command_p{rdphase}(X) #define command_pwr(X) command_p{wrphase}(X) """.format(rdphase=str(sdram_phy_settings.rdphase), wrphase=str(sdram_phy_settings.wrphase)) - r +="\n" - - # - # sdrrd/sdrwr functions utilities - # - r += "#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE\n" - sdram_dfii_pix_wrdata_addr = [] - for n in range(nphases): - sdram_dfii_pix_wrdata_addr.append("CSR_SDRAM_DFII_PI{n}_WRDATA_ADDR".format(n=n)) - r += """ + r +="\n" + + # + # sdrrd/sdrwr functions utilities + # + r += "#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE\n" + sdram_dfii_pix_wrdata_addr = [] + for n in range(nphases): + sdram_dfii_pix_wrdata_addr.append("CSR_SDRAM_DFII_PI{n}_WRDATA_ADDR".format(n=n)) + r += """ const unsigned int sdram_dfii_pix_wrdata_addr[{n}] = {{ - {sdram_dfii_pix_wrdata_addr} + {sdram_dfii_pix_wrdata_addr} }}; """.format(n=nphases, sdram_dfii_pix_wrdata_addr=",\n\t".join(sdram_dfii_pix_wrdata_addr)) - sdram_dfii_pix_rddata_addr = [] - for n in range(nphases): - sdram_dfii_pix_rddata_addr.append("CSR_SDRAM_DFII_PI{n}_RDDATA_ADDR".format(n=n)) - r += """ + sdram_dfii_pix_rddata_addr = [] + for n in range(nphases): + sdram_dfii_pix_rddata_addr.append("CSR_SDRAM_DFII_PI{n}_RDDATA_ADDR".format(n=n)) + r += """ const unsigned int sdram_dfii_pix_rddata_addr[{n}] = {{ - {sdram_dfii_pix_rddata_addr} + {sdram_dfii_pix_rddata_addr} }}; """.format(n=nphases, sdram_dfii_pix_rddata_addr=",\n\t".join(sdram_dfii_pix_rddata_addr)) - r +="\n" - - # init sequence - cmds = { - "PRECHARGE_ALL" : "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS", - "MODE_REGISTER" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS", - "AUTO_REFRESH" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS", - "UNRESET" : "DFII_CONTROL_ODT|DFII_CONTROL_RESET_N", - "CKE" : "DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N" - } - - cl = sdram_phy_settings.cl - - if sdram_phy_settings.memtype == "SDR": - bl = sdram_phy_settings.nphases - mr = log2_int(bl) + (cl << 4) - reset_dll = 1 << 8 - - init_sequence = [ - ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) - ] - - elif sdram_phy_settings.memtype == "DDR": - bl = 2*sdram_phy_settings.nphases - mr = log2_int(bl) + (cl << 4) - emr = 0 - reset_dll = 1 << 8 - - init_sequence = [ - ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0), - ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) - ] - - elif sdram_phy_settings.memtype == "LPDDR": - bl = 2*sdram_phy_settings.nphases - mr = log2_int(bl) + (cl << 4) - emr = 0 - reset_dll = 1 << 8 - - init_sequence = [ - ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Load Extended Mode Register", emr, 2, cmds["MODE_REGISTER"], 0), - ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) - ] - - elif sdram_phy_settings.memtype == "DDR2": - bl = 2*sdram_phy_settings.nphases - wr = 2 - mr = log2_int(bl) + (cl << 4) + (wr << 9) - emr = 0 - emr2 = 0 - emr3 = 0 - reset_dll = 1 << 8 - ocd = 7 << 7 - - init_sequence = [ - ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Load Extended Mode Register 3", emr3, 3, cmds["MODE_REGISTER"], 0), - ("Load Extended Mode Register 2", emr2, 2, cmds["MODE_REGISTER"], 0), - ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0), - ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), - ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), - ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200), - ("Load Extended Mode Register / OCD Default", emr+ocd, 1, cmds["MODE_REGISTER"], 0), - ("Load Extended Mode Register / OCD Exit", emr, 1, cmds["MODE_REGISTER"], 0), - ] - elif sdram_phy_settings.memtype == "DDR3": - bl = 2*sdram_phy_settings.nphases - if bl != 8: - raise NotImplementedError("DDR3 PHY header generator only supports BL of 8") - - def format_mr0(cl, wr, dll_reset): - cl_to_mr0 = { - 5 : 0b0010, - 6 : 0b0100, - 7 : 0b0110, - 8 : 0b1000, - 9 : 0b1010, - 10: 0b1100, - 11: 0b1110, - 12: 0b0001, - 13: 0b0011, - 14: 0b0101 - } - wr_to_mr0 = { - 16: 0b000, - 5 : 0b001, - 6 : 0b010, - 7 : 0b011, - 8 : 0b100, - 10: 0b101, - 12: 0b110, - 14: 0b111 - } - mr0 = (cl_to_mr0[cl] & 1) << 2 - mr0 |= ((cl_to_mr0[cl] >> 1) & 0b111) << 4 - mr0 |= dll_reset << 8 - mr0 |= wr_to_mr0[wr] << 9 - return mr0 - - def format_mr1(output_drive_strength, rtt_nom): - mr1 = ((output_drive_strength >> 0) & 1) << 1 - mr1 |= ((output_drive_strength >> 1) & 1) << 5 - mr1 |= ((rtt_nom >> 0) & 1) << 2 - mr1 |= ((rtt_nom >> 1) & 1) << 6 - mr1 |= ((rtt_nom >> 2) & 1) << 9 - return mr1 - - def format_mr2(cwl, rtt_wr): - mr2 = (cwl-5) << 3 - mr2 |= rtt_wr << 9 - return mr2 - - mr0 = format_mr0(cl, 8, 1) # wr=8 FIXME: this should be ceiling(tWR/tCK) - mr1 = format_mr1(1, 1) # Output Drive Strength RZQ/7 (34 ohm) / Rtt RZQ/4 (60 ohm) - mr2 = format_mr2(sdram_phy_settings.cwl, 2) # Rtt(WR) RZQ/4 - mr3 = 0 - - init_sequence = [ - ("Release reset", 0x0000, 0, cmds["UNRESET"], 50000), - ("Bring CKE high", 0x0000, 0, cmds["CKE"], 10000), - ("Load Mode Register 2", mr2, 2, cmds["MODE_REGISTER"], 0), - ("Load Mode Register 3", mr3, 3, cmds["MODE_REGISTER"], 0), - ("Load Mode Register 1", mr1, 1, cmds["MODE_REGISTER"], 0), - ("Load Mode Register 0, CL={0:d}, BL={1:d}".format(cl, bl), mr0, 0, cmds["MODE_REGISTER"], 200), - ("ZQ Calibration", 0x0400, 0, "DFII_COMMAND_WE|DFII_COMMAND_CS", 200), - ] - - # the value of MR1 needs to be modified during write leveling - r += "#define DDR3_MR1 {}\n\n".format(mr1) - else: - raise NotImplementedError("Unsupported memory type: "+sdram_phy_settings.memtype) - - r += "static void init_sequence(void)\n{\n" - for comment, a, ba, cmd, delay in init_sequence: - r += "\t/* {0} */\n".format(comment) - r += "\tsdram_dfii_pi0_address_write({0:#x});\n".format(a) - r += "\tsdram_dfii_pi0_baddress_write({0:d});\n".format(ba) - if cmd[:12] == "DFII_CONTROL": - r += "\tsdram_dfii_control_write({0});\n".format(cmd) - else: - r += "\tcommand_p0({0});\n".format(cmd) - if delay: - r += "\tcdelay({0:d});\n".format(delay) - r += "\n" - r += "}\n" - - r += "#endif\n" - - return r + r +="\n" + + # init sequence + cmds = { + "PRECHARGE_ALL" : "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS", + "MODE_REGISTER" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS", + "AUTO_REFRESH" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS", + "UNRESET" : "DFII_CONTROL_ODT|DFII_CONTROL_RESET_N", + "CKE" : "DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N" + } + + cl = sdram_phy_settings.cl + + if sdram_phy_settings.memtype == "SDR": + bl = sdram_phy_settings.nphases + mr = log2_int(bl) + (cl << 4) + reset_dll = 1 << 8 + + init_sequence = [ + ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) + ] + + elif sdram_phy_settings.memtype == "DDR": + bl = 2*sdram_phy_settings.nphases + mr = log2_int(bl) + (cl << 4) + emr = 0 + reset_dll = 1 << 8 + + init_sequence = [ + ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0), + ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) + ] + + elif sdram_phy_settings.memtype == "LPDDR": + bl = 2*sdram_phy_settings.nphases + mr = log2_int(bl) + (cl << 4) + emr = 0 + reset_dll = 1 << 8 + + init_sequence = [ + ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Load Extended Mode Register", emr, 2, cmds["MODE_REGISTER"], 0), + ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200) + ] + + elif sdram_phy_settings.memtype == "DDR2": + bl = 2*sdram_phy_settings.nphases + wr = 2 + mr = log2_int(bl) + (cl << 4) + (wr << 9) + emr = 0 + emr2 = 0 + emr3 = 0 + reset_dll = 1 << 8 + ocd = 7 << 7 + + init_sequence = [ + ("Bring CKE high", 0x0000, 0, cmds["CKE"], 20000), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Load Extended Mode Register 3", emr3, 3, cmds["MODE_REGISTER"], 0), + ("Load Extended Mode Register 2", emr2, 2, cmds["MODE_REGISTER"], 0), + ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0), + ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200), + ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4), + ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200), + ("Load Extended Mode Register / OCD Default", emr+ocd, 1, cmds["MODE_REGISTER"], 0), + ("Load Extended Mode Register / OCD Exit", emr, 1, cmds["MODE_REGISTER"], 0), + ] + elif sdram_phy_settings.memtype == "DDR3": + bl = 2*sdram_phy_settings.nphases + if bl != 8: + raise NotImplementedError("DDR3 PHY header generator only supports BL of 8") + + def format_mr0(cl, wr, dll_reset): + cl_to_mr0 = { + 5 : 0b0010, + 6 : 0b0100, + 7 : 0b0110, + 8 : 0b1000, + 9 : 0b1010, + 10: 0b1100, + 11: 0b1110, + 12: 0b0001, + 13: 0b0011, + 14: 0b0101 + } + wr_to_mr0 = { + 16: 0b000, + 5 : 0b001, + 6 : 0b010, + 7 : 0b011, + 8 : 0b100, + 10: 0b101, + 12: 0b110, + 14: 0b111 + } + mr0 = (cl_to_mr0[cl] & 1) << 2 + mr0 |= ((cl_to_mr0[cl] >> 1) & 0b111) << 4 + mr0 |= dll_reset << 8 + mr0 |= wr_to_mr0[wr] << 9 + return mr0 + + def format_mr1(output_drive_strength, rtt_nom): + mr1 = ((output_drive_strength >> 0) & 1) << 1 + mr1 |= ((output_drive_strength >> 1) & 1) << 5 + mr1 |= ((rtt_nom >> 0) & 1) << 2 + mr1 |= ((rtt_nom >> 1) & 1) << 6 + mr1 |= ((rtt_nom >> 2) & 1) << 9 + return mr1 + + def format_mr2(cwl, rtt_wr): + mr2 = (cwl-5) << 3 + mr2 |= rtt_wr << 9 + return mr2 + + mr0 = format_mr0(cl, 8, 1) # wr=8 FIXME: this should be ceiling(tWR/tCK) + mr1 = format_mr1(1, 1) # Output Drive Strength RZQ/7 (34 ohm) / Rtt RZQ/4 (60 ohm) + mr2 = format_mr2(sdram_phy_settings.cwl, 2) # Rtt(WR) RZQ/4 + mr3 = 0 + + init_sequence = [ + ("Release reset", 0x0000, 0, cmds["UNRESET"], 50000), + ("Bring CKE high", 0x0000, 0, cmds["CKE"], 10000), + ("Load Mode Register 2", mr2, 2, cmds["MODE_REGISTER"], 0), + ("Load Mode Register 3", mr3, 3, cmds["MODE_REGISTER"], 0), + ("Load Mode Register 1", mr1, 1, cmds["MODE_REGISTER"], 0), + ("Load Mode Register 0, CL={0:d}, BL={1:d}".format(cl, bl), mr0, 0, cmds["MODE_REGISTER"], 200), + ("ZQ Calibration", 0x0400, 0, "DFII_COMMAND_WE|DFII_COMMAND_CS", 200), + ] + + # the value of MR1 needs to be modified during write leveling + r += "#define DDR3_MR1 {}\n\n".format(mr1) + else: + raise NotImplementedError("Unsupported memory type: "+sdram_phy_settings.memtype) + + r += "static void init_sequence(void)\n{\n" + for comment, a, ba, cmd, delay in init_sequence: + r += "\t/* {0} */\n".format(comment) + r += "\tsdram_dfii_pi0_address_write({0:#x});\n".format(a) + r += "\tsdram_dfii_pi0_baddress_write({0:d});\n".format(ba) + if cmd[:12] == "DFII_CONTROL": + r += "\tsdram_dfii_control_write({0});\n".format(cmd) + else: + r += "\tcommand_p0({0});\n".format(cmd) + if delay: + r += "\tcdelay({0:d});\n".format(delay) + r += "\n" + r += "}\n" + + r += "#endif\n" + + return r diff --git a/misoclib/mem/sdram/phy/k7ddrphy.py b/misoclib/mem/sdram/phy/k7ddrphy.py index 984bdea2..db8ada18 100644 --- a/misoclib/mem/sdram/phy/k7ddrphy.py +++ b/misoclib/mem/sdram/phy/k7ddrphy.py @@ -7,286 +7,286 @@ from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class K7DDRPHY(Module, AutoCSR): - def __init__(self, pads, module): - addressbits = flen(pads.a) - bankbits = flen(pads.ba) - databits = flen(pads.dq) - nphases = 4 + def __init__(self, pads, module): + addressbits = flen(pads.a) + bankbits = flen(pads.ba) + databits = flen(pads.dq) + nphases = 4 - self._wlevel_en = CSRStorage() - self._wlevel_strobe = CSR() - self._dly_sel = CSRStorage(databits//8) - self._rdly_dq_rst = CSR() - self._rdly_dq_inc = CSR() - self._rdly_dq_bitslip = CSR() - self._wdly_dq_rst = CSR() - self._wdly_dq_inc = CSR() - self._wdly_dqs_rst = CSR() - self._wdly_dqs_inc = CSR() + self._wlevel_en = CSRStorage() + self._wlevel_strobe = CSR() + self._dly_sel = CSRStorage(databits//8) + self._rdly_dq_rst = CSR() + self._rdly_dq_inc = CSR() + self._rdly_dq_bitslip = CSR() + self._wdly_dq_rst = CSR() + self._wdly_dq_inc = CSR() + self._wdly_dqs_rst = CSR() + self._wdly_dqs_inc = CSR() - self.settings = sdram.PhySettings( - memtype=module.memtype, - dfi_databits=2*databits, - nphases=nphases, - rdphase=0, - wrphase=2, - rdcmdphase=1, - wrcmdphase=0, - cl=7, - cwl=6, - read_latency=6, - write_latency=2 - ) - self.module = module + self.settings = sdram.PhySettings( + memtype=module.memtype, + dfi_databits=2*databits, + nphases=nphases, + rdphase=0, + wrphase=2, + rdcmdphase=1, + wrcmdphase=0, + cl=7, + cwl=6, + read_latency=6, + write_latency=2 + ) + self.module = module - self.dfi = Interface(addressbits, bankbits, 2*databits, nphases) + self.dfi = Interface(addressbits, bankbits, 2*databits, nphases) - ### + ### - # Clock - sd_clk_se = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + # Clock + sd_clk_se = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OQ=sd_clk_se, - i_OCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=0, i_D2=1, i_D3=0, i_D4=1, - i_D5=0, i_D6=1, i_D7=0, i_D8=1 - ), - Instance("OBUFDS", - i_I=sd_clk_se, - o_O=pads.clk_p, - o_OB=pads.clk_n - ) - ] + o_OQ=sd_clk_se, + i_OCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=0, i_D2=1, i_D3=0, i_D4=1, + i_D5=0, i_D6=1, i_D7=0, i_D8=1 + ), + Instance("OBUFDS", + i_I=sd_clk_se, + o_O=pads.clk_p, + o_OB=pads.clk_n + ) + ] - # Addresses and commands - for i in range(addressbits): - self.specials += \ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + # Addresses and commands + for i in range(addressbits): + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OQ=pads.a[i], - i_OCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=self.dfi.phases[0].address[i], i_D2=self.dfi.phases[0].address[i], - i_D3=self.dfi.phases[1].address[i], i_D4=self.dfi.phases[1].address[i], - i_D5=self.dfi.phases[2].address[i], i_D6=self.dfi.phases[2].address[i], - i_D7=self.dfi.phases[3].address[i], i_D8=self.dfi.phases[3].address[i] - ) - for i in range(bankbits): - self.specials += \ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + o_OQ=pads.a[i], + i_OCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].address[i], i_D2=self.dfi.phases[0].address[i], + i_D3=self.dfi.phases[1].address[i], i_D4=self.dfi.phases[1].address[i], + i_D5=self.dfi.phases[2].address[i], i_D6=self.dfi.phases[2].address[i], + i_D7=self.dfi.phases[3].address[i], i_D8=self.dfi.phases[3].address[i] + ) + for i in range(bankbits): + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OQ=pads.ba[i], - i_OCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=self.dfi.phases[0].bank[i], i_D2=self.dfi.phases[0].bank[i], - i_D3=self.dfi.phases[1].bank[i], i_D4=self.dfi.phases[1].bank[i], - i_D5=self.dfi.phases[2].bank[i], i_D6=self.dfi.phases[2].bank[i], - i_D7=self.dfi.phases[3].bank[i], i_D8=self.dfi.phases[3].bank[i] - ) - for name in "ras_n", "cas_n", "we_n", "cs_n", "cke", "odt", "reset_n": - self.specials += \ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + o_OQ=pads.ba[i], + i_OCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].bank[i], i_D2=self.dfi.phases[0].bank[i], + i_D3=self.dfi.phases[1].bank[i], i_D4=self.dfi.phases[1].bank[i], + i_D5=self.dfi.phases[2].bank[i], i_D6=self.dfi.phases[2].bank[i], + i_D7=self.dfi.phases[3].bank[i], i_D8=self.dfi.phases[3].bank[i] + ) + for name in "ras_n", "cas_n", "we_n", "cs_n", "cke", "odt", "reset_n": + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OQ=getattr(pads, name), - i_OCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=getattr(self.dfi.phases[0], name), i_D2=getattr(self.dfi.phases[0], name), - i_D3=getattr(self.dfi.phases[1], name), i_D4=getattr(self.dfi.phases[1], name), - i_D5=getattr(self.dfi.phases[2], name), i_D6=getattr(self.dfi.phases[2], name), - i_D7=getattr(self.dfi.phases[3], name), i_D8=getattr(self.dfi.phases[3], name) - ) + o_OQ=getattr(pads, name), + i_OCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=getattr(self.dfi.phases[0], name), i_D2=getattr(self.dfi.phases[0], name), + i_D3=getattr(self.dfi.phases[1], name), i_D4=getattr(self.dfi.phases[1], name), + i_D5=getattr(self.dfi.phases[2], name), i_D6=getattr(self.dfi.phases[2], name), + i_D7=getattr(self.dfi.phases[3], name), i_D8=getattr(self.dfi.phases[3], name) + ) - # DQS and DM - oe_dqs = Signal() - dqs_serdes_pattern = Signal(8) - self.comb += \ - If(self._wlevel_en.storage, - If(self._wlevel_strobe.re, - dqs_serdes_pattern.eq(0b00000001) - ).Else( - dqs_serdes_pattern.eq(0b00000000) - ) - ).Else( - dqs_serdes_pattern.eq(0b01010101) - ) - for i in range(databits//8): - dm_o_nodelay = Signal() - self.specials += \ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + # DQS and DM + oe_dqs = Signal() + dqs_serdes_pattern = Signal(8) + self.comb += \ + If(self._wlevel_en.storage, + If(self._wlevel_strobe.re, + dqs_serdes_pattern.eq(0b00000001) + ).Else( + dqs_serdes_pattern.eq(0b00000000) + ) + ).Else( + dqs_serdes_pattern.eq(0b01010101) + ) + for i in range(databits//8): + dm_o_nodelay = Signal() + self.specials += \ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OQ=dm_o_nodelay, - i_OCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=self.dfi.phases[0].wrdata_mask[i], i_D2=self.dfi.phases[0].wrdata_mask[databits//8+i], - i_D3=self.dfi.phases[1].wrdata_mask[i], i_D4=self.dfi.phases[1].wrdata_mask[databits//8+i], - i_D5=self.dfi.phases[2].wrdata_mask[i], i_D6=self.dfi.phases[2].wrdata_mask[databits//8+i], - i_D7=self.dfi.phases[3].wrdata_mask[i], i_D8=self.dfi.phases[3].wrdata_mask[databits//8+i] - ) - self.specials += \ - Instance("ODELAYE2", - p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, - p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=0, + o_OQ=dm_o_nodelay, + i_OCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].wrdata_mask[i], i_D2=self.dfi.phases[0].wrdata_mask[databits//8+i], + i_D3=self.dfi.phases[1].wrdata_mask[i], i_D4=self.dfi.phases[1].wrdata_mask[databits//8+i], + i_D5=self.dfi.phases[2].wrdata_mask[i], i_D6=self.dfi.phases[2].wrdata_mask[databits//8+i], + i_D7=self.dfi.phases[3].wrdata_mask[i], i_D8=self.dfi.phases[3].wrdata_mask[databits//8+i] + ) + self.specials += \ + Instance("ODELAYE2", + p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=0, - i_C=ClockSignal(), - i_LD=self._dly_sel.storage[i] & self._wdly_dq_rst.re, - i_CE=self._dly_sel.storage[i] & self._wdly_dq_inc.re, - i_LDPIPEEN=0, i_INC=1, + i_C=ClockSignal(), + i_LD=self._dly_sel.storage[i] & self._wdly_dq_rst.re, + i_CE=self._dly_sel.storage[i] & self._wdly_dq_inc.re, + i_LDPIPEEN=0, i_INC=1, - o_ODATAIN=dm_o_nodelay, o_DATAOUT=pads.dm[i] - ) + o_ODATAIN=dm_o_nodelay, o_DATAOUT=pads.dm[i] + ) - dqs_nodelay = Signal() - dqs_delayed = Signal() - dqs_t = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + dqs_nodelay = Signal() + dqs_delayed = Signal() + dqs_t = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OFB=dqs_nodelay, o_TQ=dqs_t, - i_OCE=1, i_TCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=dqs_serdes_pattern[0], i_D2=dqs_serdes_pattern[1], - i_D3=dqs_serdes_pattern[2], i_D4=dqs_serdes_pattern[3], - i_D5=dqs_serdes_pattern[4], i_D6=dqs_serdes_pattern[5], - i_D7=dqs_serdes_pattern[6], i_D8=dqs_serdes_pattern[7], - i_T1=~oe_dqs - ), - Instance("ODELAYE2", - p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, - p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=6, + o_OFB=dqs_nodelay, o_TQ=dqs_t, + i_OCE=1, i_TCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=dqs_serdes_pattern[0], i_D2=dqs_serdes_pattern[1], + i_D3=dqs_serdes_pattern[2], i_D4=dqs_serdes_pattern[3], + i_D5=dqs_serdes_pattern[4], i_D6=dqs_serdes_pattern[5], + i_D7=dqs_serdes_pattern[6], i_D8=dqs_serdes_pattern[7], + i_T1=~oe_dqs + ), + Instance("ODELAYE2", + p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=6, - i_C=ClockSignal(), - i_LD=self._dly_sel.storage[i] & self._wdly_dqs_rst.re, - i_CE=self._dly_sel.storage[i] & self._wdly_dqs_inc.re, - i_LDPIPEEN=0, i_INC=1, + i_C=ClockSignal(), + i_LD=self._dly_sel.storage[i] & self._wdly_dqs_rst.re, + i_CE=self._dly_sel.storage[i] & self._wdly_dqs_inc.re, + i_LDPIPEEN=0, i_INC=1, - o_ODATAIN=dqs_nodelay, o_DATAOUT=dqs_delayed - ), - Instance("OBUFTDS", - i_I=dqs_delayed, i_T=dqs_t, - o_O=pads.dqs_p[i], o_OB=pads.dqs_n[i] - ) - ] + o_ODATAIN=dqs_nodelay, o_DATAOUT=dqs_delayed + ), + Instance("OBUFTDS", + i_I=dqs_delayed, i_T=dqs_t, + o_O=pads.dqs_p[i], o_OB=pads.dqs_n[i] + ) + ] - # DQ - oe_dq = Signal() - for i in range(databits): - dq_o_nodelay = Signal() - dq_o_delayed = Signal() - dq_i_nodelay = Signal() - dq_i_delayed = Signal() - dq_t = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", + # DQ + oe_dq = Signal() + for i in range(databits): + dq_o_nodelay = Signal() + dq_o_delayed = Signal() + dq_i_nodelay = Signal() + dq_i_delayed = Signal() + dq_t = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", - o_OQ=dq_o_nodelay, o_TQ=dq_t, - i_OCE=1, i_TCE=1, - i_RST=ResetSignal(), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_D1=self.dfi.phases[0].wrdata[i], i_D2=self.dfi.phases[0].wrdata[databits+i], - i_D3=self.dfi.phases[1].wrdata[i], i_D4=self.dfi.phases[1].wrdata[databits+i], - i_D5=self.dfi.phases[2].wrdata[i], i_D6=self.dfi.phases[2].wrdata[databits+i], - i_D7=self.dfi.phases[3].wrdata[i], i_D8=self.dfi.phases[3].wrdata[databits+i], - i_T1=~oe_dq - ), - Instance("ISERDESE2", - p_DATA_WIDTH=8, p_DATA_RATE="DDR", - p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", - p_NUM_CE=1, p_IOBDELAY="IFD", + o_OQ=dq_o_nodelay, o_TQ=dq_t, + i_OCE=1, i_TCE=1, + i_RST=ResetSignal(), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_D1=self.dfi.phases[0].wrdata[i], i_D2=self.dfi.phases[0].wrdata[databits+i], + i_D3=self.dfi.phases[1].wrdata[i], i_D4=self.dfi.phases[1].wrdata[databits+i], + i_D5=self.dfi.phases[2].wrdata[i], i_D6=self.dfi.phases[2].wrdata[databits+i], + i_D7=self.dfi.phases[3].wrdata[i], i_D8=self.dfi.phases[3].wrdata[databits+i], + i_T1=~oe_dq + ), + Instance("ISERDESE2", + p_DATA_WIDTH=8, p_DATA_RATE="DDR", + p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", + p_NUM_CE=1, p_IOBDELAY="IFD", - i_DDLY=dq_i_delayed, - i_CE1=1, - i_RST=ResetSignal() | (self._dly_sel.storage[i//8] & self._wdly_dq_rst.re), - i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), - i_BITSLIP=self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re, - o_Q8=self.dfi.phases[0].rddata[i], o_Q7=self.dfi.phases[0].rddata[databits+i], - o_Q6=self.dfi.phases[1].rddata[i], o_Q5=self.dfi.phases[1].rddata[databits+i], - o_Q4=self.dfi.phases[2].rddata[i], o_Q3=self.dfi.phases[2].rddata[databits+i], - o_Q2=self.dfi.phases[3].rddata[i], o_Q1=self.dfi.phases[3].rddata[databits+i] - ), - Instance("ODELAYE2", - p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, - p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=0, + i_DDLY=dq_i_delayed, + i_CE1=1, + i_RST=ResetSignal() | (self._dly_sel.storage[i//8] & self._wdly_dq_rst.re), + i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal(), + i_BITSLIP=self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re, + o_Q8=self.dfi.phases[0].rddata[i], o_Q7=self.dfi.phases[0].rddata[databits+i], + o_Q6=self.dfi.phases[1].rddata[i], o_Q5=self.dfi.phases[1].rddata[databits+i], + o_Q4=self.dfi.phases[2].rddata[i], o_Q3=self.dfi.phases[2].rddata[databits+i], + o_Q2=self.dfi.phases[3].rddata[i], o_Q1=self.dfi.phases[3].rddata[databits+i] + ), + Instance("ODELAYE2", + p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=0, - i_C=ClockSignal(), - i_LD=self._dly_sel.storage[i//8] & self._wdly_dq_rst.re, - i_CE=self._dly_sel.storage[i//8] & self._wdly_dq_inc.re, - i_LDPIPEEN=0, i_INC=1, + i_C=ClockSignal(), + i_LD=self._dly_sel.storage[i//8] & self._wdly_dq_rst.re, + i_CE=self._dly_sel.storage[i//8] & self._wdly_dq_inc.re, + i_LDPIPEEN=0, i_INC=1, - o_ODATAIN=dq_o_nodelay, o_DATAOUT=dq_o_delayed - ), - Instance("IDELAYE2", - p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, - p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=6, + o_ODATAIN=dq_o_nodelay, o_DATAOUT=dq_o_delayed + ), + Instance("IDELAYE2", + p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, + p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=6, - i_C=ClockSignal(), - i_LD=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re, - i_CE=self._dly_sel.storage[i//8] & self._rdly_dq_inc.re, - i_LDPIPEEN=0, i_INC=1, + i_C=ClockSignal(), + i_LD=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re, + i_CE=self._dly_sel.storage[i//8] & self._rdly_dq_inc.re, + i_LDPIPEEN=0, i_INC=1, - i_IDATAIN=dq_i_nodelay, o_DATAOUT=dq_i_delayed - ), - Instance("IOBUF", - i_I=dq_o_delayed, o_O=dq_i_nodelay, i_T=dq_t, - io_IO=pads.dq[i] - ) - ] + i_IDATAIN=dq_i_nodelay, o_DATAOUT=dq_i_delayed + ), + Instance("IOBUF", + i_I=dq_o_delayed, o_O=dq_i_nodelay, i_T=dq_t, + io_IO=pads.dq[i] + ) + ] - # Flow control - # - # total read latency = 6: - # 2 cycles through OSERDESE2 - # 2 cycles CAS - # 2 cycles through ISERDESE2 - rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en - for i in range(5): - n_rddata_en = Signal() - self.sync += n_rddata_en.eq(rddata_en) - rddata_en = n_rddata_en - self.sync += [phase.rddata_valid.eq(rddata_en | self._wlevel_en.storage) - for phase in self.dfi.phases] + # Flow control + # + # total read latency = 6: + # 2 cycles through OSERDESE2 + # 2 cycles CAS + # 2 cycles through ISERDESE2 + rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en + for i in range(5): + n_rddata_en = Signal() + self.sync += n_rddata_en.eq(rddata_en) + rddata_en = n_rddata_en + self.sync += [phase.rddata_valid.eq(rddata_en | self._wlevel_en.storage) + for phase in self.dfi.phases] - oe = Signal() - last_wrdata_en = Signal(4) - wrphase = self.dfi.phases[self.settings.wrphase] - self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:3])) - self.comb += oe.eq(last_wrdata_en[1] | last_wrdata_en[2] | last_wrdata_en[3]) - self.sync += \ - If(self._wlevel_en.storage, - oe_dqs.eq(1), oe_dq.eq(0) - ).Else( - oe_dqs.eq(oe), oe_dq.eq(oe) - ) + oe = Signal() + last_wrdata_en = Signal(4) + wrphase = self.dfi.phases[self.settings.wrphase] + self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:3])) + self.comb += oe.eq(last_wrdata_en[1] | last_wrdata_en[2] | last_wrdata_en[3]) + self.sync += \ + If(self._wlevel_en.storage, + oe_dqs.eq(1), oe_dq.eq(0) + ).Else( + oe_dqs.eq(oe), oe_dq.eq(oe) + ) diff --git a/misoclib/mem/sdram/phy/s6ddrphy.py b/misoclib/mem/sdram/phy/s6ddrphy.py index b70260e8..36ed10a4 100644 --- a/misoclib/mem/sdram/phy/s6ddrphy.py +++ b/misoclib/mem/sdram/phy/s6ddrphy.py @@ -21,342 +21,342 @@ from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class S6DDRPHY(Module): - def __init__(self, pads, module, rd_bitslip, wr_bitslip, dqs_ddr_alignment): - if module.memtype not in ["DDR", "LPDDR", "DDR2"]: - raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2") - addressbits = flen(pads.a) - bankbits = flen(pads.ba) - databits = flen(pads.dq) - nphases = 2 - - self.settings = sdram.PhySettings( - memtype=module.memtype, - dfi_databits=2*databits, - nphases=nphases, - rdphase=0, - wrphase=1, - rdcmdphase=1, - wrcmdphase=0, - cl=3, - read_latency=5, - write_latency=0 - ) - self.module = module - - self.dfi = Interface(addressbits, bankbits, 2*databits, nphases) - self.clk4x_wr_strb = Signal() - self.clk4x_rd_strb = Signal() - - ### - - # sys_clk : system clk, used for dfi interface - # sdram_half_clk : half rate sdram clk - # sdram_full_wr_clk : full rate sdram write clk - # sdram_full_rd_clk : full rate sdram read clk - sd_sys = getattr(self.sync, "sys") - sd_sdram_half = getattr(self.sync, "sdram_half") - - sys_clk = ClockSignal("sys") - sdram_half_clk = ClockSignal("sdram_half") - sdram_full_wr_clk = ClockSignal("sdram_full_wr") - sdram_full_rd_clk = ClockSignal("sdram_full_rd") - - # - # Command/address - # - - # select active phase - # sys_clk ----____----____ - # phase_sel(nphases=2) 0 1 0 1 Half Rate - phase_sel = Signal(log2_int(nphases)) - phase_half = Signal.like(phase_sel) - phase_sys = Signal.like(phase_half) - - sd_sys += phase_sys.eq(phase_half) - - sd_sdram_half += [ - If(phase_half == phase_sys, - phase_sel.eq(0), - ).Else( - phase_sel.eq(phase_sel+1) - ), - phase_half.eq(phase_half+1), - ] - - # register dfi cmds on half_rate clk - r_dfi = Array(Record(phase_cmd_description(addressbits, bankbits)) for i in range(nphases)) - for n, phase in enumerate(self.dfi.phases): - sd_sdram_half +=[ - r_dfi[n].address.eq(phase.address), - r_dfi[n].bank.eq(phase.bank), - r_dfi[n].cs_n.eq(phase.cs_n), - r_dfi[n].cke.eq(phase.cke), - r_dfi[n].cas_n.eq(phase.cas_n), - r_dfi[n].ras_n.eq(phase.ras_n), - r_dfi[n].we_n.eq(phase.we_n) - ] - - # output cmds - sd_sdram_half += [ - pads.a.eq(r_dfi[phase_sel].address), - pads.ba.eq(r_dfi[phase_sel].bank), - pads.cke.eq(r_dfi[phase_sel].cke), - pads.ras_n.eq(r_dfi[phase_sel].ras_n), - pads.cas_n.eq(r_dfi[phase_sel].cas_n), - pads.we_n.eq(r_dfi[phase_sel].we_n) - ] - if hasattr(pads, "cs_n"): - sd_sdram_half += pads.cs_n.eq(r_dfi[phase_sel].cs_n) - - # - # Bitslip - # - bitslip_cnt = Signal(4) - bitslip_inc = Signal() - - sd_sys += [ - If(bitslip_cnt == rd_bitslip, - bitslip_inc.eq(0) - ).Else( - bitslip_cnt.eq(bitslip_cnt+1), - bitslip_inc.eq(1) - ) - ] - - # - # DQ/DQS/DM data - # - sdram_half_clk_n = Signal() - self.comb += sdram_half_clk_n.eq(~sdram_half_clk) - - postamble = Signal() - drive_dqs = Signal() - dqs_t_d0 = Signal() - dqs_t_d1 = Signal() - - dqs_o = Signal(databits//8) - dqs_t = Signal(databits//8) - - self.comb += [ - dqs_t_d0.eq(~(drive_dqs | postamble)), - dqs_t_d1.eq(~drive_dqs), - ] - - for i in range(databits//8): - # DQS output - self.specials += Instance("ODDR2", - p_DDR_ALIGNMENT=dqs_ddr_alignment, - p_INIT=0, - p_SRTYPE="ASYNC", - - i_C0=sdram_half_clk, - i_C1=sdram_half_clk_n, - - i_CE=1, - i_D0=0, - i_D1=1, - i_R=0, - i_S=0, - - o_Q=dqs_o[i] - ) - - # DQS tristate cmd - self.specials += Instance("ODDR2", - p_DDR_ALIGNMENT=dqs_ddr_alignment, - p_INIT=0, - p_SRTYPE="ASYNC", - - i_C0=sdram_half_clk, - i_C1=sdram_half_clk_n, - - i_CE=1, - i_D0=dqs_t_d0, - i_D1=dqs_t_d1, - i_R=0, - i_S=0, - - o_Q=dqs_t[i] - ) - - # DQS tristate buffer - if hasattr(pads, "dqs_n"): - self.specials += Instance("OBUFTDS", - i_I=dqs_o[i], - i_T=dqs_t[i], - - o_O=pads.dqs[i], - o_OB=pads.dqs_n[i], - ) - else: - self.specials += Instance("OBUFT", - i_I=dqs_o[i], - i_T=dqs_t[i], - - o_O=pads.dqs[i] - ) - - sd_sdram_half += postamble.eq(drive_dqs) - - d_dfi = [Record(phase_wrdata_description(nphases*databits)+phase_rddata_description(nphases*databits)) - for i in range(2*nphases)] - - for n, phase in enumerate(self.dfi.phases): - self.comb += [ - d_dfi[n].wrdata.eq(phase.wrdata), - d_dfi[n].wrdata_mask.eq(phase.wrdata_mask), - d_dfi[n].wrdata_en.eq(phase.wrdata_en), - d_dfi[n].rddata_en.eq(phase.rddata_en), - ] - sd_sys += [ - d_dfi[nphases+n].wrdata.eq(phase.wrdata), - d_dfi[nphases+n].wrdata_mask.eq(phase.wrdata_mask) - ] - - - drive_dq = Signal() - drive_dq_n = [Signal() for i in range(2)] - self.comb += drive_dq_n[0].eq(~drive_dq) - sd_sys += drive_dq_n[1].eq(drive_dq_n[0]) - - dq_t = Signal(databits) - dq_o = Signal(databits) - dq_i = Signal(databits) - - dq_wrdata = [] - for i in range(2): - for j in reversed(range(nphases)): - dq_wrdata.append(d_dfi[i*nphases+j].wrdata[:databits]) - dq_wrdata.append(d_dfi[i*nphases+j].wrdata[databits:]) - - for i in range(databits): - # Data serializer - self.specials += Instance("OSERDES2", - p_DATA_WIDTH=4, - p_DATA_RATE_OQ="SDR", - p_DATA_RATE_OT="SDR", - p_SERDES_MODE="NONE", - p_OUTPUT_MODE="SINGLE_ENDED", - - o_OQ=dq_o[i], - i_OCE=1, - i_CLK0=sdram_full_wr_clk, - i_CLK1=0, - i_IOCE=self.clk4x_wr_strb, - i_RST=0, - i_CLKDIV=sys_clk, - - i_D1=dq_wrdata[wr_bitslip+3][i], - i_D2=dq_wrdata[wr_bitslip+2][i], - i_D3=dq_wrdata[wr_bitslip+1][i], - i_D4=dq_wrdata[wr_bitslip+0][i], - - o_TQ=dq_t[i], - i_T1=drive_dq_n[(wr_bitslip+3)//4], - i_T2=drive_dq_n[(wr_bitslip+2)//4], - i_T3=drive_dq_n[(wr_bitslip+1)//4], - i_T4=drive_dq_n[(wr_bitslip+0)//4], - i_TRAIN=0, - i_TCE=1, - i_SHIFTIN1=0, - i_SHIFTIN2=0, - i_SHIFTIN3=0, - i_SHIFTIN4=0, - ) - - # Data deserializer - self.specials += Instance("ISERDES2", - p_DATA_WIDTH=4, - p_DATA_RATE="SDR", - p_BITSLIP_ENABLE="TRUE", - p_SERDES_MODE="NONE", - p_INTERFACE_TYPE="RETIMED", - - i_D=dq_i[i], - i_CE0=1, - i_CLK0=sdram_full_rd_clk, - i_CLK1=0, - i_IOCE=self.clk4x_rd_strb, - i_RST=ResetSignal(), - i_CLKDIV=sys_clk, - i_BITSLIP=bitslip_inc, - - o_Q1=d_dfi[0*nphases+0].rddata[i+databits], - o_Q2=d_dfi[0*nphases+0].rddata[i], - o_Q3=d_dfi[0*nphases+1].rddata[i+databits], - o_Q4=d_dfi[0*nphases+1].rddata[i], - ) - - # Data buffer - self.specials += Instance("IOBUF", - i_I=dq_o[i], - o_O=dq_i[i], - i_T=dq_t[i], - io_IO=pads.dq[i] - ) - - dq_wrdata_mask = [] - for i in range(2): - for j in reversed(range(nphases)): - dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[:databits//8]) - dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[databits//8:]) - - for i in range(databits//8): - # Mask serializer - self.specials += Instance("OSERDES2", - p_DATA_WIDTH=4, - p_DATA_RATE_OQ="SDR", - p_DATA_RATE_OT="SDR", - p_SERDES_MODE="NONE", - p_OUTPUT_MODE="SINGLE_ENDED", - - o_OQ=pads.dm[i], - i_OCE=1, - i_CLK0=sdram_full_wr_clk, - i_CLK1=0, - i_IOCE=self.clk4x_wr_strb, - i_RST=0, - i_CLKDIV=sys_clk, - - i_D1=dq_wrdata_mask[wr_bitslip+3][i], - i_D2=dq_wrdata_mask[wr_bitslip+2][i], - i_D3=dq_wrdata_mask[wr_bitslip+1][i], - i_D4=dq_wrdata_mask[wr_bitslip+0][i], - - i_TRAIN=0, - i_TCE=0, - i_SHIFTIN1=0, - i_SHIFTIN2=0, - i_SHIFTIN3=0, - i_SHIFTIN4=0, - ) - - # - # ODT - # - # ODT not yet supported - if hasattr(pads, "odt"): - self.comb += pads.odt.eq(0) - - # - # DQ/DQS/DM control - # - self.comb += drive_dq.eq(d_dfi[self.settings.wrphase].wrdata_en) - - d_dfi_wrdata_en = Signal() - sd_sys += d_dfi_wrdata_en.eq(d_dfi[self.settings.wrphase].wrdata_en) - - r_dfi_wrdata_en = Signal(2) - sd_sdram_half += r_dfi_wrdata_en.eq(Cat(d_dfi_wrdata_en, r_dfi_wrdata_en[0])) - - self.comb += drive_dqs.eq(r_dfi_wrdata_en[1]) - - rddata_sr = Signal(self.settings.read_latency) - sd_sys += rddata_sr.eq(Cat(rddata_sr[1:self.settings.read_latency], - d_dfi[self.settings.rdphase].rddata_en)) - - for n, phase in enumerate(self.dfi.phases): - self.comb += [ - phase.rddata.eq(d_dfi[n].rddata), - phase.rddata_valid.eq(rddata_sr[0]), - ] + def __init__(self, pads, module, rd_bitslip, wr_bitslip, dqs_ddr_alignment): + if module.memtype not in ["DDR", "LPDDR", "DDR2"]: + raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2") + addressbits = flen(pads.a) + bankbits = flen(pads.ba) + databits = flen(pads.dq) + nphases = 2 + + self.settings = sdram.PhySettings( + memtype=module.memtype, + dfi_databits=2*databits, + nphases=nphases, + rdphase=0, + wrphase=1, + rdcmdphase=1, + wrcmdphase=0, + cl=3, + read_latency=5, + write_latency=0 + ) + self.module = module + + self.dfi = Interface(addressbits, bankbits, 2*databits, nphases) + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() + + ### + + # sys_clk : system clk, used for dfi interface + # sdram_half_clk : half rate sdram clk + # sdram_full_wr_clk : full rate sdram write clk + # sdram_full_rd_clk : full rate sdram read clk + sd_sys = getattr(self.sync, "sys") + sd_sdram_half = getattr(self.sync, "sdram_half") + + sys_clk = ClockSignal("sys") + sdram_half_clk = ClockSignal("sdram_half") + sdram_full_wr_clk = ClockSignal("sdram_full_wr") + sdram_full_rd_clk = ClockSignal("sdram_full_rd") + + # + # Command/address + # + + # select active phase + # sys_clk ----____----____ + # phase_sel(nphases=2) 0 1 0 1 Half Rate + phase_sel = Signal(log2_int(nphases)) + phase_half = Signal.like(phase_sel) + phase_sys = Signal.like(phase_half) + + sd_sys += phase_sys.eq(phase_half) + + sd_sdram_half += [ + If(phase_half == phase_sys, + phase_sel.eq(0), + ).Else( + phase_sel.eq(phase_sel+1) + ), + phase_half.eq(phase_half+1), + ] + + # register dfi cmds on half_rate clk + r_dfi = Array(Record(phase_cmd_description(addressbits, bankbits)) for i in range(nphases)) + for n, phase in enumerate(self.dfi.phases): + sd_sdram_half +=[ + r_dfi[n].address.eq(phase.address), + r_dfi[n].bank.eq(phase.bank), + r_dfi[n].cs_n.eq(phase.cs_n), + r_dfi[n].cke.eq(phase.cke), + r_dfi[n].cas_n.eq(phase.cas_n), + r_dfi[n].ras_n.eq(phase.ras_n), + r_dfi[n].we_n.eq(phase.we_n) + ] + + # output cmds + sd_sdram_half += [ + pads.a.eq(r_dfi[phase_sel].address), + pads.ba.eq(r_dfi[phase_sel].bank), + pads.cke.eq(r_dfi[phase_sel].cke), + pads.ras_n.eq(r_dfi[phase_sel].ras_n), + pads.cas_n.eq(r_dfi[phase_sel].cas_n), + pads.we_n.eq(r_dfi[phase_sel].we_n) + ] + if hasattr(pads, "cs_n"): + sd_sdram_half += pads.cs_n.eq(r_dfi[phase_sel].cs_n) + + # + # Bitslip + # + bitslip_cnt = Signal(4) + bitslip_inc = Signal() + + sd_sys += [ + If(bitslip_cnt == rd_bitslip, + bitslip_inc.eq(0) + ).Else( + bitslip_cnt.eq(bitslip_cnt+1), + bitslip_inc.eq(1) + ) + ] + + # + # DQ/DQS/DM data + # + sdram_half_clk_n = Signal() + self.comb += sdram_half_clk_n.eq(~sdram_half_clk) + + postamble = Signal() + drive_dqs = Signal() + dqs_t_d0 = Signal() + dqs_t_d1 = Signal() + + dqs_o = Signal(databits//8) + dqs_t = Signal(databits//8) + + self.comb += [ + dqs_t_d0.eq(~(drive_dqs | postamble)), + dqs_t_d1.eq(~drive_dqs), + ] + + for i in range(databits//8): + # DQS output + self.specials += Instance("ODDR2", + p_DDR_ALIGNMENT=dqs_ddr_alignment, + p_INIT=0, + p_SRTYPE="ASYNC", + + i_C0=sdram_half_clk, + i_C1=sdram_half_clk_n, + + i_CE=1, + i_D0=0, + i_D1=1, + i_R=0, + i_S=0, + + o_Q=dqs_o[i] + ) + + # DQS tristate cmd + self.specials += Instance("ODDR2", + p_DDR_ALIGNMENT=dqs_ddr_alignment, + p_INIT=0, + p_SRTYPE="ASYNC", + + i_C0=sdram_half_clk, + i_C1=sdram_half_clk_n, + + i_CE=1, + i_D0=dqs_t_d0, + i_D1=dqs_t_d1, + i_R=0, + i_S=0, + + o_Q=dqs_t[i] + ) + + # DQS tristate buffer + if hasattr(pads, "dqs_n"): + self.specials += Instance("OBUFTDS", + i_I=dqs_o[i], + i_T=dqs_t[i], + + o_O=pads.dqs[i], + o_OB=pads.dqs_n[i], + ) + else: + self.specials += Instance("OBUFT", + i_I=dqs_o[i], + i_T=dqs_t[i], + + o_O=pads.dqs[i] + ) + + sd_sdram_half += postamble.eq(drive_dqs) + + d_dfi = [Record(phase_wrdata_description(nphases*databits)+phase_rddata_description(nphases*databits)) + for i in range(2*nphases)] + + for n, phase in enumerate(self.dfi.phases): + self.comb += [ + d_dfi[n].wrdata.eq(phase.wrdata), + d_dfi[n].wrdata_mask.eq(phase.wrdata_mask), + d_dfi[n].wrdata_en.eq(phase.wrdata_en), + d_dfi[n].rddata_en.eq(phase.rddata_en), + ] + sd_sys += [ + d_dfi[nphases+n].wrdata.eq(phase.wrdata), + d_dfi[nphases+n].wrdata_mask.eq(phase.wrdata_mask) + ] + + + drive_dq = Signal() + drive_dq_n = [Signal() for i in range(2)] + self.comb += drive_dq_n[0].eq(~drive_dq) + sd_sys += drive_dq_n[1].eq(drive_dq_n[0]) + + dq_t = Signal(databits) + dq_o = Signal(databits) + dq_i = Signal(databits) + + dq_wrdata = [] + for i in range(2): + for j in reversed(range(nphases)): + dq_wrdata.append(d_dfi[i*nphases+j].wrdata[:databits]) + dq_wrdata.append(d_dfi[i*nphases+j].wrdata[databits:]) + + for i in range(databits): + # Data serializer + self.specials += Instance("OSERDES2", + p_DATA_WIDTH=4, + p_DATA_RATE_OQ="SDR", + p_DATA_RATE_OT="SDR", + p_SERDES_MODE="NONE", + p_OUTPUT_MODE="SINGLE_ENDED", + + o_OQ=dq_o[i], + i_OCE=1, + i_CLK0=sdram_full_wr_clk, + i_CLK1=0, + i_IOCE=self.clk4x_wr_strb, + i_RST=0, + i_CLKDIV=sys_clk, + + i_D1=dq_wrdata[wr_bitslip+3][i], + i_D2=dq_wrdata[wr_bitslip+2][i], + i_D3=dq_wrdata[wr_bitslip+1][i], + i_D4=dq_wrdata[wr_bitslip+0][i], + + o_TQ=dq_t[i], + i_T1=drive_dq_n[(wr_bitslip+3)//4], + i_T2=drive_dq_n[(wr_bitslip+2)//4], + i_T3=drive_dq_n[(wr_bitslip+1)//4], + i_T4=drive_dq_n[(wr_bitslip+0)//4], + i_TRAIN=0, + i_TCE=1, + i_SHIFTIN1=0, + i_SHIFTIN2=0, + i_SHIFTIN3=0, + i_SHIFTIN4=0, + ) + + # Data deserializer + self.specials += Instance("ISERDES2", + p_DATA_WIDTH=4, + p_DATA_RATE="SDR", + p_BITSLIP_ENABLE="TRUE", + p_SERDES_MODE="NONE", + p_INTERFACE_TYPE="RETIMED", + + i_D=dq_i[i], + i_CE0=1, + i_CLK0=sdram_full_rd_clk, + i_CLK1=0, + i_IOCE=self.clk4x_rd_strb, + i_RST=ResetSignal(), + i_CLKDIV=sys_clk, + i_BITSLIP=bitslip_inc, + + o_Q1=d_dfi[0*nphases+0].rddata[i+databits], + o_Q2=d_dfi[0*nphases+0].rddata[i], + o_Q3=d_dfi[0*nphases+1].rddata[i+databits], + o_Q4=d_dfi[0*nphases+1].rddata[i], + ) + + # Data buffer + self.specials += Instance("IOBUF", + i_I=dq_o[i], + o_O=dq_i[i], + i_T=dq_t[i], + io_IO=pads.dq[i] + ) + + dq_wrdata_mask = [] + for i in range(2): + for j in reversed(range(nphases)): + dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[:databits//8]) + dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[databits//8:]) + + for i in range(databits//8): + # Mask serializer + self.specials += Instance("OSERDES2", + p_DATA_WIDTH=4, + p_DATA_RATE_OQ="SDR", + p_DATA_RATE_OT="SDR", + p_SERDES_MODE="NONE", + p_OUTPUT_MODE="SINGLE_ENDED", + + o_OQ=pads.dm[i], + i_OCE=1, + i_CLK0=sdram_full_wr_clk, + i_CLK1=0, + i_IOCE=self.clk4x_wr_strb, + i_RST=0, + i_CLKDIV=sys_clk, + + i_D1=dq_wrdata_mask[wr_bitslip+3][i], + i_D2=dq_wrdata_mask[wr_bitslip+2][i], + i_D3=dq_wrdata_mask[wr_bitslip+1][i], + i_D4=dq_wrdata_mask[wr_bitslip+0][i], + + i_TRAIN=0, + i_TCE=0, + i_SHIFTIN1=0, + i_SHIFTIN2=0, + i_SHIFTIN3=0, + i_SHIFTIN4=0, + ) + + # + # ODT + # + # ODT not yet supported + if hasattr(pads, "odt"): + self.comb += pads.odt.eq(0) + + # + # DQ/DQS/DM control + # + self.comb += drive_dq.eq(d_dfi[self.settings.wrphase].wrdata_en) + + d_dfi_wrdata_en = Signal() + sd_sys += d_dfi_wrdata_en.eq(d_dfi[self.settings.wrphase].wrdata_en) + + r_dfi_wrdata_en = Signal(2) + sd_sdram_half += r_dfi_wrdata_en.eq(Cat(d_dfi_wrdata_en, r_dfi_wrdata_en[0])) + + self.comb += drive_dqs.eq(r_dfi_wrdata_en[1]) + + rddata_sr = Signal(self.settings.read_latency) + sd_sys += rddata_sr.eq(Cat(rddata_sr[1:self.settings.read_latency], + d_dfi[self.settings.rdphase].rddata_en)) + + for n, phase in enumerate(self.dfi.phases): + self.comb += [ + phase.rddata.eq(d_dfi[n].rddata), + phase.rddata_valid.eq(rddata_sr[0]), + ] diff --git a/misoclib/mem/sdram/phy/simphy.py b/misoclib/mem/sdram/phy/simphy.py index 6ec39626..8b93f687 100644 --- a/misoclib/mem/sdram/phy/simphy.py +++ b/misoclib/mem/sdram/phy/simphy.py @@ -12,172 +12,172 @@ from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class Bank(Module): - def __init__(self, data_width, nrows, ncols): - self.activate = Signal() - self.activate_row = Signal(max=nrows) - self.precharge = Signal() - - self.write = Signal() - self.write_col = Signal(max=ncols) - self.write_data = Signal(data_width) - self.write_mask = Signal(data_width//8) - - self.read = Signal() - self.read_col = Signal(max=ncols) - self.read_data = Signal(data_width) - - ### - active = Signal() - row = Signal(max=nrows) - - self.sync += \ - If(self.precharge, - active.eq(0), - ).Elif(self.activate, - active.eq(1), - row.eq(self.activate_row) - ) - - self.specials.mem = mem = Memory(data_width, nrows*ncols) - self.specials.write_port = write_port = mem.get_port(write_capable=True, we_granularity=8) - self.specials.read_port = read_port = mem.get_port(async_read=True) - self.comb += [ - If(active, - write_port.adr.eq(row*ncols | self.write_col), - write_port.dat_w.eq(self.write_data), - write_port.we.eq(Replicate(self.write, data_width//8) & ~self.write_mask), - If(self.read, - read_port.adr.eq(row*ncols | self.read_col), - self.read_data.eq(read_port.dat_r) - ) - ) - ] + def __init__(self, data_width, nrows, ncols): + self.activate = Signal() + self.activate_row = Signal(max=nrows) + self.precharge = Signal() + + self.write = Signal() + self.write_col = Signal(max=ncols) + self.write_data = Signal(data_width) + self.write_mask = Signal(data_width//8) + + self.read = Signal() + self.read_col = Signal(max=ncols) + self.read_data = Signal(data_width) + + ### + active = Signal() + row = Signal(max=nrows) + + self.sync += \ + If(self.precharge, + active.eq(0), + ).Elif(self.activate, + active.eq(1), + row.eq(self.activate_row) + ) + + self.specials.mem = mem = Memory(data_width, nrows*ncols) + self.specials.write_port = write_port = mem.get_port(write_capable=True, we_granularity=8) + self.specials.read_port = read_port = mem.get_port(async_read=True) + self.comb += [ + If(active, + write_port.adr.eq(row*ncols | self.write_col), + write_port.dat_w.eq(self.write_data), + write_port.we.eq(Replicate(self.write, data_width//8) & ~self.write_mask), + If(self.read, + read_port.adr.eq(row*ncols | self.read_col), + self.read_data.eq(read_port.dat_r) + ) + ) + ] class DFIPhase(Module): - def __init__(self, dfi, n): - phase = getattr(dfi, "p"+str(n)) - - self.bank = phase.bank - self.address = phase.address - - self.wrdata = phase.wrdata - self.wrdata_mask = phase.wrdata_mask - - self.rddata = phase.rddata - self.rddata_valid = phase.rddata_valid - - self.activate = Signal() - self.precharge = Signal() - self.write = Signal() - self.read = Signal() - - ### - self.comb += [ - If(~phase.cs_n & ~phase.ras_n & phase.cas_n, - self.activate.eq(phase.we_n), - self.precharge.eq(~phase.we_n) - ), - If(~phase.cs_n & phase.ras_n & ~phase.cas_n, - self.write.eq(~phase.we_n), - self.read.eq(phase.we_n) - ) - ] + def __init__(self, dfi, n): + phase = getattr(dfi, "p"+str(n)) + + self.bank = phase.bank + self.address = phase.address + + self.wrdata = phase.wrdata + self.wrdata_mask = phase.wrdata_mask + + self.rddata = phase.rddata + self.rddata_valid = phase.rddata_valid + + self.activate = Signal() + self.precharge = Signal() + self.write = Signal() + self.read = Signal() + + ### + self.comb += [ + If(~phase.cs_n & ~phase.ras_n & phase.cas_n, + self.activate.eq(phase.we_n), + self.precharge.eq(~phase.we_n) + ), + If(~phase.cs_n & phase.ras_n & ~phase.cas_n, + self.write.eq(~phase.we_n), + self.read.eq(phase.we_n) + ) + ] class SDRAMPHYSim(Module): - def __init__(self, module, settings): - addressbits = module.geom_settings.addressbits - bankbits = module.geom_settings.bankbits - rowbits = module.geom_settings.rowbits - colbits = module.geom_settings.colbits - - self.settings = settings - self.module = module - - self.dfi = Interface(addressbits, bankbits, self.settings.dfi_databits, self.settings.nphases) - - ### - nbanks = 2**bankbits - nrows = 2**rowbits - ncols = 2**colbits - data_width = self.settings.dfi_databits*self.settings.nphases - - # DFI phases - phases = [DFIPhase(self.dfi, n) for n in range(self.settings.nphases)] - self.submodules += phases - - # banks - banks = [Bank(data_width, nrows, ncols) for i in range(nbanks)] - self.submodules += banks - - # connect DFI phases to banks (cmds, write datapath) - for nb, bank in enumerate(banks): - # bank activate - activates = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += activates[np].eq(phase.activate) - cases[2**np] = [ - bank.activate.eq(phase.bank == nb), - bank.activate_row.eq(phase.address) - ] - self.comb += Case(activates, cases) - - # bank precharge - precharges = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += precharges[np].eq(phase.precharge) - cases[2**np] = [ - bank.precharge.eq((phase.bank == nb) | phase.address[10]) - ] - self.comb += Case(precharges, cases) - - # bank writes - writes = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += writes[np].eq(phase.write) - cases[2**np] = [ - bank.write.eq(phase.bank == nb), - bank.write_col.eq(phase.address) - ] - self.comb += Case(writes, cases) - self.comb += [ - bank.write_data.eq(Cat(*[phase.wrdata for phase in phases])), - bank.write_mask.eq(Cat(*[phase.wrdata_mask for phase in phases])) - ] - - # bank reads - reads = Signal(len(phases)) - read_data = Signal(data_width) - cases = {} - for np, phase in enumerate(phases): - self.comb += reads[np].eq(phase.read) - cases[2**np] = [ - bank.read.eq(phase.bank == nb), - bank.read_col.eq(phase.address) - ] - self.comb += Case(reads, cases) - - # connect banks to DFI phases (cmds, read datapath) - banks_read = Signal() - banks_read_data = Signal(data_width) - self.comb += [ - banks_read.eq(optree("|", [bank.read for bank in banks])), - banks_read_data.eq(optree("|", [bank.read_data for bank in banks])) - ] - # simulate read latency - for i in range(self.settings.read_latency): - new_banks_read = Signal() - new_banks_read_data = Signal(data_width) - self.sync += [ - new_banks_read.eq(banks_read), - new_banks_read_data.eq(banks_read_data) - ] - banks_read = new_banks_read - banks_read_data = new_banks_read_data - - self.comb += [ - Cat(*[phase.rddata_valid for phase in phases]).eq(banks_read), - Cat(*[phase.rddata for phase in phases]).eq(banks_read_data) - ] + def __init__(self, module, settings): + addressbits = module.geom_settings.addressbits + bankbits = module.geom_settings.bankbits + rowbits = module.geom_settings.rowbits + colbits = module.geom_settings.colbits + + self.settings = settings + self.module = module + + self.dfi = Interface(addressbits, bankbits, self.settings.dfi_databits, self.settings.nphases) + + ### + nbanks = 2**bankbits + nrows = 2**rowbits + ncols = 2**colbits + data_width = self.settings.dfi_databits*self.settings.nphases + + # DFI phases + phases = [DFIPhase(self.dfi, n) for n in range(self.settings.nphases)] + self.submodules += phases + + # banks + banks = [Bank(data_width, nrows, ncols) for i in range(nbanks)] + self.submodules += banks + + # connect DFI phases to banks (cmds, write datapath) + for nb, bank in enumerate(banks): + # bank activate + activates = Signal(len(phases)) + cases = {} + for np, phase in enumerate(phases): + self.comb += activates[np].eq(phase.activate) + cases[2**np] = [ + bank.activate.eq(phase.bank == nb), + bank.activate_row.eq(phase.address) + ] + self.comb += Case(activates, cases) + + # bank precharge + precharges = Signal(len(phases)) + cases = {} + for np, phase in enumerate(phases): + self.comb += precharges[np].eq(phase.precharge) + cases[2**np] = [ + bank.precharge.eq((phase.bank == nb) | phase.address[10]) + ] + self.comb += Case(precharges, cases) + + # bank writes + writes = Signal(len(phases)) + cases = {} + for np, phase in enumerate(phases): + self.comb += writes[np].eq(phase.write) + cases[2**np] = [ + bank.write.eq(phase.bank == nb), + bank.write_col.eq(phase.address) + ] + self.comb += Case(writes, cases) + self.comb += [ + bank.write_data.eq(Cat(*[phase.wrdata for phase in phases])), + bank.write_mask.eq(Cat(*[phase.wrdata_mask for phase in phases])) + ] + + # bank reads + reads = Signal(len(phases)) + read_data = Signal(data_width) + cases = {} + for np, phase in enumerate(phases): + self.comb += reads[np].eq(phase.read) + cases[2**np] = [ + bank.read.eq(phase.bank == nb), + bank.read_col.eq(phase.address) + ] + self.comb += Case(reads, cases) + + # connect banks to DFI phases (cmds, read datapath) + banks_read = Signal() + banks_read_data = Signal(data_width) + self.comb += [ + banks_read.eq(optree("|", [bank.read for bank in banks])), + banks_read_data.eq(optree("|", [bank.read_data for bank in banks])) + ] + # simulate read latency + for i in range(self.settings.read_latency): + new_banks_read = Signal() + new_banks_read_data = Signal(data_width) + self.sync += [ + new_banks_read.eq(banks_read), + new_banks_read_data.eq(banks_read_data) + ] + banks_read = new_banks_read + banks_read_data = new_banks_read_data + + self.comb += [ + Cat(*[phase.rddata_valid for phase in phases]).eq(banks_read), + Cat(*[phase.rddata for phase in phases]).eq(banks_read_data) + ] diff --git a/misoclib/mem/sdram/test/abstract_transactions_lasmi.py b/misoclib/mem/sdram/test/abstract_transactions_lasmi.py index cdd78e70..5ad8d789 100644 --- a/misoclib/mem/sdram/test/abstract_transactions_lasmi.py +++ b/misoclib/mem/sdram/test/abstract_transactions_lasmi.py @@ -5,35 +5,35 @@ from migen.sim.generic import run_simulation from misoclib.mem.sdram.core import lasmibus def my_generator(n): - bank = n % 4 - for x in range(4): - t = TWrite(4*bank+x, 0x1000*bank + 0x100*x) - yield t - print("{0}: Wrote in {1} cycle(s)".format(n, t.latency)) + bank = n % 4 + for x in range(4): + t = TWrite(4*bank+x, 0x1000*bank + 0x100*x) + yield t + print("{0}: Wrote in {1} cycle(s)".format(n, t.latency)) - for x in range(4): - t = TRead(4*bank+x) - yield t - print("{0}: Read {1:x} in {2} cycle(s)".format(n, t.data, t.latency)) - assert(t.data == 0x1000*bank + 0x100*x) + for x in range(4): + t = TRead(4*bank+x) + yield t + print("{0}: Read {1:x} in {2} cycle(s)".format(n, t.data, t.latency)) + assert(t.data == 0x1000*bank + 0x100*x) class MyModel(lasmibus.TargetModel): - def read(self, bank, address): - r = 0x1000*bank + 0x100*address - #print("read from bank {0} address {1} -> {2:x}".format(bank, address, r)) - return r + def read(self, bank, address): + r = 0x1000*bank + 0x100*address + #print("read from bank {0} address {1} -> {2:x}".format(bank, address, r)) + return r - def write(self, bank, address, data, we): - print("write to bank {0} address {1:x} data {2:x}".format(bank, address, data)) - assert(data == 0x1000*bank + 0x100*address) + def write(self, bank, address, data, we): + print("write to bank {0} address {1:x} data {2:x}".format(bank, address, data)) + assert(data == 0x1000*bank + 0x100*address) class TB(Module): - def __init__(self): - self.submodules.controller = lasmibus.Target(MyModel(), aw=4, dw=32, nbanks=4, req_queue_size=4, - read_latency=4, write_latency=1) - self.submodules.xbar = lasmibus.Crossbar([self.controller.bus], 2) - self.initiators = [lasmibus.Initiator(my_generator(n), self.xbar.get_master()) for n in range(4)] - self.submodules += self.initiators + def __init__(self): + self.submodules.controller = lasmibus.Target(MyModel(), aw=4, dw=32, nbanks=4, req_queue_size=4, + read_latency=4, write_latency=1) + self.submodules.xbar = lasmibus.Crossbar([self.controller.bus], 2) + self.initiators = [lasmibus.Initiator(my_generator(n), self.xbar.get_master()) for n in range(4)] + self.submodules += self.initiators if __name__ == "__main__": - run_simulation(TB()) + run_simulation(TB()) diff --git a/misoclib/mem/sdram/test/bankmachine_tb.py b/misoclib/mem/sdram/test/bankmachine_tb.py index 77841e43..9c6f4900 100644 --- a/misoclib/mem/sdram/test/bankmachine_tb.py +++ b/misoclib/mem/sdram/test/bankmachine_tb.py @@ -7,35 +7,35 @@ from misoclib.mem.sdram.core.lasmicon.bankmachine import * from common import sdram_phy, sdram_geom, sdram_timing, CommandLogger def my_generator(): - for x in range(10): - yield True, x - for x in range(10): - yield False, 128*x + for x in range(10): + yield True, x + for x in range(10): + yield False, 128*x class TB(Module): - def __init__(self): - self.req = Interface(32, 32, 1, - sdram_timing.req_queue_size, sdram_phy.read_latency, sdram_phy.write_latency) - self.submodules.dut = BankMachine(sdram_geom, sdram_timing, 2, 0, self.req) - self.submodules.logger = CommandLogger(self.dut.cmd, True) - self.generator = my_generator() - self.dat_ack_cnt = 0 + def __init__(self): + self.req = Interface(32, 32, 1, + sdram_timing.req_queue_size, sdram_phy.read_latency, sdram_phy.write_latency) + self.submodules.dut = BankMachine(sdram_geom, sdram_timing, 2, 0, self.req) + self.submodules.logger = CommandLogger(self.dut.cmd, True) + self.generator = my_generator() + self.dat_ack_cnt = 0 - def do_simulation(self, selfp): - if selfp.req.dat_ack: - self.dat_ack_cnt += 1 - if selfp.req.req_ack: - try: - we, adr = next(self.generator) - except StopIteration: - selfp.req.stb = 0 - if not selfp.req.lock: - print("data ack count: {0}".format(self.dat_ack_cnt)) - raise StopSimulation - return - selfp.req.adr = adr - selfp.req.we = we - selfp.req.stb = 1 + def do_simulation(self, selfp): + if selfp.req.dat_ack: + self.dat_ack_cnt += 1 + if selfp.req.req_ack: + try: + we, adr = next(self.generator) + except StopIteration: + selfp.req.stb = 0 + if not selfp.req.lock: + print("data ack count: {0}".format(self.dat_ack_cnt)) + raise StopSimulation + return + selfp.req.adr = adr + selfp.req.we = we + selfp.req.stb = 1 if __name__ == "__main__": - run_simulation(TB(), vcd_name="my.vcd") + run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/common.py b/misoclib/mem/sdram/test/common.py index 3ad126a5..f4b7dc2b 100644 --- a/misoclib/mem/sdram/test/common.py +++ b/misoclib/mem/sdram/test/common.py @@ -10,92 +10,92 @@ clk_freq = (83 + Fraction(1, 3))*MHz clk_period_ns = 1000000000/clk_freq def ns(t, margin=True): - if margin: - t += clk_period_ns/2 - return ceil(t/clk_period_ns) + if margin: + t += clk_period_ns/2 + return ceil(t/clk_period_ns) sdram_phy = sdram.PhySettings( - memtype="DDR", - dfi_databits=64, - nphases=2, - rdphase=0, - wrphase=1, - rdcmdphase=1, - wrcmdphase=0, - cl=3, - read_latency=5, - write_latency=0 + memtype="DDR", + dfi_databits=64, + nphases=2, + rdphase=0, + wrphase=1, + rdcmdphase=1, + wrcmdphase=0, + cl=3, + read_latency=5, + write_latency=0 ) sdram_geom = sdram.GeomSettings( - bankbits=2, - rowbits=13, - colbits=10 + bankbits=2, + rowbits=13, + colbits=10 ) sdram_timing = sdram.TimingSettings( - tRP=ns(15), - tRCD=ns(15), - tWR=ns(15), - tWTR=2, - tREFI=ns(7800, False), - tRFC=ns(70), + tRP=ns(15), + tRCD=ns(15), + tWR=ns(15), + tWTR=2, + tREFI=ns(7800, False), + tRFC=ns(70), - req_queue_size=8, - read_time=32, - write_time=16 + req_queue_size=8, + read_time=32, + write_time=16 ) def decode_sdram(ras_n, cas_n, we_n, bank, address): - elts = [] - if not ras_n and cas_n and we_n: - elts.append("ACTIVATE") - elts.append("BANK " + str(bank)) - elts.append("ROW " + str(address)) - elif ras_n and not cas_n and we_n: - elts.append("READ\t") - elts.append("BANK " + str(bank)) - elts.append("COL " + str(address)) - elif ras_n and not cas_n and not we_n: - elts.append("WRITE\t") - elts.append("BANK " + str(bank)) - elts.append("COL " + str(address)) - elif ras_n and cas_n and not we_n: - elts.append("BST") - elif not ras_n and not cas_n and we_n: - elts.append("AUTO REFRESH") - elif not ras_n and cas_n and not we_n: - elts.append("PRECHARGE") - if address & 2**10: - elts.append("ALL") - else: - elts.append("BANK " + str(bank)) - elif not ras_n and not cas_n and not we_n: - elts.append("LMR") - return elts + elts = [] + if not ras_n and cas_n and we_n: + elts.append("ACTIVATE") + elts.append("BANK " + str(bank)) + elts.append("ROW " + str(address)) + elif ras_n and not cas_n and we_n: + elts.append("READ\t") + elts.append("BANK " + str(bank)) + elts.append("COL " + str(address)) + elif ras_n and not cas_n and not we_n: + elts.append("WRITE\t") + elts.append("BANK " + str(bank)) + elts.append("COL " + str(address)) + elif ras_n and cas_n and not we_n: + elts.append("BST") + elif not ras_n and not cas_n and we_n: + elts.append("AUTO REFRESH") + elif not ras_n and cas_n and not we_n: + elts.append("PRECHARGE") + if address & 2**10: + elts.append("ALL") + else: + elts.append("BANK " + str(bank)) + elif not ras_n and not cas_n and not we_n: + elts.append("LMR") + return elts class CommandLogger(Module): - def __init__(self, cmd, rw=False): - self.cmd = cmd - if rw: - self.comb += self.cmd.ack.eq(1) + def __init__(self, cmd, rw=False): + self.cmd = cmd + if rw: + self.comb += self.cmd.ack.eq(1) - def do_simulation(self, selfp): - elts = ["@" + str(selfp.simulator.cycle_counter)] - cmdp = selfp.cmd - elts += decode_sdram(cmdp.ras_n, cmdp.cas_n, cmdp.we_n, cmdp.ba, cmdp.a) - if len(elts) > 1: - print("\t".join(elts)) - do_simulation.passive = True + def do_simulation(self, selfp): + elts = ["@" + str(selfp.simulator.cycle_counter)] + cmdp = selfp.cmd + elts += decode_sdram(cmdp.ras_n, cmdp.cas_n, cmdp.we_n, cmdp.ba, cmdp.a) + if len(elts) > 1: + print("\t".join(elts)) + do_simulation.passive = True class DFILogger(Module): - def __init__(self, dfi): - self.dfi = dfi + def __init__(self, dfi): + self.dfi = dfi - def do_simulation(self, selfp): - dfip = selfp.dfi - for i, p in enumerate(dfip.phases): - elts = ["@" + str(selfp.simulator.cycle_counter) + ":" + str(i)] - elts += decode_sdram(p.ras_n, p.cas_n, p.we_n, p.bank, p.address) - if len(elts) > 1: - print("\t".join(elts)) - do_simulation.passive = True + def do_simulation(self, selfp): + dfip = selfp.dfi + for i, p in enumerate(dfip.phases): + elts = ["@" + str(selfp.simulator.cycle_counter) + ":" + str(i)] + elts += decode_sdram(p.ras_n, p.cas_n, p.we_n, p.bank, p.address) + if len(elts) > 1: + print("\t".join(elts)) + do_simulation.passive = True diff --git a/misoclib/mem/sdram/test/lasmicon_df_tb.py b/misoclib/mem/sdram/test/lasmicon_df_tb.py index d239d49a..5db8befe 100644 --- a/misoclib/mem/sdram/test/lasmicon_df_tb.py +++ b/misoclib/mem/sdram/test/lasmicon_df_tb.py @@ -8,32 +8,32 @@ from misoclib.mem.sdram.frontend import dma_lasmi from common import sdram_phy, sdram_geom, sdram_timing, DFILogger class TB(Module): - def __init__(self): - self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) - self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) - self.submodules.logger = DFILogger(self.ctler.dfi) - self.submodules.writer = dma_lasmi.Writer(self.xbar.get_master()) + def __init__(self): + self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) + self.submodules.logger = DFILogger(self.ctler.dfi) + self.submodules.writer = dma_lasmi.Writer(self.xbar.get_master()) - self.comb += self.writer.address_data.stb.eq(1) - pl = self.writer.address_data.payload - pl.a.reset = 255 - pl.d.reset = pl.a.reset*2 - self.sync += If(self.writer.address_data.ack, - pl.a.eq(pl.a + 1), - pl.d.eq(pl.d + 2) - ) - self.open_row = None + self.comb += self.writer.address_data.stb.eq(1) + pl = self.writer.address_data.payload + pl.a.reset = 255 + pl.d.reset = pl.a.reset*2 + self.sync += If(self.writer.address_data.ack, + pl.a.eq(pl.a + 1), + pl.d.eq(pl.d + 2) + ) + self.open_row = None - def do_simulation(self, selfp): - dfip = selfp.ctler.dfi - for p in dfip.phases: - if p.ras_n and not p.cas_n and not p.we_n: # write - d = dfip.phases[0].wrdata | (dfip.phases[1].wrdata << 64) - print(d) - if d != p.address//2 + p.bank*512 + self.open_row*2048: - print("**** ERROR ****") - elif not p.ras_n and p.cas_n and p.we_n: # activate - self.open_row = p.address + def do_simulation(self, selfp): + dfip = selfp.ctler.dfi + for p in dfip.phases: + if p.ras_n and not p.cas_n and not p.we_n: # write + d = dfip.phases[0].wrdata | (dfip.phases[1].wrdata << 64) + print(d) + if d != p.address//2 + p.bank*512 + self.open_row*2048: + print("**** ERROR ****") + elif not p.ras_n and p.cas_n and p.we_n: # activate + self.open_row = p.address if __name__ == "__main__": - run_simulation(TB(), ncycles=3500, vcd_name="my.vcd") + run_simulation(TB(), ncycles=3500, vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/lasmicon_tb.py b/misoclib/mem/sdram/test/lasmicon_tb.py index 0352c060..be4ad1f8 100644 --- a/misoclib/mem/sdram/test/lasmicon_tb.py +++ b/misoclib/mem/sdram/test/lasmicon_tb.py @@ -7,33 +7,33 @@ from misoclib.mem.sdram.core.lasmicon import * from common import sdram_phy, sdram_geom, sdram_timing, DFILogger def my_generator_r(n): - for x in range(10): - t = TRead(128*n + 48*n*x) - yield t - print("{0:3}: reads done".format(n)) + for x in range(10): + t = TRead(128*n + 48*n*x) + yield t + print("{0:3}: reads done".format(n)) def my_generator_w(n): - for x in range(10): - t = TWrite(128*n + 48*n*x, x) - yield t - print("{0:3}: writes done".format(n)) + for x in range(10): + t = TWrite(128*n + 48*n*x, x) + yield t + print("{0:3}: writes done".format(n)) def my_generator(n): - if n % 2: - return my_generator_w(n // 2) - else: - return my_generator_r(n // 2) + if n % 2: + return my_generator_w(n // 2) + else: + return my_generator_r(n // 2) class TB(Module): - def __init__(self): - self.submodules.dut = LASMIcon(sdram_phy, sdram_geom, sdram_timing) - self.submodules.xbar = lasmibus.Crossbar([self.dut.lasmic], self.dut.nrowbits) - self.submodules.logger = DFILogger(self.dut.dfi) + def __init__(self): + self.submodules.dut = LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.xbar = lasmibus.Crossbar([self.dut.lasmic], self.dut.nrowbits) + self.submodules.logger = DFILogger(self.dut.dfi) - masters = [self.xbar.get_master() for i in range(6)] - self.initiators = [Initiator(my_generator(n), master) - for n, master in enumerate(masters)] - self.submodules += self.initiators + masters = [self.xbar.get_master() for i in range(6)] + self.initiators = [Initiator(my_generator(n), master) + for n, master in enumerate(masters)] + self.submodules += self.initiators if __name__ == "__main__": - run_simulation(TB(), vcd_name="my.vcd") + run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/lasmicon_wb.py b/misoclib/mem/sdram/test/lasmicon_wb.py index dae6c634..eb78e5a5 100644 --- a/misoclib/mem/sdram/test/lasmicon_wb.py +++ b/misoclib/mem/sdram/test/lasmicon_wb.py @@ -12,27 +12,27 @@ from common import sdram_phy, sdram_geom, sdram_timing, DFILogger l2_size = 8192 # in bytes def my_generator(): - for x in range(20): - t = TWrite(x, x) - yield t - print(str(t) + " delay=" + str(t.latency)) - for x in range(20): - t = TRead(x) - yield t - print(str(t) + " delay=" + str(t.latency)) - for x in range(20): - t = TRead(x+l2_size//4) - yield t - print(str(t) + " delay=" + str(t.latency)) + for x in range(20): + t = TWrite(x, x) + yield t + print(str(t) + " delay=" + str(t.latency)) + for x in range(20): + t = TRead(x) + yield t + print(str(t) + " delay=" + str(t.latency)) + for x in range(20): + t = TRead(x+l2_size//4) + yield t + print(str(t) + " delay=" + str(t.latency)) class TB(Module): - def __init__(self): - self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) - self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) - self.submodules.logger = DFILogger(self.ctler.dfi) - self.submodules.bridge = wishbone2lasmi.WB2LASMI(l2_size//4, self.xbar.get_master()) - self.submodules.initiator = wishbone.Initiator(my_generator()) - self.submodules.conn = wishbone.InterconnectPointToPoint(self.initiator.bus, self.bridge.wishbone) + def __init__(self): + self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) + self.submodules.logger = DFILogger(self.ctler.dfi) + self.submodules.bridge = wishbone2lasmi.WB2LASMI(l2_size//4, self.xbar.get_master()) + self.submodules.initiator = wishbone.Initiator(my_generator()) + self.submodules.conn = wishbone.InterconnectPointToPoint(self.initiator.bus, self.bridge.wishbone) if __name__ == "__main__": - run_simulation(TB(), vcd_name="my.vcd") + run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/minicon_tb.py b/misoclib/mem/sdram/test/minicon_tb.py index aba057a9..d664aecb 100644 --- a/misoclib/mem/sdram/test/minicon_tb.py +++ b/misoclib/mem/sdram/test/minicon_tb.py @@ -16,86 +16,86 @@ clk_freq = 80000000 from math import ceil def ns(t, margin=True): - clk_period_ns = 1000000000/clk_freq - if margin: - t += clk_period_ns/2 - return ceil(t/clk_period_ns) + clk_period_ns = 1000000000/clk_freq + if margin: + t += clk_period_ns/2 + return ceil(t/clk_period_ns) class MiniconTB(Module): - def __init__(self, sdrphy, dfi, sdram_geom, sdram_timing, pads, sdram_clk): - - self.clk_freq = 80000000 - phy_settings = sdrphy.settings - rdphase = phy_settings.rdphase - self.submodules.slave = Minicon(phy_settings, sdram_geom, sdram_timing) - - self.submodules.tap = wishbone.Tap(self.slave.bus) - self.submodules.dc = dc = wishbone.DownConverter(32, phy_settings.nphases*flen(dfi.phases[rdphase].rddata)) - self.submodules.master = wishbone.Initiator(self.genxfers(), bus=dc.wishbone_i) - self.submodules.intercon = wishbone.InterconnectPointToPoint(dc.wishbone_o, self.slave.bus) - - self.submodules.sdrphy = self.sdrphy = sdrphy - self.dfi = dfi - self.pads = pads - - self.specials += Instance("mt48lc4m16a2", - io_Dq=pads.dq, - i_Addr=pads.a, - i_Ba=pads.ba, - i_Clk=ClockSignal(), - i_Cke=pads.cke, - i_Cs_n=pads.cs_n, - i_Ras_n=pads.ras_n, - i_Cas_n=pads.cas_n, - i_We_n=pads.we_n, - i_Dqm=pads.dm - ) - - def genxfers(self): - cycle = 0 - for a in chain(range(4),range(256,260),range(1024,1028)): - t = TRead(a) - yield t - print("read {} in {} cycles".format(t.data, t.latency)) - for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): - t = TWrite(a, 0xaa55aa55+cycle) - cycle += 1 - yield t - print("read {} in {} cycles".format(t.data, t.latency)) - for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): - t = TRead(a) - yield t - print("read {} in {} cycles".format(t.data, t.latency)) - - def gen_simulation(self, selfp): - dfi = selfp.dfi - phy = self.sdrphy - rdphase = phy.settings.rdphase - cycle = 0 - - while True: - yield + def __init__(self, sdrphy, dfi, sdram_geom, sdram_timing, pads, sdram_clk): + + self.clk_freq = 80000000 + phy_settings = sdrphy.settings + rdphase = phy_settings.rdphase + self.submodules.slave = Minicon(phy_settings, sdram_geom, sdram_timing) + + self.submodules.tap = wishbone.Tap(self.slave.bus) + self.submodules.dc = dc = wishbone.DownConverter(32, phy_settings.nphases*flen(dfi.phases[rdphase].rddata)) + self.submodules.master = wishbone.Initiator(self.genxfers(), bus=dc.wishbone_i) + self.submodules.intercon = wishbone.InterconnectPointToPoint(dc.wishbone_o, self.slave.bus) + + self.submodules.sdrphy = self.sdrphy = sdrphy + self.dfi = dfi + self.pads = pads + + self.specials += Instance("mt48lc4m16a2", + io_Dq=pads.dq, + i_Addr=pads.a, + i_Ba=pads.ba, + i_Clk=ClockSignal(), + i_Cke=pads.cke, + i_Cs_n=pads.cs_n, + i_Ras_n=pads.ras_n, + i_Cas_n=pads.cas_n, + i_We_n=pads.we_n, + i_Dqm=pads.dm + ) + + def genxfers(self): + cycle = 0 + for a in chain(range(4),range(256,260),range(1024,1028)): + t = TRead(a) + yield t + print("read {} in {} cycles".format(t.data, t.latency)) + for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): + t = TWrite(a, 0xaa55aa55+cycle) + cycle += 1 + yield t + print("read {} in {} cycles".format(t.data, t.latency)) + for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): + t = TRead(a) + yield t + print("read {} in {} cycles".format(t.data, t.latency)) + + def gen_simulation(self, selfp): + dfi = selfp.dfi + phy = self.sdrphy + rdphase = phy.settings.rdphase + cycle = 0 + + while True: + yield class MyTopLevel: - def __init__(self, vcd_name=None, vcd_level=1, - top_name="top", dut_type="dut", dut_name="dut", - cd_name="sys", clk_period=10): - self.vcd_name = vcd_name - self.vcd_level = vcd_level - self.top_name = top_name - self.dut_type = dut_type - self.dut_name = dut_name - - self._cd_name = cd_name - self._clk_period = clk_period - - cd = ClockDomain(self._cd_name) - cd_ps = ClockDomain("sys_ps") - self.clock_domains = [cd, cd_ps] - self.ios = {cd.clk, cd.rst, cd_ps.clk} - - def get(self, sockaddr): - template1 = """`timescale 1ns / 1ps + def __init__(self, vcd_name=None, vcd_level=1, + top_name="top", dut_type="dut", dut_name="dut", + cd_name="sys", clk_period=10): + self.vcd_name = vcd_name + self.vcd_level = vcd_level + self.top_name = top_name + self.dut_type = dut_type + self.dut_name = dut_name + + self._cd_name = cd_name + self._clk_period = clk_period + + cd = ClockDomain(self._cd_name) + cd_ps = ClockDomain("sys_ps") + self.clock_domains = [cd, cd_ps] + self.ios = {cd.clk, cd.rst, cd_ps.clk} + + def get(self, sockaddr): + template1 = """`timescale 1ns / 1ps module {top_name}(); @@ -104,89 +104,89 @@ reg {rst_name}; reg sys_ps_clk; initial begin - {rst_name} <= 1'b1; - @(posedge {clk_name}); - {rst_name} <= 1'b0; + {rst_name} <= 1'b1; + @(posedge {clk_name}); + {rst_name} <= 1'b0; end always begin - {clk_name} <= 1'b0; - #{hclk_period}; - {clk_name} <= 1'b1; - #{hclk_period}; + {clk_name} <= 1'b0; + #{hclk_period}; + {clk_name} <= 1'b1; + #{hclk_period}; end always @(posedge {clk_name} or negedge {clk_name}) - sys_ps_clk <= #({hclk_period}*2-3) {clk_name}; + sys_ps_clk <= #({hclk_period}*2-3) {clk_name}; {dut_type} {dut_name}( - .{rst_name}({rst_name}), - .{clk_name}({clk_name}), - .sys_ps_clk(sys_ps_clk) + .{rst_name}({rst_name}), + .{clk_name}({clk_name}), + .sys_ps_clk(sys_ps_clk) ); initial $migensim_connect("{sockaddr}"); always @(posedge {clk_name}) $migensim_tick; """ - template2 = """ + template2 = """ initial begin - $dumpfile("{vcd_name}"); - $dumpvars({vcd_level}, {dut_name}); + $dumpfile("{vcd_name}"); + $dumpvars({vcd_level}, {dut_name}); end """ - r = template1.format(top_name=self.top_name, - dut_type=self.dut_type, - dut_name=self.dut_name, - clk_name=self._cd_name + "_clk", - rst_name=self._cd_name + "_rst", - hclk_period=str(self._clk_period/2), - sockaddr=sockaddr) - if self.vcd_name is not None: - r += template2.format(vcd_name=self.vcd_name, - vcd_level=str(self.vcd_level), - dut_name=self.dut_name) - r += "\nendmodule" - return r + r = template1.format(top_name=self.top_name, + dut_type=self.dut_type, + dut_name=self.dut_name, + clk_name=self._cd_name + "_clk", + rst_name=self._cd_name + "_rst", + hclk_period=str(self._clk_period/2), + sockaddr=sockaddr) + if self.vcd_name is not None: + r += template2.format(vcd_name=self.vcd_name, + vcd_level=str(self.vcd_level), + dut_name=self.dut_name) + r += "\nendmodule" + return r if __name__ == "__main__": - plat = board.Platform() + plat = board.Platform() - sdram_geom = sdram.GeomSettings( - bankbits=2, - rowbits=12, - colbits=8 - ) + sdram_geom = sdram.GeomSettings( + bankbits=2, + rowbits=12, + colbits=8 + ) - sdram_timing = sdram.TimingSettings( - tRP=ns(15), - tRCD=ns(15), - tWR=ns(14), - tWTR=2, - tREFI=ns(64*1000*1000/4096, False), - tRFC=ns(66), - req_queue_size=8, - read_time=32, - write_time=16 - ) + sdram_timing = sdram.TimingSettings( + tRP=ns(15), + tRCD=ns(15), + tWR=ns(14), + tWTR=2, + tREFI=ns(64*1000*1000/4096, False), + tRFC=ns(66), + req_queue_size=8, + read_time=32, + write_time=16 + ) - sdram_pads = plat.request("sdram") - sdram_clk = plat.request("sdram_clock") + sdram_pads = plat.request("sdram") + sdram_clk = plat.request("sdram_clock") - sdrphy = gensdrphy.GENSDRPHY(sdram_pads) + sdrphy = gensdrphy.GENSDRPHY(sdram_pads) # This sets CL to 2 during LMR done on 1st cycle - sdram_pads.a.reset = 1<<5 + sdram_pads.a.reset = 1<<5 - s = MiniconTB(sdrphy, sdrphy.dfi, sdram_geom, sdram_timing, pads=sdram_pads, sdram_clk=sdram_clk) + s = MiniconTB(sdrphy, sdrphy.dfi, sdram_geom, sdram_timing, pads=sdram_pads, sdram_clk=sdram_clk) - extra_files = [ "sdram_model/mt48lc4m16a2.v" ] + extra_files = [ "sdram_model/mt48lc4m16a2.v" ] - if not isfile(extra_files[0]): - print("ERROR: You need to download Micron Verilog simulation model for MT48LC4M16A2 and put it in sdram_model/mt48lc4m16a2.v") - print("File can be downloaded from this URL: http://www.micron.com/-/media/documents/products/sim%20model/dram/dram/4054mt48lc4m16a2.zip") - sys.exit(1) + if not isfile(extra_files[0]): + print("ERROR: You need to download Micron Verilog simulation model for MT48LC4M16A2 and put it in sdram_model/mt48lc4m16a2.v") + print("File can be downloaded from this URL: http://www.micron.com/-/media/documents/products/sim%20model/dram/dram/4054mt48lc4m16a2.zip") + sys.exit(1) - with Simulator(s, MyTopLevel("top.vcd", clk_period=int(1/0.08)), icarus.Runner(extra_files=extra_files, keep_files=True)) as sim: - sim.run(5000) + with Simulator(s, MyTopLevel("top.vcd", clk_period=int(1/0.08)), icarus.Runner(extra_files=extra_files, keep_files=True)) as sim: + sim.run(5000) diff --git a/misoclib/mem/sdram/test/refresher.py b/misoclib/mem/sdram/test/refresher.py index 00caa497..00a39887 100644 --- a/misoclib/mem/sdram/test/refresher.py +++ b/misoclib/mem/sdram/test/refresher.py @@ -8,38 +8,38 @@ from misoclib.mem.sdram.core.lasmicon.refresher import * from common import CommandLogger class Granter(Module): - def __init__(self, req, ack): - self.req = req - self.ack = ack - self.state = 0 - self.prng = Random(92837) - - def do_simulation(self, selfp): - elts = ["@" + str(selfp.simulator.cycle_counter)] - - if self.state == 0: - if selfp.req: - elts.append("Refresher requested access") - self.state = 1 - elif self.state == 1: - if self.prng.randrange(0, 5) == 0: - elts.append("Granted access to refresher") - selfp.ack = 1 - self.state = 2 - elif self.state == 2: - if not selfp.req: - elts.append("Refresher released access") - selfp.ack = 0 - self.state = 0 - - if len(elts) > 1: - print("\t".join(elts)) + def __init__(self, req, ack): + self.req = req + self.ack = ack + self.state = 0 + self.prng = Random(92837) + + def do_simulation(self, selfp): + elts = ["@" + str(selfp.simulator.cycle_counter)] + + if self.state == 0: + if selfp.req: + elts.append("Refresher requested access") + self.state = 1 + elif self.state == 1: + if self.prng.randrange(0, 5) == 0: + elts.append("Granted access to refresher") + selfp.ack = 1 + self.state = 2 + elif self.state == 2: + if not selfp.req: + elts.append("Refresher released access") + selfp.ack = 0 + self.state = 0 + + if len(elts) > 1: + print("\t".join(elts)) class TB(Module): - def __init__(self): - self.submodules.dut = Refresher(13, 2, tRP=3, tREFI=100, tRFC=5) - self.submodules.logger = CommandLogger(self.dut.cmd) - self.submodules.granter = Granter(self.dut.req, self.dut.ack) + def __init__(self): + self.submodules.dut = Refresher(13, 2, tRP=3, tREFI=100, tRFC=5) + self.submodules.logger = CommandLogger(self.dut.cmd) + self.submodules.granter = Granter(self.dut.req, self.dut.ack) if __name__ == "__main__": - run_simulation(TB(), ncycles=400) + run_simulation(TB(), ncycles=400) diff --git a/misoclib/others/mxcrg/__init__.py b/misoclib/others/mxcrg/__init__.py index 986e255b..cb0e60e0 100644 --- a/misoclib/others/mxcrg/__init__.py +++ b/misoclib/others/mxcrg/__init__.py @@ -3,38 +3,38 @@ from fractions import Fraction from migen.fhdl.std import * class MXCRG(Module): - def __init__(self, pads, outfreq1x): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sdram_half = ClockDomain() - self.clock_domains.cd_sdram_full_wr = ClockDomain() - self.clock_domains.cd_sdram_full_rd = ClockDomain() - self.clock_domains.cd_base50 = ClockDomain(reset_less=True) - - self.clk4x_wr_strb = Signal() - self.clk4x_rd_strb = Signal() - - ### - - infreq = 50*1000000 - ratio = Fraction(outfreq1x)/Fraction(infreq) - in_period = float(Fraction(1000000000)/Fraction(infreq)) - - self.specials += Instance("mxcrg", - Instance.Parameter("in_period", in_period), - Instance.Parameter("f_mult", ratio.numerator), - Instance.Parameter("f_div", ratio.denominator), - Instance.Input("clk50_pad", pads.clk50), - Instance.Input("trigger_reset", pads.trigger_reset), - - Instance.Output("sys_clk", self.cd_sys.clk), - Instance.Output("sys_rst", self.cd_sys.rst), - Instance.Output("clk2x_270", self.cd_sdram_half.clk), - Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk), - Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk), - Instance.Output("base50_clk", self.cd_base50.clk), - - Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb), - Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb), - Instance.Output("norflash_rst_n", pads.norflash_rst_n), - Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p), - Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n)) + def __init__(self, pads, outfreq1x): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sdram_half = ClockDomain() + self.clock_domains.cd_sdram_full_wr = ClockDomain() + self.clock_domains.cd_sdram_full_rd = ClockDomain() + self.clock_domains.cd_base50 = ClockDomain(reset_less=True) + + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() + + ### + + infreq = 50*1000000 + ratio = Fraction(outfreq1x)/Fraction(infreq) + in_period = float(Fraction(1000000000)/Fraction(infreq)) + + self.specials += Instance("mxcrg", + Instance.Parameter("in_period", in_period), + Instance.Parameter("f_mult", ratio.numerator), + Instance.Parameter("f_div", ratio.denominator), + Instance.Input("clk50_pad", pads.clk50), + Instance.Input("trigger_reset", pads.trigger_reset), + + Instance.Output("sys_clk", self.cd_sys.clk), + Instance.Output("sys_rst", self.cd_sys.rst), + Instance.Output("clk2x_270", self.cd_sdram_half.clk), + Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk), + Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk), + Instance.Output("base50_clk", self.cd_base50.clk), + + Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb), + Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb), + Instance.Output("norflash_rst_n", pads.norflash_rst_n), + Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p), + Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n)) diff --git a/misoclib/soc/__init__.py b/misoclib/soc/__init__.py index ada3e9e4..b9b56226 100644 --- a/misoclib/soc/__init__.py +++ b/misoclib/soc/__init__.py @@ -10,190 +10,190 @@ from misoclib.cpu import lm32, mor1kx from misoclib.cpu.peripherals import identifier, timer def mem_decoder(address, start=26, end=29): - return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1) + return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1) class SoC(Module): - csr_map = { - "crg": 0, # user - "uart_phy": 1, # provided by default (optional) - "uart": 2, # provided by default (optional) - "identifier": 3, # provided by default (optional) - "timer0": 4, # provided by default (optional) - "buttons": 5, # user - "leds": 6, # user - } - interrupt_map = { - "uart": 0, - "timer0": 1, - } - mem_map = { - "rom": 0x00000000, # (shadow @0x80000000) - "sram": 0x10000000, # (shadow @0x90000000) - "main_ram": 0x40000000, # (shadow @0xc0000000) - "csr": 0x60000000, # (shadow @0xe0000000) - } - def __init__(self, platform, clk_freq, - cpu_type="lm32", cpu_reset_address=0x00000000, - integrated_rom_size=0, - integrated_sram_size=4096, - integrated_main_ram_size=0, - with_csr=True, csr_data_width=8, csr_address_width=14, - with_uart=True, uart_baudrate=115200, - with_identifier=True, - with_timer=True): - self.platform = platform - self.clk_freq = clk_freq - - self.cpu_type = cpu_type - if integrated_rom_size: - cpu_reset_address = 0 - self.cpu_reset_address = cpu_reset_address - - self.integrated_rom_size = integrated_rom_size - self.integrated_sram_size = integrated_sram_size - self.integrated_main_ram_size = integrated_main_ram_size - - self.with_uart = with_uart - self.uart_baudrate = uart_baudrate - - self.with_identifier = with_identifier - - self.with_csr = with_csr - self.csr_data_width = csr_data_width - self.csr_address_width = csr_address_width - - self._memory_regions = [] # list of (name, origin, length) - self._csr_regions = [] # list of (name, origin, busword, csr_list/Memory) - self._constants = [] # list of (name, value) - - self._wb_masters = [] - self._wb_slaves = [] - - if cpu_type != "none": - if cpu_type == "lm32": - self.add_cpu_or_bridge(lm32.LM32(platform, self.cpu_reset_address)) - elif cpu_type == "or1k": - self.add_cpu_or_bridge(mor1kx.MOR1KX(platform, self.cpu_reset_address)) - else: - raise ValueError("Unsupported CPU type: {}".format(cpu_type)) - self.add_wb_master(self.cpu_or_bridge.ibus) - self.add_wb_master(self.cpu_or_bridge.dbus) - - if integrated_rom_size: - self.submodules.rom = wishbone.SRAM(integrated_rom_size, read_only=True) - self.register_rom(self.rom.bus, integrated_rom_size) - - if integrated_sram_size: - self.submodules.sram = wishbone.SRAM(integrated_sram_size) - self.register_mem("sram", self.mem_map["sram"], self.sram.bus, integrated_sram_size) - - # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping. - if integrated_main_ram_size: - self.submodules.main_ram = wishbone.SRAM(integrated_main_ram_size) - self.register_mem("main_ram", self.mem_map["main_ram"], self.main_ram.bus, integrated_main_ram_size) - - if with_csr: - self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(csr_data_width, csr_address_width)) - self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone) - - if with_uart: - self.submodules.uart_phy = UARTPHY(platform.request("serial"), clk_freq, uart_baudrate) - self.submodules.uart = uart.UART(self.uart_phy) - - if with_identifier: - platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier - self.submodules.identifier = identifier.Identifier(platform_id, int(clk_freq)) - - if with_timer: - self.submodules.timer0 = timer.Timer() - - def add_cpu_or_bridge(self, cpu_or_bridge): - if self.finalized: - raise FinalizeError - if hasattr(self, "cpu_or_bridge"): - raise NotImplementedError("More than one CPU is not supported") - self.submodules.cpu_or_bridge = cpu_or_bridge - - def init_rom(self, data): - self.rom.mem.init = data - - def add_wb_master(self, wbm): - if self.finalized: - raise FinalizeError - self._wb_masters.append(wbm) - - def add_wb_slave(self, address_decoder, interface): - if self.finalized: - raise FinalizeError - self._wb_slaves.append((address_decoder, interface)) - - def add_memory_region(self, name, origin, length): - def in_this_region(addr): - return addr >= origin and addr < origin + length - for n, o, l in self._memory_regions: - if n == name or in_this_region(o) or in_this_region(o+l-1): - raise ValueError("Memory region conflict between {} and {}".format(n, name)) - - self._memory_regions.append((name, origin, length)) - - def register_mem(self, name, address, interface, size=None): - self.add_wb_slave(mem_decoder(address), interface) - if size is not None: - self.add_memory_region(name, address, size) - - def register_rom(self, interface, rom_size=0xa000): - self.add_wb_slave(mem_decoder(self.mem_map["rom"]), interface) - self.add_memory_region("rom", self.cpu_reset_address, rom_size) - - def get_memory_regions(self): - return self._memory_regions - - def check_csr_region(self, name, origin): - for n, o, l, obj in self._csr_regions: - if n == name or o == origin: - raise ValueError("CSR region conflict between {} and {}".format(n, name)) - - def add_csr_region(self, name, origin, busword, obj): - self.check_csr_region(name, origin) - self._csr_regions.append((name, origin, busword, obj)) - - def get_csr_regions(self): - return self._csr_regions - - def add_constant(self, name, value): - self._constants.append((name, value)) - - def get_constants(self): - r = [] - for name, interrupt in sorted(self.interrupt_map.items(), key=itemgetter(1)): - r.append((name.upper() + "_INTERRUPT", interrupt)) - r += self._constants - return r - - def do_finalize(self): - registered_mems = {regions[0] for regions in self._memory_regions} - if self.cpu_type != "none": - for mem in "rom", "sram": - if mem not in registered_mems: - raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem)) - - # Wishbone - self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters, - self._wb_slaves, register=True) - - # CSR - if self.with_csr: - self.submodules.csrbankarray = csrgen.BankArray(self, - lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override], - data_width=self.csr_data_width, address_width=self.csr_address_width) - self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses()) - for name, csrs, mapaddr, rmap in self.csrbankarray.banks: - self.add_csr_region(name, self.mem_map["csr"]+0x80000000+0x800*mapaddr, self.csr_data_width, csrs) - for name, memory, mapaddr, mmap in self.csrbankarray.srams: - self.add_csr_region(name + "_" + memory.name_override, self.mem_map["csr"]+0x80000000+0x800*mapaddr, self.csr_data_width, memory) - - # Interrupts - if hasattr(self.cpu_or_bridge, "interrupt"): - for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)): - if hasattr(self, k): - self.comb += self.cpu_or_bridge.interrupt[v].eq(getattr(self, k).ev.irq) + csr_map = { + "crg": 0, # user + "uart_phy": 1, # provided by default (optional) + "uart": 2, # provided by default (optional) + "identifier": 3, # provided by default (optional) + "timer0": 4, # provided by default (optional) + "buttons": 5, # user + "leds": 6, # user + } + interrupt_map = { + "uart": 0, + "timer0": 1, + } + mem_map = { + "rom": 0x00000000, # (shadow @0x80000000) + "sram": 0x10000000, # (shadow @0x90000000) + "main_ram": 0x40000000, # (shadow @0xc0000000) + "csr": 0x60000000, # (shadow @0xe0000000) + } + def __init__(self, platform, clk_freq, + cpu_type="lm32", cpu_reset_address=0x00000000, + integrated_rom_size=0, + integrated_sram_size=4096, + integrated_main_ram_size=0, + with_csr=True, csr_data_width=8, csr_address_width=14, + with_uart=True, uart_baudrate=115200, + with_identifier=True, + with_timer=True): + self.platform = platform + self.clk_freq = clk_freq + + self.cpu_type = cpu_type + if integrated_rom_size: + cpu_reset_address = 0 + self.cpu_reset_address = cpu_reset_address + + self.integrated_rom_size = integrated_rom_size + self.integrated_sram_size = integrated_sram_size + self.integrated_main_ram_size = integrated_main_ram_size + + self.with_uart = with_uart + self.uart_baudrate = uart_baudrate + + self.with_identifier = with_identifier + + self.with_csr = with_csr + self.csr_data_width = csr_data_width + self.csr_address_width = csr_address_width + + self._memory_regions = [] # list of (name, origin, length) + self._csr_regions = [] # list of (name, origin, busword, csr_list/Memory) + self._constants = [] # list of (name, value) + + self._wb_masters = [] + self._wb_slaves = [] + + if cpu_type != "none": + if cpu_type == "lm32": + self.add_cpu_or_bridge(lm32.LM32(platform, self.cpu_reset_address)) + elif cpu_type == "or1k": + self.add_cpu_or_bridge(mor1kx.MOR1KX(platform, self.cpu_reset_address)) + else: + raise ValueError("Unsupported CPU type: {}".format(cpu_type)) + self.add_wb_master(self.cpu_or_bridge.ibus) + self.add_wb_master(self.cpu_or_bridge.dbus) + + if integrated_rom_size: + self.submodules.rom = wishbone.SRAM(integrated_rom_size, read_only=True) + self.register_rom(self.rom.bus, integrated_rom_size) + + if integrated_sram_size: + self.submodules.sram = wishbone.SRAM(integrated_sram_size) + self.register_mem("sram", self.mem_map["sram"], self.sram.bus, integrated_sram_size) + + # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping. + if integrated_main_ram_size: + self.submodules.main_ram = wishbone.SRAM(integrated_main_ram_size) + self.register_mem("main_ram", self.mem_map["main_ram"], self.main_ram.bus, integrated_main_ram_size) + + if with_csr: + self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(csr_data_width, csr_address_width)) + self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone) + + if with_uart: + self.submodules.uart_phy = UARTPHY(platform.request("serial"), clk_freq, uart_baudrate) + self.submodules.uart = uart.UART(self.uart_phy) + + if with_identifier: + platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier + self.submodules.identifier = identifier.Identifier(platform_id, int(clk_freq)) + + if with_timer: + self.submodules.timer0 = timer.Timer() + + def add_cpu_or_bridge(self, cpu_or_bridge): + if self.finalized: + raise FinalizeError + if hasattr(self, "cpu_or_bridge"): + raise NotImplementedError("More than one CPU is not supported") + self.submodules.cpu_or_bridge = cpu_or_bridge + + def init_rom(self, data): + self.rom.mem.init = data + + def add_wb_master(self, wbm): + if self.finalized: + raise FinalizeError + self._wb_masters.append(wbm) + + def add_wb_slave(self, address_decoder, interface): + if self.finalized: + raise FinalizeError + self._wb_slaves.append((address_decoder, interface)) + + def add_memory_region(self, name, origin, length): + def in_this_region(addr): + return addr >= origin and addr < origin + length + for n, o, l in self._memory_regions: + if n == name or in_this_region(o) or in_this_region(o+l-1): + raise ValueError("Memory region conflict between {} and {}".format(n, name)) + + self._memory_regions.append((name, origin, length)) + + def register_mem(self, name, address, interface, size=None): + self.add_wb_slave(mem_decoder(address), interface) + if size is not None: + self.add_memory_region(name, address, size) + + def register_rom(self, interface, rom_size=0xa000): + self.add_wb_slave(mem_decoder(self.mem_map["rom"]), interface) + self.add_memory_region("rom", self.cpu_reset_address, rom_size) + + def get_memory_regions(self): + return self._memory_regions + + def check_csr_region(self, name, origin): + for n, o, l, obj in self._csr_regions: + if n == name or o == origin: + raise ValueError("CSR region conflict between {} and {}".format(n, name)) + + def add_csr_region(self, name, origin, busword, obj): + self.check_csr_region(name, origin) + self._csr_regions.append((name, origin, busword, obj)) + + def get_csr_regions(self): + return self._csr_regions + + def add_constant(self, name, value): + self._constants.append((name, value)) + + def get_constants(self): + r = [] + for name, interrupt in sorted(self.interrupt_map.items(), key=itemgetter(1)): + r.append((name.upper() + "_INTERRUPT", interrupt)) + r += self._constants + return r + + def do_finalize(self): + registered_mems = {regions[0] for regions in self._memory_regions} + if self.cpu_type != "none": + for mem in "rom", "sram": + if mem not in registered_mems: + raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem)) + + # Wishbone + self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters, + self._wb_slaves, register=True) + + # CSR + if self.with_csr: + self.submodules.csrbankarray = csrgen.BankArray(self, + lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override], + data_width=self.csr_data_width, address_width=self.csr_address_width) + self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses()) + for name, csrs, mapaddr, rmap in self.csrbankarray.banks: + self.add_csr_region(name, self.mem_map["csr"]+0x80000000+0x800*mapaddr, self.csr_data_width, csrs) + for name, memory, mapaddr, mmap in self.csrbankarray.srams: + self.add_csr_region(name + "_" + memory.name_override, self.mem_map["csr"]+0x80000000+0x800*mapaddr, self.csr_data_width, memory) + + # Interrupts + if hasattr(self.cpu_or_bridge, "interrupt"): + for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)): + if hasattr(self, k): + self.comb += self.cpu_or_bridge.interrupt[v].eq(getattr(self, k).ev.irq) diff --git a/misoclib/soc/cpuif.py b/misoclib/soc/cpuif.py index 48d77604..c35c134e 100644 --- a/misoclib/soc/cpuif.py +++ b/misoclib/soc/cpuif.py @@ -2,98 +2,98 @@ from migen.fhdl.std import * from migen.bank.description import CSRStatus def get_cpu_mak(cpu_type): - if cpu_type == "lm32": - cpuflags = "-mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled -msign-extend-enabled" - elif cpu_type == "or1k": - cpuflags = "-mhard-mul -mhard-div" - else: - raise ValueError("Unsupported CPU type: "+cpu_type) - return "CPU={}\nCPUFLAGS={}\n".format(cpu_type, cpuflags) + if cpu_type == "lm32": + cpuflags = "-mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled -msign-extend-enabled" + elif cpu_type == "or1k": + cpuflags = "-mhard-mul -mhard-div" + else: + raise ValueError("Unsupported CPU type: "+cpu_type) + return "CPU={}\nCPUFLAGS={}\n".format(cpu_type, cpuflags) def get_linker_output_format(cpu_type): - return "OUTPUT_FORMAT(\"elf32-{}\")\n".format(cpu_type) + return "OUTPUT_FORMAT(\"elf32-{}\")\n".format(cpu_type) def get_linker_regions(regions): - r = "MEMORY {\n" - for name, origin, length in regions: - r += "\t{} : ORIGIN = 0x{:08x}, LENGTH = 0x{:08x}\n".format(name, origin, length) - r += "}\n" - return r + r = "MEMORY {\n" + for name, origin, length in regions: + r += "\t{} : ORIGIN = 0x{:08x}, LENGTH = 0x{:08x}\n".format(name, origin, length) + r += "}\n" + return r def get_mem_header(regions, flash_boot_address): - r = "#ifndef __GENERATED_MEM_H\n#define __GENERATED_MEM_H\n\n" - for name, base, size in regions: - r += "#define {name}_BASE 0x{base:08x}\n#define {name}_SIZE 0x{size:08x}\n\n".format(name=name.upper(), base=base, size=size) - if flash_boot_address is not None: - r += "#define FLASH_BOOT_ADDRESS 0x{:08x}\n\n".format(flash_boot_address) - r += "#endif\n" - return r + r = "#ifndef __GENERATED_MEM_H\n#define __GENERATED_MEM_H\n\n" + for name, base, size in regions: + r += "#define {name}_BASE 0x{base:08x}\n#define {name}_SIZE 0x{size:08x}\n\n".format(name=name.upper(), base=base, size=size) + if flash_boot_address is not None: + r += "#define FLASH_BOOT_ADDRESS 0x{:08x}\n\n".format(flash_boot_address) + r += "#endif\n" + return r def _get_rw_functions(reg_name, reg_base, nwords, busword, read_only): - r = "" + r = "" - r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n" - r += "#define CSR_"+reg_name.upper()+"_SIZE "+str(nwords)+"\n" + r += "#define CSR_"+reg_name.upper()+"_ADDR "+hex(reg_base)+"\n" + r += "#define CSR_"+reg_name.upper()+"_SIZE "+str(nwords)+"\n" - size = nwords*busword - if size > 64: - return r - elif size > 32: - ctype = "unsigned long long int" - elif size > 16: - ctype = "unsigned int" - elif size > 8: - ctype = "unsigned short int" - else: - ctype = "unsigned char" + size = nwords*busword + if size > 64: + return r + elif size > 32: + ctype = "unsigned long long int" + elif size > 16: + ctype = "unsigned int" + elif size > 8: + ctype = "unsigned short int" + else: + ctype = "unsigned char" - r += "static inline "+ctype+" "+reg_name+"_read(void) {\n" - if size > 1: - r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n" - for byte in range(1, nwords): - r += "\tr <<= "+str(busword)+";\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n" - r += "\treturn r;\n}\n" - else: - r += "\treturn MMPTR("+hex(reg_base)+");\n}\n" + r += "static inline "+ctype+" "+reg_name+"_read(void) {\n" + if size > 1: + r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n" + for byte in range(1, nwords): + r += "\tr <<= "+str(busword)+";\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n" + r += "\treturn r;\n}\n" + else: + r += "\treturn MMPTR("+hex(reg_base)+");\n}\n" - if not read_only: - r += "static inline void "+reg_name+"_write("+ctype+" value) {\n" - for word in range(nwords): - shift = (nwords-word-1)*busword - if shift: - value_shifted = "value >> "+str(shift) - else: - value_shifted = "value" - r += "\tMMPTR("+hex(reg_base+4*word)+") = "+value_shifted+";\n" - r += "}\n" - return r + if not read_only: + r += "static inline void "+reg_name+"_write("+ctype+" value) {\n" + for word in range(nwords): + shift = (nwords-word-1)*busword + if shift: + value_shifted = "value >> "+str(shift) + else: + value_shifted = "value" + r += "\tMMPTR("+hex(reg_base+4*word)+") = "+value_shifted+";\n" + r += "}\n" + return r def get_csr_header(regions, constants): - r = "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n#include \n" - for name, origin, busword, obj in regions: - if isinstance(obj, Memory): - r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n" - else: - r += "\n/* "+name+" */\n" - r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n" - for csr in obj: - nr = (csr.size + busword - 1)//busword - r += _get_rw_functions(name + "_" + csr.name, origin, nr, busword, isinstance(csr, CSRStatus)) - origin += 4*nr + r = "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n#include \n" + for name, origin, busword, obj in regions: + if isinstance(obj, Memory): + r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n" + else: + r += "\n/* "+name+" */\n" + r += "#define CSR_"+name.upper()+"_BASE "+hex(origin)+"\n" + for csr in obj: + nr = (csr.size + busword - 1)//busword + r += _get_rw_functions(name + "_" + csr.name, origin, nr, busword, isinstance(csr, CSRStatus)) + origin += 4*nr - r += "\n/* constants */\n" - for name, value in constants: - r += "#define " + name + " " + str(value) + "\n" + r += "\n/* constants */\n" + for name, value in constants: + r += "#define " + name + " " + str(value) + "\n" - r += "\n#endif\n" - return r + r += "\n#endif\n" + return r def get_csr_csv(regions): - r = "" - for name, origin, busword, obj in regions: - if not isinstance(obj, Memory): - for csr in obj: - nr = (csr.size + busword - 1)//busword - r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, origin, nr, "ro" if isinstance(csr, CSRStatus) else "rw") - origin += 4*nr - return r + r = "" + for name, origin, busword, obj in regions: + if not isinstance(obj, Memory): + for csr in obj: + nr = (csr.size + busword - 1)//busword + r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, origin, nr, "ro" if isinstance(csr, CSRStatus) else "rw") + origin += 4*nr + return r diff --git a/misoclib/soc/sdram.py b/misoclib/soc/sdram.py index 2097c54e..05bbdec6 100644 --- a/misoclib/soc/sdram.py +++ b/misoclib/soc/sdram.py @@ -9,76 +9,76 @@ from misoclib.mem.sdram.frontend import memtest, wishbone2lasmi from misoclib.soc import SoC class SDRAMSoC(SoC): - csr_map = { - "sdram": 8, - "wishbone2lasmi": 9, - "memtest_w": 10, - "memtest_r": 11 - } - csr_map.update(SoC.csr_map) + csr_map = { + "sdram": 8, + "wishbone2lasmi": 9, + "memtest_w": 10, + "memtest_r": 11 + } + csr_map.update(SoC.csr_map) - def __init__(self, platform, clk_freq, sdram_controller_settings, - **kwargs): - SoC.__init__(self, platform, clk_freq, **kwargs) - if isinstance(sdram_controller_settings, str): - self.sdram_controller_settings = eval(sdram_controller_settings) - else: - self.sdram_controller_settings = sdram_controller_settings - self._sdram_phy_registered = False + def __init__(self, platform, clk_freq, sdram_controller_settings, + **kwargs): + SoC.__init__(self, platform, clk_freq, **kwargs) + if isinstance(sdram_controller_settings, str): + self.sdram_controller_settings = eval(sdram_controller_settings) + else: + self.sdram_controller_settings = sdram_controller_settings + self._sdram_phy_registered = False - def register_sdram_phy(self, phy): - if self._sdram_phy_registered: - raise FinalizeError - self._sdram_phy_registered = True - if isinstance(self.sdram_controller_settings, MiniconSettings) and phy.settings.memtype != "SDR": - raise NotImplementedError("Minicon only supports SDR memtype for now (" + phy.settings.memtype + ")") + def register_sdram_phy(self, phy): + if self._sdram_phy_registered: + raise FinalizeError + self._sdram_phy_registered = True + if isinstance(self.sdram_controller_settings, MiniconSettings) and phy.settings.memtype != "SDR": + raise NotImplementedError("Minicon only supports SDR memtype for now (" + phy.settings.memtype + ")") - # Core - self.submodules.sdram = SDRAMCore(phy, phy.module.geom_settings, phy.module.timing_settings, self.sdram_controller_settings) + # Core + self.submodules.sdram = SDRAMCore(phy, phy.module.geom_settings, phy.module.timing_settings, self.sdram_controller_settings) - dfi_databits_divisor = 1 if phy.settings.memtype == "SDR" else 2 - sdram_width = phy.settings.dfi_databits//dfi_databits_divisor - main_ram_size = 2**(phy.module.geom_settings.bankbits+ - phy.module.geom_settings.rowbits+ - phy.module.geom_settings.colbits)*sdram_width//8 - # XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories. - main_ram_size = min(main_ram_size, 256*1024*1024) + dfi_databits_divisor = 1 if phy.settings.memtype == "SDR" else 2 + sdram_width = phy.settings.dfi_databits//dfi_databits_divisor + main_ram_size = 2**(phy.module.geom_settings.bankbits+ + phy.module.geom_settings.rowbits+ + phy.module.geom_settings.colbits)*sdram_width//8 + # XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories. + main_ram_size = min(main_ram_size, 256*1024*1024) - # LASMICON frontend - if isinstance(self.sdram_controller_settings, LASMIconSettings): - if self.sdram_controller_settings.with_bandwidth: - self.sdram.controller.multiplexer.add_bandwidth() + # LASMICON frontend + if isinstance(self.sdram_controller_settings, LASMIconSettings): + if self.sdram_controller_settings.with_bandwidth: + self.sdram.controller.multiplexer.add_bandwidth() - if self.sdram_controller_settings.with_memtest: - self.submodules.memtest_w = memtest.MemtestWriter(self.sdram.crossbar.get_master()) - self.submodules.memtest_r = memtest.MemtestReader(self.sdram.crossbar.get_master()) + if self.sdram_controller_settings.with_memtest: + self.submodules.memtest_w = memtest.MemtestWriter(self.sdram.crossbar.get_master()) + self.submodules.memtest_r = memtest.MemtestReader(self.sdram.crossbar.get_master()) - l2_size = self.sdram_controller_settings.l2_size - if l2_size: - # XXX Vivado 2014.X workaround, Vivado is not able to map correctly our L2 cache. - # Issue is reported to Xilinx and should be fixed in next releases (2015.1?). - # Remove this workaround when fixed by Xilinx. - from mibuild.xilinx.vivado import XilinxVivadoToolchain - if isinstance(self.platform.toolchain, XilinxVivadoToolchain): - from migen.fhdl.simplify import FullMemoryWE - self.submodules.wishbone2lasmi = FullMemoryWE()(wishbone2lasmi.WB2LASMI(l2_size//4, self.sdram.crossbar.get_master())) - else: - self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(l2_size//4, self.sdram.crossbar.get_master()) - self.register_mem("main_ram", self.mem_map["main_ram"], self.wishbone2lasmi.wishbone, main_ram_size) + l2_size = self.sdram_controller_settings.l2_size + if l2_size: + # XXX Vivado 2014.X workaround, Vivado is not able to map correctly our L2 cache. + # Issue is reported to Xilinx and should be fixed in next releases (2015.1?). + # Remove this workaround when fixed by Xilinx. + from mibuild.xilinx.vivado import XilinxVivadoToolchain + if isinstance(self.platform.toolchain, XilinxVivadoToolchain): + from migen.fhdl.simplify import FullMemoryWE + self.submodules.wishbone2lasmi = FullMemoryWE()(wishbone2lasmi.WB2LASMI(l2_size//4, self.sdram.crossbar.get_master())) + else: + self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(l2_size//4, self.sdram.crossbar.get_master()) + self.register_mem("main_ram", self.mem_map["main_ram"], self.wishbone2lasmi.wishbone, main_ram_size) - # MINICON frontend - elif isinstance(self.sdram_controller_settings, MiniconSettings): - if sdram_width == 32: - self.register_mem("main_ram", self.mem_map["main_ram"], self.sdram.controller.bus, main_ram_size) - elif sdram_width < 32: - self.submodules.downconverter = downconverter = wishbone.DownConverter(32, sdram_width) - self.comb += Record.connect(downconverter.wishbone_o, self.sdram.controller.bus) - self.register_mem("main_ram", self.mem_map["main_ram"], downconverter.wishbone_i, main_ram_size) - else: - raise NotImplementedError("Unsupported SDRAM width of {} > 32".format(sdram_width)) + # MINICON frontend + elif isinstance(self.sdram_controller_settings, MiniconSettings): + if sdram_width == 32: + self.register_mem("main_ram", self.mem_map["main_ram"], self.sdram.controller.bus, main_ram_size) + elif sdram_width < 32: + self.submodules.downconverter = downconverter = wishbone.DownConverter(32, sdram_width) + self.comb += Record.connect(downconverter.wishbone_o, self.sdram.controller.bus) + self.register_mem("main_ram", self.mem_map["main_ram"], downconverter.wishbone_i, main_ram_size) + else: + raise NotImplementedError("Unsupported SDRAM width of {} > 32".format(sdram_width)) - def do_finalize(self): - if not self.integrated_main_ram_size: - if not self._sdram_phy_registered: - raise FinalizeError("Need to call SDRAMSoC.register_sdram_phy()") - SoC.do_finalize(self) + def do_finalize(self): + if not self.integrated_main_ram_size: + if not self._sdram_phy_registered: + raise FinalizeError("Need to call SDRAMSoC.register_sdram_phy()") + SoC.do_finalize(self) diff --git a/misoclib/video/dvisampler/__init__.py b/misoclib/video/dvisampler/__init__.py index aaf28d05..2bc38f2f 100644 --- a/misoclib/video/dvisampler/__init__.py +++ b/misoclib/video/dvisampler/__init__.py @@ -12,68 +12,68 @@ from misoclib.video.dvisampler.analysis import SyncPolarity, ResolutionDetection from misoclib.video.dvisampler.dma import DMA class DVISampler(Module, AutoCSR): - def __init__(self, pads, lasmim, n_dma_slots=2): - self.submodules.edid = EDID(pads) - self.submodules.clocking = Clocking(pads) + def __init__(self, pads, lasmim, n_dma_slots=2): + self.submodules.edid = EDID(pads) + self.submodules.clocking = Clocking(pads) - for datan in range(3): - name = "data" + str(datan) + for datan in range(3): + name = "data" + str(datan) - cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8) - setattr(self.submodules, name + "_cap", cap) - self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe) + cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8) + setattr(self.submodules, name + "_cap", cap) + self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe) - charsync = CharSync() - setattr(self.submodules, name + "_charsync", charsync) - self.comb += charsync.raw_data.eq(cap.d) + charsync = CharSync() + setattr(self.submodules, name + "_charsync", charsync) + self.comb += charsync.raw_data.eq(cap.d) - wer = WER() - setattr(self.submodules, name + "_wer", wer) - self.comb += wer.data.eq(charsync.data) + wer = WER() + setattr(self.submodules, name + "_wer", wer) + self.comb += wer.data.eq(charsync.data) - decoding = Decoding() - setattr(self.submodules, name + "_decod", decoding) - self.comb += [ - decoding.valid_i.eq(charsync.synced), - decoding.input.eq(charsync.data) - ] + decoding = Decoding() + setattr(self.submodules, name + "_decod", decoding) + self.comb += [ + decoding.valid_i.eq(charsync.synced), + decoding.input.eq(charsync.data) + ] - self.submodules.chansync = ChanSync() - self.comb += [ - self.chansync.valid_i.eq(self.data0_decod.valid_o & \ - self.data1_decod.valid_o & self.data2_decod.valid_o), - self.chansync.data_in0.eq(self.data0_decod.output), - self.chansync.data_in1.eq(self.data1_decod.output), - self.chansync.data_in2.eq(self.data2_decod.output), - ] + self.submodules.chansync = ChanSync() + self.comb += [ + self.chansync.valid_i.eq(self.data0_decod.valid_o & \ + self.data1_decod.valid_o & self.data2_decod.valid_o), + self.chansync.data_in0.eq(self.data0_decod.output), + self.chansync.data_in1.eq(self.data1_decod.output), + self.chansync.data_in2.eq(self.data2_decod.output), + ] - self.submodules.syncpol = SyncPolarity() - self.comb += [ - self.syncpol.valid_i.eq(self.chansync.chan_synced), - self.syncpol.data_in0.eq(self.chansync.data_out0), - self.syncpol.data_in1.eq(self.chansync.data_out1), - self.syncpol.data_in2.eq(self.chansync.data_out2) - ] + self.submodules.syncpol = SyncPolarity() + self.comb += [ + self.syncpol.valid_i.eq(self.chansync.chan_synced), + self.syncpol.data_in0.eq(self.chansync.data_out0), + self.syncpol.data_in1.eq(self.chansync.data_out1), + self.syncpol.data_in2.eq(self.chansync.data_out2) + ] - self.submodules.resdetection = ResolutionDetection() - self.comb += [ - self.resdetection.valid_i.eq(self.syncpol.valid_o), - self.resdetection.de.eq(self.syncpol.de), - self.resdetection.vsync.eq(self.syncpol.vsync) - ] + self.submodules.resdetection = ResolutionDetection() + self.comb += [ + self.resdetection.valid_i.eq(self.syncpol.valid_o), + self.resdetection.de.eq(self.syncpol.de), + self.resdetection.vsync.eq(self.syncpol.vsync) + ] - self.submodules.frame = FrameExtraction(24*lasmim.dw//32) - self.comb += [ - self.frame.valid_i.eq(self.syncpol.valid_o), - self.frame.de.eq(self.syncpol.de), - self.frame.vsync.eq(self.syncpol.vsync), - self.frame.r.eq(self.syncpol.r), - self.frame.g.eq(self.syncpol.g), - self.frame.b.eq(self.syncpol.b) - ] + self.submodules.frame = FrameExtraction(24*lasmim.dw//32) + self.comb += [ + self.frame.valid_i.eq(self.syncpol.valid_o), + self.frame.de.eq(self.syncpol.de), + self.frame.vsync.eq(self.syncpol.vsync), + self.frame.r.eq(self.syncpol.r), + self.frame.g.eq(self.syncpol.g), + self.frame.b.eq(self.syncpol.b) + ] - self.submodules.dma = DMA(lasmim, n_dma_slots) - self.comb += self.frame.frame.connect(self.dma.frame) - self.ev = self.dma.ev + self.submodules.dma = DMA(lasmim, n_dma_slots) + self.comb += self.frame.frame.connect(self.dma.frame) + self.ev = self.dma.ev - autocsr_exclude = {"ev"} + autocsr_exclude = {"ev"} diff --git a/misoclib/video/dvisampler/analysis.py b/misoclib/video/dvisampler/analysis.py index 5f0a30ac..1d2f0847 100644 --- a/misoclib/video/dvisampler/analysis.py +++ b/misoclib/video/dvisampler/analysis.py @@ -8,198 +8,198 @@ from migen.flow.actor import * from misoclib.video.dvisampler.common import channel_layout class SyncPolarity(Module): - def __init__(self): - self.valid_i = Signal() - self.data_in0 = Record(channel_layout) - self.data_in1 = Record(channel_layout) - self.data_in2 = Record(channel_layout) - - self.valid_o = Signal() - self.de = Signal() - self.hsync = Signal() - self.vsync = Signal() - self.r = Signal(8) - self.g = Signal(8) - self.b = Signal(8) - - ### - - de = self.data_in0.de - de_r = Signal() - c = self.data_in0.c - c_polarity = Signal(2) - c_out = Signal(2) - - self.comb += [ - self.de.eq(de_r), - self.hsync.eq(c_out[0]), - self.vsync.eq(c_out[1]) - ] - - self.sync.pix += [ - self.valid_o.eq(self.valid_i), - self.r.eq(self.data_in2.d), - self.g.eq(self.data_in1.d), - self.b.eq(self.data_in0.d), - - de_r.eq(de), - If(de_r & ~de, - c_polarity.eq(c), - c_out.eq(0) - ).Else( - c_out.eq(c ^ c_polarity) - ) - ] + def __init__(self): + self.valid_i = Signal() + self.data_in0 = Record(channel_layout) + self.data_in1 = Record(channel_layout) + self.data_in2 = Record(channel_layout) + + self.valid_o = Signal() + self.de = Signal() + self.hsync = Signal() + self.vsync = Signal() + self.r = Signal(8) + self.g = Signal(8) + self.b = Signal(8) + + ### + + de = self.data_in0.de + de_r = Signal() + c = self.data_in0.c + c_polarity = Signal(2) + c_out = Signal(2) + + self.comb += [ + self.de.eq(de_r), + self.hsync.eq(c_out[0]), + self.vsync.eq(c_out[1]) + ] + + self.sync.pix += [ + self.valid_o.eq(self.valid_i), + self.r.eq(self.data_in2.d), + self.g.eq(self.data_in1.d), + self.b.eq(self.data_in0.d), + + de_r.eq(de), + If(de_r & ~de, + c_polarity.eq(c), + c_out.eq(0) + ).Else( + c_out.eq(c ^ c_polarity) + ) + ] class ResolutionDetection(Module, AutoCSR): - def __init__(self, nbits=11): - self.valid_i = Signal() - self.vsync = Signal() - self.de = Signal() - - self._hres = CSRStatus(nbits) - self._vres = CSRStatus(nbits) - - ### - - # Detect DE transitions - de_r = Signal() - pn_de = Signal() - self.sync.pix += de_r.eq(self.de) - self.comb += pn_de.eq(~self.de & de_r) - - # HRES - hcounter = Signal(nbits) - self.sync.pix += If(self.valid_i & self.de, - hcounter.eq(hcounter + 1) - ).Else( - hcounter.eq(0) - ) - - hcounter_st = Signal(nbits) - self.sync.pix += If(self.valid_i, - If(pn_de, hcounter_st.eq(hcounter)) - ).Else( - hcounter_st.eq(0) - ) - self.specials += MultiReg(hcounter_st, self._hres.status) - - # VRES - vsync_r = Signal() - p_vsync = Signal() - self.sync.pix += vsync_r.eq(self.vsync), - self.comb += p_vsync.eq(self.vsync & ~vsync_r) - - vcounter = Signal(nbits) - self.sync.pix += If(self.valid_i & p_vsync, - vcounter.eq(0) - ).Elif(pn_de, - vcounter.eq(vcounter + 1) - ) - - vcounter_st = Signal(nbits) - self.sync.pix += If(self.valid_i, - If(p_vsync, vcounter_st.eq(vcounter)) - ).Else( - vcounter_st.eq(0) - ) - self.specials += MultiReg(vcounter_st, self._vres.status) + def __init__(self, nbits=11): + self.valid_i = Signal() + self.vsync = Signal() + self.de = Signal() + + self._hres = CSRStatus(nbits) + self._vres = CSRStatus(nbits) + + ### + + # Detect DE transitions + de_r = Signal() + pn_de = Signal() + self.sync.pix += de_r.eq(self.de) + self.comb += pn_de.eq(~self.de & de_r) + + # HRES + hcounter = Signal(nbits) + self.sync.pix += If(self.valid_i & self.de, + hcounter.eq(hcounter + 1) + ).Else( + hcounter.eq(0) + ) + + hcounter_st = Signal(nbits) + self.sync.pix += If(self.valid_i, + If(pn_de, hcounter_st.eq(hcounter)) + ).Else( + hcounter_st.eq(0) + ) + self.specials += MultiReg(hcounter_st, self._hres.status) + + # VRES + vsync_r = Signal() + p_vsync = Signal() + self.sync.pix += vsync_r.eq(self.vsync), + self.comb += p_vsync.eq(self.vsync & ~vsync_r) + + vcounter = Signal(nbits) + self.sync.pix += If(self.valid_i & p_vsync, + vcounter.eq(0) + ).Elif(pn_de, + vcounter.eq(vcounter + 1) + ) + + vcounter_st = Signal(nbits) + self.sync.pix += If(self.valid_i, + If(p_vsync, vcounter_st.eq(vcounter)) + ).Else( + vcounter_st.eq(0) + ) + self.specials += MultiReg(vcounter_st, self._vres.status) class FrameExtraction(Module, AutoCSR): - def __init__(self, word_width): - # in pix clock domain - self.valid_i = Signal() - self.vsync = Signal() - self.de = Signal() - self.r = Signal(8) - self.g = Signal(8) - self.b = Signal(8) - - # in sys clock domain - word_layout = [("sof", 1), ("pixels", word_width)] - self.frame = Source(word_layout) - self.busy = Signal() - - self._overflow = CSR() - - ### - - # start of frame detection - vsync_r = Signal() - new_frame = Signal() - self.comb += new_frame.eq(self.vsync & ~vsync_r) - self.sync.pix += vsync_r.eq(self.vsync) - - # pack pixels into words - cur_word = Signal(word_width) - cur_word_valid = Signal() - encoded_pixel = Signal(24) - self.comb += encoded_pixel.eq(Cat(self.b, self.g, self.r)) - pack_factor = word_width//24 - assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2 - pack_counter = Signal(max=pack_factor) - self.sync.pix += [ - cur_word_valid.eq(0), - If(new_frame, - cur_word_valid.eq(pack_counter == (pack_factor - 1)), - pack_counter.eq(0), - ).Elif(self.valid_i & self.de, - [If(pack_counter == (pack_factor-i-1), - cur_word[24*i:24*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)], - cur_word_valid.eq(pack_counter == (pack_factor - 1)), - pack_counter.eq(pack_counter + 1) - ) - ] - - # FIFO - fifo = RenameClockDomains(AsyncFIFO(word_layout, 512), - {"write": "pix", "read": "sys"}) - self.submodules += fifo - self.comb += [ - fifo.din.pixels.eq(cur_word), - fifo.we.eq(cur_word_valid) - ] - self.sync.pix += \ - If(new_frame, - fifo.din.sof.eq(1) - ).Elif(cur_word_valid, - fifo.din.sof.eq(0) - ) - self.comb += [ - self.frame.stb.eq(fifo.readable), - self.frame.payload.eq(fifo.dout), - fifo.re.eq(self.frame.ack), - self.busy.eq(0) - ] - - # overflow detection - pix_overflow = Signal() - pix_overflow_reset = Signal() - self.sync.pix += [ - If(fifo.we & ~fifo.writable, - pix_overflow.eq(1) - ).Elif(pix_overflow_reset, - pix_overflow.eq(0) - ) - ] - - sys_overflow = Signal() - self.specials += MultiReg(pix_overflow, sys_overflow) - self.submodules.overflow_reset = PulseSynchronizer("sys", "pix") - self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys") - self.comb += [ - pix_overflow_reset.eq(self.overflow_reset.o), - self.overflow_reset_ack.i.eq(pix_overflow_reset) - ] - - overflow_mask = Signal() - self.comb += [ - self._overflow.w.eq(sys_overflow & ~overflow_mask), - self.overflow_reset.i.eq(self._overflow.re) - ] - self.sync += \ - If(self._overflow.re, - overflow_mask.eq(1) - ).Elif(self.overflow_reset_ack.o, - overflow_mask.eq(0) - ) + def __init__(self, word_width): + # in pix clock domain + self.valid_i = Signal() + self.vsync = Signal() + self.de = Signal() + self.r = Signal(8) + self.g = Signal(8) + self.b = Signal(8) + + # in sys clock domain + word_layout = [("sof", 1), ("pixels", word_width)] + self.frame = Source(word_layout) + self.busy = Signal() + + self._overflow = CSR() + + ### + + # start of frame detection + vsync_r = Signal() + new_frame = Signal() + self.comb += new_frame.eq(self.vsync & ~vsync_r) + self.sync.pix += vsync_r.eq(self.vsync) + + # pack pixels into words + cur_word = Signal(word_width) + cur_word_valid = Signal() + encoded_pixel = Signal(24) + self.comb += encoded_pixel.eq(Cat(self.b, self.g, self.r)) + pack_factor = word_width//24 + assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2 + pack_counter = Signal(max=pack_factor) + self.sync.pix += [ + cur_word_valid.eq(0), + If(new_frame, + cur_word_valid.eq(pack_counter == (pack_factor - 1)), + pack_counter.eq(0), + ).Elif(self.valid_i & self.de, + [If(pack_counter == (pack_factor-i-1), + cur_word[24*i:24*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)], + cur_word_valid.eq(pack_counter == (pack_factor - 1)), + pack_counter.eq(pack_counter + 1) + ) + ] + + # FIFO + fifo = RenameClockDomains(AsyncFIFO(word_layout, 512), + {"write": "pix", "read": "sys"}) + self.submodules += fifo + self.comb += [ + fifo.din.pixels.eq(cur_word), + fifo.we.eq(cur_word_valid) + ] + self.sync.pix += \ + If(new_frame, + fifo.din.sof.eq(1) + ).Elif(cur_word_valid, + fifo.din.sof.eq(0) + ) + self.comb += [ + self.frame.stb.eq(fifo.readable), + self.frame.payload.eq(fifo.dout), + fifo.re.eq(self.frame.ack), + self.busy.eq(0) + ] + + # overflow detection + pix_overflow = Signal() + pix_overflow_reset = Signal() + self.sync.pix += [ + If(fifo.we & ~fifo.writable, + pix_overflow.eq(1) + ).Elif(pix_overflow_reset, + pix_overflow.eq(0) + ) + ] + + sys_overflow = Signal() + self.specials += MultiReg(pix_overflow, sys_overflow) + self.submodules.overflow_reset = PulseSynchronizer("sys", "pix") + self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys") + self.comb += [ + pix_overflow_reset.eq(self.overflow_reset.o), + self.overflow_reset_ack.i.eq(pix_overflow_reset) + ] + + overflow_mask = Signal() + self.comb += [ + self._overflow.w.eq(sys_overflow & ~overflow_mask), + self.overflow_reset.i.eq(self._overflow.re) + ] + self.sync += \ + If(self._overflow.re, + overflow_mask.eq(1) + ).Elif(self.overflow_reset_ack.o, + overflow_mask.eq(0) + ) diff --git a/misoclib/video/dvisampler/chansync.py b/misoclib/video/dvisampler/chansync.py index c0c5963d..7b37593e 100644 --- a/misoclib/video/dvisampler/chansync.py +++ b/misoclib/video/dvisampler/chansync.py @@ -8,122 +8,122 @@ from migen.bank.description import * from misoclib.video.dvisampler.common import channel_layout class _SyncBuffer(Module): - def __init__(self, width, depth): - self.din = Signal(width) - self.dout = Signal(width) - self.re = Signal() - - ### - - produce = Signal(max=depth) - consume = Signal(max=depth) - storage = Memory(width, depth) - self.specials += storage - - wrport = storage.get_port(write_capable=True) - self.specials += wrport - self.comb += [ - wrport.adr.eq(produce), - wrport.dat_w.eq(self.din), - wrport.we.eq(1) - ] - self.sync += _inc(produce, depth) - - rdport = storage.get_port(async_read=True) - self.specials += rdport - self.comb += [ - rdport.adr.eq(consume), - self.dout.eq(rdport.dat_r) - ] - self.sync += If(self.re, _inc(consume, depth)) + def __init__(self, width, depth): + self.din = Signal(width) + self.dout = Signal(width) + self.re = Signal() + + ### + + produce = Signal(max=depth) + consume = Signal(max=depth) + storage = Memory(width, depth) + self.specials += storage + + wrport = storage.get_port(write_capable=True) + self.specials += wrport + self.comb += [ + wrport.adr.eq(produce), + wrport.dat_w.eq(self.din), + wrport.we.eq(1) + ] + self.sync += _inc(produce, depth) + + rdport = storage.get_port(async_read=True) + self.specials += rdport + self.comb += [ + rdport.adr.eq(consume), + self.dout.eq(rdport.dat_r) + ] + self.sync += If(self.re, _inc(consume, depth)) class ChanSync(Module, AutoCSR): - def __init__(self, nchan=3, depth=8): - self.valid_i = Signal() - self.chan_synced = Signal() - - self._channels_synced = CSRStatus() - - lst_control = [] - all_control = Signal() - for i in range(nchan): - name = "data_in" + str(i) - data_in = Record(channel_layout, name=name) - setattr(self, name, data_in) - name = "data_out" + str(i) - data_out = Record(channel_layout, name=name) - setattr(self, name, data_out) - - ### - - syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix") - self.submodules += syncbuffer - self.comb += [ - syncbuffer.din.eq(data_in.raw_bits()), - data_out.raw_bits().eq(syncbuffer.dout) - ] - is_control = Signal() - self.comb += [ - is_control.eq(~data_out.de), - syncbuffer.re.eq(~is_control | all_control) - ] - lst_control.append(is_control) - - some_control = Signal() - self.comb += [ - all_control.eq(optree("&", lst_control)), - some_control.eq(optree("|", lst_control)) - ] - self.sync.pix += If(~self.valid_i, - self.chan_synced.eq(0) - ).Else( - If(some_control, - If(all_control, - self.chan_synced.eq(1) - ).Else( - self.chan_synced.eq(0) - ) - ) - ) - self.specials += MultiReg(self.chan_synced, self._channels_synced.status) + def __init__(self, nchan=3, depth=8): + self.valid_i = Signal() + self.chan_synced = Signal() + + self._channels_synced = CSRStatus() + + lst_control = [] + all_control = Signal() + for i in range(nchan): + name = "data_in" + str(i) + data_in = Record(channel_layout, name=name) + setattr(self, name, data_in) + name = "data_out" + str(i) + data_out = Record(channel_layout, name=name) + setattr(self, name, data_out) + + ### + + syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix") + self.submodules += syncbuffer + self.comb += [ + syncbuffer.din.eq(data_in.raw_bits()), + data_out.raw_bits().eq(syncbuffer.dout) + ] + is_control = Signal() + self.comb += [ + is_control.eq(~data_out.de), + syncbuffer.re.eq(~is_control | all_control) + ] + lst_control.append(is_control) + + some_control = Signal() + self.comb += [ + all_control.eq(optree("&", lst_control)), + some_control.eq(optree("|", lst_control)) + ] + self.sync.pix += If(~self.valid_i, + self.chan_synced.eq(0) + ).Else( + If(some_control, + If(all_control, + self.chan_synced.eq(1) + ).Else( + self.chan_synced.eq(0) + ) + ) + ) + self.specials += MultiReg(self.chan_synced, self._channels_synced.status) class _TB(Module): - def __init__(self, test_seq_it): - self.test_seq_it = test_seq_it + def __init__(self, test_seq_it): + self.test_seq_it = test_seq_it - self.submodules.chansync = RenameClockDomains(ChanSync(), {"pix": "sys"}) - self.comb += self.chansync.valid_i.eq(1) + self.submodules.chansync = RenameClockDomains(ChanSync(), {"pix": "sys"}) + self.comb += self.chansync.valid_i.eq(1) - def do_simulation(self, selfp): - try: - de0, de1, de2 = next(self.test_seq_it) - except StopIteration: - raise StopSimulation + def do_simulation(self, selfp): + try: + de0, de1, de2 = next(self.test_seq_it) + except StopIteration: + raise StopSimulation - selfp.chansync.data_in0.de = de0 - selfp.chansync.data_in1.de = de1 - selfp.chansync.data_in2.de = de2 - selfp.chansync.data_in0.d = selfp.simulator.cycle_counter - selfp.chansync.data_in1.d = selfp.simulator.cycle_counter - selfp.chansync.data_in2.d = selfp.simulator.cycle_counter + selfp.chansync.data_in0.de = de0 + selfp.chansync.data_in1.de = de1 + selfp.chansync.data_in2.de = de2 + selfp.chansync.data_in0.d = selfp.simulator.cycle_counter + selfp.chansync.data_in1.d = selfp.simulator.cycle_counter + selfp.chansync.data_in2.d = selfp.simulator.cycle_counter - out0 = selfp.chansync.data_out0.d - out1 = selfp.chansync.data_out1.d - out2 = selfp.chansync.data_out2.d + out0 = selfp.chansync.data_out0.d + out1 = selfp.chansync.data_out1.d + out2 = selfp.chansync.data_out2.d - print("{0:5} {1:5} {2:5}".format(out0, out1, out2)) + print("{0:5} {1:5} {2:5}".format(out0, out1, out2)) if __name__ == "__main__": - from migen.sim.generic import run_simulation - - test_seq = [ - (1, 1, 1), - (1, 1, 0), - (0, 0, 0), - (0, 0, 0), - (0, 0, 1), - (1, 1, 1), - (1, 1, 1), - ] - tb = _TB(iter(test_seq*2)) - run_simulation(tb) + from migen.sim.generic import run_simulation + + test_seq = [ + (1, 1, 1), + (1, 1, 0), + (0, 0, 0), + (0, 0, 0), + (0, 0, 1), + (1, 1, 1), + (1, 1, 1), + ] + tb = _TB(iter(test_seq*2)) + run_simulation(tb) diff --git a/misoclib/video/dvisampler/charsync.py b/misoclib/video/dvisampler/charsync.py index 15558941..ee302d7e 100644 --- a/misoclib/video/dvisampler/charsync.py +++ b/misoclib/video/dvisampler/charsync.py @@ -6,48 +6,48 @@ from migen.bank.description import * from misoclib.video.dvisampler.common import control_tokens class CharSync(Module, AutoCSR): - def __init__(self, required_controls=8): - self.raw_data = Signal(10) - self.synced = Signal() - self.data = Signal(10) - - self._char_synced = CSRStatus() - self._ctl_pos = CSRStatus(bits_for(9)) - - ### - - raw_data1 = Signal(10) - self.sync.pix += raw_data1.eq(self.raw_data) - raw = Signal(20) - self.comb += raw.eq(Cat(raw_data1, self.raw_data)) - - found_control = Signal() - control_position = Signal(max=10) - self.sync.pix += found_control.eq(0) - for i in range(10): - self.sync.pix += If(optree("|", [raw[i:i+10] == t for t in control_tokens]), - found_control.eq(1), - control_position.eq(i) - ) - - control_counter = Signal(max=required_controls) - previous_control_position = Signal(max=10) - word_sel = Signal(max=10) - self.sync.pix += [ - If(found_control & (control_position == previous_control_position), - If(control_counter == (required_controls - 1), - control_counter.eq(0), - self.synced.eq(1), - word_sel.eq(control_position) - ).Else( - control_counter.eq(control_counter + 1) - ) - ).Else( - control_counter.eq(0) - ), - previous_control_position.eq(control_position) - ] - self.specials += MultiReg(self.synced, self._char_synced.status) - self.specials += MultiReg(word_sel, self._ctl_pos.status) - - self.sync.pix += self.data.eq(raw >> word_sel) + def __init__(self, required_controls=8): + self.raw_data = Signal(10) + self.synced = Signal() + self.data = Signal(10) + + self._char_synced = CSRStatus() + self._ctl_pos = CSRStatus(bits_for(9)) + + ### + + raw_data1 = Signal(10) + self.sync.pix += raw_data1.eq(self.raw_data) + raw = Signal(20) + self.comb += raw.eq(Cat(raw_data1, self.raw_data)) + + found_control = Signal() + control_position = Signal(max=10) + self.sync.pix += found_control.eq(0) + for i in range(10): + self.sync.pix += If(optree("|", [raw[i:i+10] == t for t in control_tokens]), + found_control.eq(1), + control_position.eq(i) + ) + + control_counter = Signal(max=required_controls) + previous_control_position = Signal(max=10) + word_sel = Signal(max=10) + self.sync.pix += [ + If(found_control & (control_position == previous_control_position), + If(control_counter == (required_controls - 1), + control_counter.eq(0), + self.synced.eq(1), + word_sel.eq(control_position) + ).Else( + control_counter.eq(control_counter + 1) + ) + ).Else( + control_counter.eq(0) + ), + previous_control_position.eq(control_position) + ] + self.specials += MultiReg(self.synced, self._char_synced.status) + self.specials += MultiReg(word_sel, self._ctl_pos.status) + + self.sync.pix += self.data.eq(raw >> word_sel) diff --git a/misoclib/video/dvisampler/clocking.py b/misoclib/video/dvisampler/clocking.py index 9e17dbc6..215cdba6 100644 --- a/misoclib/video/dvisampler/clocking.py +++ b/misoclib/video/dvisampler/clocking.py @@ -3,77 +3,77 @@ from migen.genlib.cdc import MultiReg from migen.bank.description import * class Clocking(Module, AutoCSR): - def __init__(self, pads): - self._pll_reset = CSRStorage(reset=1) - self._locked = CSRStatus() + def __init__(self, pads): + self._pll_reset = CSRStorage(reset=1) + self._locked = CSRStatus() - # DRP - self._pll_adr = CSRStorage(5) - self._pll_dat_r = CSRStatus(16) - self._pll_dat_w = CSRStorage(16) - self._pll_read = CSR() - self._pll_write = CSR() - self._pll_drdy = CSRStatus() + # DRP + self._pll_adr = CSRStorage(5) + self._pll_dat_r = CSRStatus(16) + self._pll_dat_w = CSRStorage(16) + self._pll_read = CSR() + self._pll_write = CSR() + self._pll_drdy = CSRStatus() - self.locked = Signal() - self.serdesstrobe = Signal() - self.clock_domains._cd_pix = ClockDomain() - self.clock_domains._cd_pix2x = ClockDomain() - self.clock_domains._cd_pix10x = ClockDomain(reset_less=True) + self.locked = Signal() + self.serdesstrobe = Signal() + self.clock_domains._cd_pix = ClockDomain() + self.clock_domains._cd_pix2x = ClockDomain() + self.clock_domains._cd_pix10x = ClockDomain(reset_less=True) - ### + ### - clk_se = Signal() - self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se) + clk_se = Signal() + self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se) - clkfbout = Signal() - pll_locked = Signal() - pll_clk0 = Signal() - pll_clk1 = Signal() - pll_clk2 = Signal() - pll_drdy = Signal() - self.sync += If(self._pll_read.re | self._pll_write.re, - self._pll_drdy.status.eq(0) - ).Elif(pll_drdy, - self._pll_drdy.status.eq(1) - ) - self.specials += Instance("PLL_ADV", - p_CLKFBOUT_MULT=10, - p_CLKOUT0_DIVIDE=1, # pix10x - p_CLKOUT1_DIVIDE=5, # pix2x - p_CLKOUT2_DIVIDE=10, # pix - p_COMPENSATION="INTERNAL", + clkfbout = Signal() + pll_locked = Signal() + pll_clk0 = Signal() + pll_clk1 = Signal() + pll_clk2 = Signal() + pll_drdy = Signal() + self.sync += If(self._pll_read.re | self._pll_write.re, + self._pll_drdy.status.eq(0) + ).Elif(pll_drdy, + self._pll_drdy.status.eq(1) + ) + self.specials += Instance("PLL_ADV", + p_CLKFBOUT_MULT=10, + p_CLKOUT0_DIVIDE=1, # pix10x + p_CLKOUT1_DIVIDE=5, # pix2x + p_CLKOUT2_DIVIDE=10, # pix + p_COMPENSATION="INTERNAL", - i_CLKINSEL=1, - i_CLKIN1=clk_se, - o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2, - o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout, - o_LOCKED=pll_locked, i_RST=self._pll_reset.storage, + i_CLKINSEL=1, + i_CLKIN1=clk_se, + o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2, + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout, + o_LOCKED=pll_locked, i_RST=self._pll_reset.storage, - i_DADDR=self._pll_adr.storage, - o_DO=self._pll_dat_r.status, - i_DI=self._pll_dat_w.storage, - i_DEN=self._pll_read.re | self._pll_write.re, - i_DWE=self._pll_write.re, - o_DRDY=pll_drdy, - i_DCLK=ClockSignal()) + i_DADDR=self._pll_adr.storage, + o_DO=self._pll_dat_r.status, + i_DI=self._pll_dat_w.storage, + i_DEN=self._pll_read.re | self._pll_write.re, + i_DWE=self._pll_write.re, + o_DRDY=pll_drdy, + i_DCLK=ClockSignal()) - locked_async = Signal() - self.specials += [ - Instance("BUFPLL", p_DIVIDE=5, - i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked, - o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe), - Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix2x.clk), - Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk), - MultiReg(locked_async, self.locked, "sys") - ] - self.comb += self._locked.status.eq(self.locked) + locked_async = Signal() + self.specials += [ + Instance("BUFPLL", p_DIVIDE=5, + i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked, + o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe), + Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix2x.clk), + Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk), + MultiReg(locked_async, self.locked, "sys") + ] + self.comb += self._locked.status.eq(self.locked) - # sychronize pix+pix2x reset - pix_rst_n = 1 - for i in range(2): - new_pix_rst_n = Signal() - self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"), - i_CLR=~locked_async, o_Q=new_pix_rst_n) - pix_rst_n = new_pix_rst_n - self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix2x.rst.eq(~pix_rst_n) + # sychronize pix+pix2x reset + pix_rst_n = 1 + for i in range(2): + new_pix_rst_n = Signal() + self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"), + i_CLR=~locked_async, o_Q=new_pix_rst_n) + pix_rst_n = new_pix_rst_n + self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix2x.rst.eq(~pix_rst_n) diff --git a/misoclib/video/dvisampler/datacapture.py b/misoclib/video/dvisampler/datacapture.py index 44b97fcd..0649917b 100644 --- a/misoclib/video/dvisampler/datacapture.py +++ b/misoclib/video/dvisampler/datacapture.py @@ -3,184 +3,184 @@ from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.bank.description import * class DataCapture(Module, AutoCSR): - def __init__(self, pad_p, pad_n, ntbits): - self.serdesstrobe = Signal() - self.d = Signal(10) - - self._dly_ctl = CSR(6) - self._dly_busy = CSRStatus(2) - self._phase = CSRStatus(2) - self._phase_reset = CSR() - - ### - - # IO - pad_se = Signal() - self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se) - - pad_delayed_master = Signal() - pad_delayed_slave = Signal() - delay_inc = Signal() - delay_ce = Signal() - delay_master_cal = Signal() - delay_master_rst = Signal() - delay_master_busy = Signal() - delay_slave_cal = Signal() - delay_slave_rst = Signal() - delay_slave_busy = Signal() - self.specials += Instance("IODELAY2", - p_SERDES_MODE="MASTER", - p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", - p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR", - - i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master, - i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"), - - i_INC=delay_inc, i_CE=delay_ce, - i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy, - i_T=1) - self.specials += Instance("IODELAY2", - p_SERDES_MODE="SLAVE", - p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", - p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR", - - i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave, - i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"), - - i_INC=delay_inc, i_CE=delay_ce, - i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy, - i_T=1) - - dsr2 = Signal(5) - pd_valid = Signal() - pd_incdec = Signal() - pd_edge = Signal() - pd_cascade = Signal() - self.specials += Instance("ISERDES2", - p_SERDES_MODE="MASTER", - p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5, - p_INTERFACE_TYPE="RETIMED", - - i_D=pad_delayed_master, - o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1], - - i_BITSLIP=0, i_CE0=1, i_RST=0, - i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"), - i_IOCE=self.serdesstrobe, - - o_VALID=pd_valid, o_INCDEC=pd_incdec, - i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade) - self.specials += Instance("ISERDES2", - p_SERDES_MODE="SLAVE", - p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5, - p_INTERFACE_TYPE="RETIMED", - - i_D=pad_delayed_slave, - o_Q4=dsr2[0], - - i_BITSLIP=0, i_CE0=1, i_RST=0, - i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"), - i_IOCE=self.serdesstrobe, - - i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge) - - # Phase error accumulator - lateness = Signal(ntbits, reset=2**(ntbits - 1)) - too_late = Signal() - too_early = Signal() - reset_lateness = Signal() - self.comb += [ - too_late.eq(lateness == (2**ntbits - 1)), - too_early.eq(lateness == 0) - ] - self.sync.pix2x += [ - If(reset_lateness, - lateness.eq(2**(ntbits - 1)) - ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early, - If(pd_valid & pd_incdec, lateness.eq(lateness - 1)), - If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1)) - ) - ] - - # Delay control - self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys") - delay_master_pending = Signal() - self.sync.pix2x += [ - self.delay_master_done.i.eq(0), - If(~delay_master_pending, - If(delay_master_cal | delay_ce, delay_master_pending.eq(1)) - ).Else( - If(~delay_master_busy, - self.delay_master_done.i.eq(1), - delay_master_pending.eq(0) - ) - ) - ] - self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys") - delay_slave_pending = Signal() - self.sync.pix2x += [ - self.delay_slave_done.i.eq(0), - If(~delay_slave_pending, - If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1)) - ).Else( - If(~delay_slave_busy, - self.delay_slave_done.i.eq(1), - delay_slave_pending.eq(0) - ) - ) - ] - - self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x") - self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x") - self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x") - self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x") - self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x") - self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x") - self.comb += [ - delay_master_cal.eq(self.do_delay_master_cal.o), - delay_master_rst.eq(self.do_delay_master_rst.o), - delay_slave_cal.eq(self.do_delay_slave_cal.o), - delay_slave_rst.eq(self.do_delay_slave_rst.o), - delay_inc.eq(self.do_delay_inc.o), - delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o), - ] - - sys_delay_master_pending = Signal() - self.sync += [ - If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i, - sys_delay_master_pending.eq(1) - ).Elif(self.delay_master_done.o, - sys_delay_master_pending.eq(0) - ) - ] - sys_delay_slave_pending = Signal() - self.sync += [ - If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i, - sys_delay_slave_pending.eq(1) - ).Elif(self.delay_slave_done.o, - sys_delay_slave_pending.eq(0) - ) - ] - - self.comb += [ - self.do_delay_master_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]), - self.do_delay_master_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[1]), - self.do_delay_slave_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[2]), - self.do_delay_slave_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[3]), - self.do_delay_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[4]), - self.do_delay_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[5]), - self._dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending)) - ] - - # Phase detector control - self.specials += MultiReg(Cat(too_late, too_early), self._phase.status) - self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x") - self.comb += [ - reset_lateness.eq(self.do_reset_lateness.o), - self.do_reset_lateness.i.eq(self._phase_reset.re) - ] - - # 5:10 deserialization - dsr = Signal(10) - self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2)) - self.sync.pix += self.d.eq(dsr) + def __init__(self, pad_p, pad_n, ntbits): + self.serdesstrobe = Signal() + self.d = Signal(10) + + self._dly_ctl = CSR(6) + self._dly_busy = CSRStatus(2) + self._phase = CSRStatus(2) + self._phase_reset = CSR() + + ### + + # IO + pad_se = Signal() + self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se) + + pad_delayed_master = Signal() + pad_delayed_slave = Signal() + delay_inc = Signal() + delay_ce = Signal() + delay_master_cal = Signal() + delay_master_rst = Signal() + delay_master_busy = Signal() + delay_slave_cal = Signal() + delay_slave_rst = Signal() + delay_slave_busy = Signal() + self.specials += Instance("IODELAY2", + p_SERDES_MODE="MASTER", + p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", + p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR", + + i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master, + i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"), + + i_INC=delay_inc, i_CE=delay_ce, + i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy, + i_T=1) + self.specials += Instance("IODELAY2", + p_SERDES_MODE="SLAVE", + p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", + p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR", + + i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave, + i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"), + + i_INC=delay_inc, i_CE=delay_ce, + i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy, + i_T=1) + + dsr2 = Signal(5) + pd_valid = Signal() + pd_incdec = Signal() + pd_edge = Signal() + pd_cascade = Signal() + self.specials += Instance("ISERDES2", + p_SERDES_MODE="MASTER", + p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5, + p_INTERFACE_TYPE="RETIMED", + + i_D=pad_delayed_master, + o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1], + + i_BITSLIP=0, i_CE0=1, i_RST=0, + i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"), + i_IOCE=self.serdesstrobe, + + o_VALID=pd_valid, o_INCDEC=pd_incdec, + i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade) + self.specials += Instance("ISERDES2", + p_SERDES_MODE="SLAVE", + p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5, + p_INTERFACE_TYPE="RETIMED", + + i_D=pad_delayed_slave, + o_Q4=dsr2[0], + + i_BITSLIP=0, i_CE0=1, i_RST=0, + i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"), + i_IOCE=self.serdesstrobe, + + i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge) + + # Phase error accumulator + lateness = Signal(ntbits, reset=2**(ntbits - 1)) + too_late = Signal() + too_early = Signal() + reset_lateness = Signal() + self.comb += [ + too_late.eq(lateness == (2**ntbits - 1)), + too_early.eq(lateness == 0) + ] + self.sync.pix2x += [ + If(reset_lateness, + lateness.eq(2**(ntbits - 1)) + ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early, + If(pd_valid & pd_incdec, lateness.eq(lateness - 1)), + If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1)) + ) + ] + + # Delay control + self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys") + delay_master_pending = Signal() + self.sync.pix2x += [ + self.delay_master_done.i.eq(0), + If(~delay_master_pending, + If(delay_master_cal | delay_ce, delay_master_pending.eq(1)) + ).Else( + If(~delay_master_busy, + self.delay_master_done.i.eq(1), + delay_master_pending.eq(0) + ) + ) + ] + self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys") + delay_slave_pending = Signal() + self.sync.pix2x += [ + self.delay_slave_done.i.eq(0), + If(~delay_slave_pending, + If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1)) + ).Else( + If(~delay_slave_busy, + self.delay_slave_done.i.eq(1), + delay_slave_pending.eq(0) + ) + ) + ] + + self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x") + self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x") + self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x") + self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x") + self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x") + self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x") + self.comb += [ + delay_master_cal.eq(self.do_delay_master_cal.o), + delay_master_rst.eq(self.do_delay_master_rst.o), + delay_slave_cal.eq(self.do_delay_slave_cal.o), + delay_slave_rst.eq(self.do_delay_slave_rst.o), + delay_inc.eq(self.do_delay_inc.o), + delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o), + ] + + sys_delay_master_pending = Signal() + self.sync += [ + If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i, + sys_delay_master_pending.eq(1) + ).Elif(self.delay_master_done.o, + sys_delay_master_pending.eq(0) + ) + ] + sys_delay_slave_pending = Signal() + self.sync += [ + If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i, + sys_delay_slave_pending.eq(1) + ).Elif(self.delay_slave_done.o, + sys_delay_slave_pending.eq(0) + ) + ] + + self.comb += [ + self.do_delay_master_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]), + self.do_delay_master_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[1]), + self.do_delay_slave_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[2]), + self.do_delay_slave_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[3]), + self.do_delay_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[4]), + self.do_delay_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[5]), + self._dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending)) + ] + + # Phase detector control + self.specials += MultiReg(Cat(too_late, too_early), self._phase.status) + self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x") + self.comb += [ + reset_lateness.eq(self.do_reset_lateness.o), + self.do_reset_lateness.i.eq(self._phase_reset.re) + ] + + # 5:10 deserialization + dsr = Signal(10) + self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2)) + self.sync.pix += self.d.eq(dsr) diff --git a/misoclib/video/dvisampler/debug.py b/misoclib/video/dvisampler/debug.py index bb52d07a..472f7384 100644 --- a/misoclib/video/dvisampler/debug.py +++ b/misoclib/video/dvisampler/debug.py @@ -10,38 +10,38 @@ from misoclib.video.dvisampler.clocking import Clocking from misoclib.video.dvisampler.datacapture import DataCapture class RawDVISampler(Module, AutoCSR): - def __init__(self, pads, asmiport): - self.submodules.edid = EDID(pads) - self.submodules.clocking = Clocking(pads) + def __init__(self, pads, asmiport): + self.submodules.edid = EDID(pads) + self.submodules.clocking = Clocking(pads) - invert = False - try: - s = getattr(pads, "data0") - except AttributeError: - s = getattr(pads, "data0_n") - invert = True - self.submodules.data0_cap = DataCapture(8, invert) - self.comb += [ - self.data0_cap.pad.eq(s), - self.data0_cap.serdesstrobe.eq(self.clocking.serdesstrobe) - ] + invert = False + try: + s = getattr(pads, "data0") + except AttributeError: + s = getattr(pads, "data0_n") + invert = True + self.submodules.data0_cap = DataCapture(8, invert) + self.comb += [ + self.data0_cap.pad.eq(s), + self.data0_cap.serdesstrobe.eq(self.clocking.serdesstrobe) + ] - fifo = RenameClockDomains(AsyncFIFO(10, 256), - {"write": "pix", "read": "sys"}) - self.submodules += fifo - self.comb += [ - fifo.din.eq(self.data0_cap.d), - fifo.we.eq(1) - ] + fifo = RenameClockDomains(AsyncFIFO(10, 256), + {"write": "pix", "read": "sys"}) + self.submodules += fifo + self.comb += [ + fifo.din.eq(self.data0_cap.d), + fifo.we.eq(1) + ] - pack_factor = asmiport.hub.dw//16 - self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor) - self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw) - self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT) - self.comb += [ - self.packer.sink.stb.eq(fifo.readable), - fifo.re.eq(self.packer.sink.ack), - self.packer.sink.word.eq(fifo.dout), - self.packer.source.connect_flat(self.cast.sink), - self.cast.source.connect_flat(self.dma.data) - ] + pack_factor = asmiport.hub.dw//16 + self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor) + self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw) + self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT) + self.comb += [ + self.packer.sink.stb.eq(fifo.readable), + fifo.re.eq(self.packer.sink.ack), + self.packer.sink.word.eq(fifo.dout), + self.packer.source.connect_flat(self.cast.sink), + self.cast.source.connect_flat(self.dma.data) + ] diff --git a/misoclib/video/dvisampler/decoding.py b/misoclib/video/dvisampler/decoding.py index fe799611..0ceb2827 100644 --- a/misoclib/video/dvisampler/decoding.py +++ b/misoclib/video/dvisampler/decoding.py @@ -4,21 +4,21 @@ from migen.genlib.record import Record from misoclib.video.dvisampler.common import control_tokens, channel_layout class Decoding(Module): - def __init__(self): - self.valid_i = Signal() - self.input = Signal(10) - self.valid_o = Signal() - self.output = Record(channel_layout) + def __init__(self): + self.valid_i = Signal() + self.input = Signal(10) + self.valid_o = Signal() + self.output = Record(channel_layout) - ### + ### - self.sync.pix += self.output.de.eq(1) - for i, t in enumerate(control_tokens): - self.sync.pix += If(self.input == t, - self.output.de.eq(0), - self.output.c.eq(i) - ) - self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9]) - for i in range(1, 8): - self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i-1] ^ ~self.input[8]) - self.sync.pix += self.valid_o.eq(self.valid_i) + self.sync.pix += self.output.de.eq(1) + for i, t in enumerate(control_tokens): + self.sync.pix += If(self.input == t, + self.output.de.eq(0), + self.output.c.eq(i) + ) + self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9]) + for i in range(1, 8): + self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i-1] ^ ~self.input[8]) + self.sync.pix += self.valid_o.eq(self.valid_i) diff --git a/misoclib/video/dvisampler/dma.py b/misoclib/video/dvisampler/dma.py index 02475320..d811ab7f 100644 --- a/misoclib/video/dvisampler/dma.py +++ b/misoclib/video/dvisampler/dma.py @@ -8,134 +8,134 @@ from misoclib.mem.sdram.frontend import dma_lasmi # Slot status: EMPTY=0 LOADED=1 PENDING=2 class _Slot(Module, AutoCSR): - def __init__(self, addr_bits, alignment_bits): - self.ev_source = EventSourceLevel() - self.address = Signal(addr_bits) - self.address_reached = Signal(addr_bits) - self.address_valid = Signal() - self.address_done = Signal() - - self._status = CSRStorage(2, write_from_dev=True) - self._address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits, write_from_dev=True) - - ### - - self.comb += [ - self.address.eq(self._address.storage), - self.address_valid.eq(self._status.storage[0]), - self._status.dat_w.eq(2), - self._status.we.eq(self.address_done), - self._address.dat_w.eq(self.address_reached), - self._address.we.eq(self.address_done), - self.ev_source.trigger.eq(self._status.storage[1]) - ] + def __init__(self, addr_bits, alignment_bits): + self.ev_source = EventSourceLevel() + self.address = Signal(addr_bits) + self.address_reached = Signal(addr_bits) + self.address_valid = Signal() + self.address_done = Signal() + + self._status = CSRStorage(2, write_from_dev=True) + self._address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits, write_from_dev=True) + + ### + + self.comb += [ + self.address.eq(self._address.storage), + self.address_valid.eq(self._status.storage[0]), + self._status.dat_w.eq(2), + self._status.we.eq(self.address_done), + self._address.dat_w.eq(self.address_reached), + self._address.we.eq(self.address_done), + self.ev_source.trigger.eq(self._status.storage[1]) + ] class _SlotArray(Module, AutoCSR): - def __init__(self, nslots, addr_bits, alignment_bits): - self.submodules.ev = EventManager() - self.address = Signal(addr_bits) - self.address_reached = Signal(addr_bits) - self.address_valid = Signal() - self.address_done = Signal() - - ### - - slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)] - for n, slot in enumerate(slots): - setattr(self.submodules, "slot"+str(n), slot) - setattr(self.ev, "slot"+str(n), slot.ev_source) - self.ev.finalize() - - change_slot = Signal() - current_slot = Signal(max=nslots) - self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))]) - self.comb += change_slot.eq(~self.address_valid | self.address_done) - - self.comb += [ - self.address.eq(Array(slot.address for slot in slots)[current_slot]), - self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot]) - ] - self.comb += [slot.address_reached.eq(self.address_reached) for slot in slots] - self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)] + def __init__(self, nslots, addr_bits, alignment_bits): + self.submodules.ev = EventManager() + self.address = Signal(addr_bits) + self.address_reached = Signal(addr_bits) + self.address_valid = Signal() + self.address_done = Signal() + + ### + + slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)] + for n, slot in enumerate(slots): + setattr(self.submodules, "slot"+str(n), slot) + setattr(self.ev, "slot"+str(n), slot.ev_source) + self.ev.finalize() + + change_slot = Signal() + current_slot = Signal(max=nslots) + self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))]) + self.comb += change_slot.eq(~self.address_valid | self.address_done) + + self.comb += [ + self.address.eq(Array(slot.address for slot in slots)[current_slot]), + self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot]) + ] + self.comb += [slot.address_reached.eq(self.address_reached) for slot in slots] + self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)] class DMA(Module): - def __init__(self, lasmim, nslots): - bus_aw = lasmim.aw - bus_dw = lasmim.dw - alignment_bits = bits_for(bus_dw//8) - 1 - - fifo_word_width = 24*bus_dw//32 - self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)]) - self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits) - self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits) - self.ev = self._slot_array.ev - - ### - - # address generator + maximum memory word count to prevent DMA buffer overrun - reset_words = Signal() - count_word = Signal() - last_word = Signal() - current_address = Signal(bus_aw) - mwords_remaining = Signal(bus_aw) - self.comb += [ - self._slot_array.address_reached.eq(current_address), - last_word.eq(mwords_remaining == 1) - ] - self.sync += [ - If(reset_words, - current_address.eq(self._slot_array.address), - mwords_remaining.eq(self._frame_size.storage) - ).Elif(count_word, - current_address.eq(current_address + 1), - mwords_remaining.eq(mwords_remaining - 1) - ) - ] - - # 24bpp -> 32bpp - memory_word = Signal(bus_dw) - pixbits = [] - for i in range(bus_dw//32): - for j in range(3): - b = (i*3+j)*8 - pixbits.append(self.frame.pixels[b+6:b+8]) - pixbits.append(self.frame.pixels[b:b+8]) - pixbits.append(0) - pixbits.append(0) - self.comb += memory_word.eq(Cat(*pixbits)) - - # bus accessor - self.submodules._bus_accessor = dma_lasmi.Writer(lasmim) - self.comb += [ - self._bus_accessor.address_data.a.eq(current_address), - self._bus_accessor.address_data.d.eq(memory_word) - ] - - # control FSM - fsm = FSM() - self.submodules += fsm - - fsm.act("WAIT_SOF", - reset_words.eq(1), - self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.sof), - If(self._slot_array.address_valid & self.frame.sof & self.frame.stb, NextState("TRANSFER_PIXELS")) - ) - fsm.act("TRANSFER_PIXELS", - self.frame.ack.eq(self._bus_accessor.address_data.ack), - If(self.frame.stb, - self._bus_accessor.address_data.stb.eq(1), - If(self._bus_accessor.address_data.ack, - count_word.eq(1), - If(last_word, NextState("EOF")) - ) - ) - ) - fsm.act("EOF", - If(~self._bus_accessor.busy, - self._slot_array.address_done.eq(1), - NextState("WAIT_SOF") - ) - ) - - def get_csrs(self): - return [self._frame_size] + self._slot_array.get_csrs() + def __init__(self, lasmim, nslots): + bus_aw = lasmim.aw + bus_dw = lasmim.dw + alignment_bits = bits_for(bus_dw//8) - 1 + + fifo_word_width = 24*bus_dw//32 + self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)]) + self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits) + self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits) + self.ev = self._slot_array.ev + + ### + + # address generator + maximum memory word count to prevent DMA buffer overrun + reset_words = Signal() + count_word = Signal() + last_word = Signal() + current_address = Signal(bus_aw) + mwords_remaining = Signal(bus_aw) + self.comb += [ + self._slot_array.address_reached.eq(current_address), + last_word.eq(mwords_remaining == 1) + ] + self.sync += [ + If(reset_words, + current_address.eq(self._slot_array.address), + mwords_remaining.eq(self._frame_size.storage) + ).Elif(count_word, + current_address.eq(current_address + 1), + mwords_remaining.eq(mwords_remaining - 1) + ) + ] + + # 24bpp -> 32bpp + memory_word = Signal(bus_dw) + pixbits = [] + for i in range(bus_dw//32): + for j in range(3): + b = (i*3+j)*8 + pixbits.append(self.frame.pixels[b+6:b+8]) + pixbits.append(self.frame.pixels[b:b+8]) + pixbits.append(0) + pixbits.append(0) + self.comb += memory_word.eq(Cat(*pixbits)) + + # bus accessor + self.submodules._bus_accessor = dma_lasmi.Writer(lasmim) + self.comb += [ + self._bus_accessor.address_data.a.eq(current_address), + self._bus_accessor.address_data.d.eq(memory_word) + ] + + # control FSM + fsm = FSM() + self.submodules += fsm + + fsm.act("WAIT_SOF", + reset_words.eq(1), + self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.sof), + If(self._slot_array.address_valid & self.frame.sof & self.frame.stb, NextState("TRANSFER_PIXELS")) + ) + fsm.act("TRANSFER_PIXELS", + self.frame.ack.eq(self._bus_accessor.address_data.ack), + If(self.frame.stb, + self._bus_accessor.address_data.stb.eq(1), + If(self._bus_accessor.address_data.ack, + count_word.eq(1), + If(last_word, NextState("EOF")) + ) + ) + ) + fsm.act("EOF", + If(~self._bus_accessor.busy, + self._slot_array.address_done.eq(1), + NextState("WAIT_SOF") + ) + ) + + def get_csrs(self): + return [self._frame_size] + self._slot_array.get_csrs() diff --git a/misoclib/video/dvisampler/edid.py b/misoclib/video/dvisampler/edid.py index fc2d4b19..efe54d38 100644 --- a/misoclib/video/dvisampler/edid.py +++ b/misoclib/video/dvisampler/edid.py @@ -6,184 +6,184 @@ from migen.genlib.misc import chooser from migen.bank.description import CSRStorage, CSRStatus, AutoCSR _default_edid = [ - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3D, 0x17, 0x32, 0x12, 0x2A, 0x6A, 0xBF, 0x00, - 0x05, 0x17, 0x01, 0x03, 0x80, 0x28, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xB2, 0x0C, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, - 0x36, 0x00, 0x28, 0x1E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4D, 0x31, 0x20, - 0x44, 0x56, 0x49, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x72, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3D, 0x17, 0x32, 0x12, 0x2A, 0x6A, 0xBF, 0x00, + 0x05, 0x17, 0x01, 0x03, 0x80, 0x28, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xB2, 0x0C, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88, + 0x36, 0x00, 0x28, 0x1E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4D, 0x31, 0x20, + 0x44, 0x56, 0x49, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x72, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, ] class EDID(Module, AutoCSR): - def __init__(self, pads, default=_default_edid): - self._hpd_notif = CSRStatus() - self._hpd_en = CSRStorage() - self.specials.mem = Memory(8, 128, init=default) - - ### - - # HPD - if hasattr(pads, "hpd_notif"): - self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status) - else: - self.comb += self._hpd_notif.status.eq(1) - if hasattr(pads, "hpd_en"): - self.comb += pads.hpd_en.eq(self._hpd_en.storage) - - # EDID - scl_raw = Signal() - sda_i = Signal() - sda_drv = Signal() - _sda_drv_reg = Signal() - _sda_i_async = Signal() - self.sync += _sda_drv_reg.eq(sda_drv) - self.specials += [ - MultiReg(pads.scl, scl_raw), - Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async), - MultiReg(_sda_i_async, sda_i) - ] - - scl_i = Signal() - samp_count = Signal(6) - samp_carry = Signal() - self.sync += [ - Cat(samp_count, samp_carry).eq(samp_count + 1), - If(samp_carry, scl_i.eq(scl_raw)) - ] - - scl_r = Signal() - sda_r = Signal() - scl_rising = Signal() - sda_rising = Signal() - sda_falling = Signal() - self.sync += [ - scl_r.eq(scl_i), - sda_r.eq(sda_i) - ] - self.comb += [ - scl_rising.eq(scl_i & ~scl_r), - sda_rising.eq(sda_i & ~sda_r), - sda_falling.eq(~sda_i & sda_r) - ] - - start = Signal() - self.comb += start.eq(scl_i & sda_falling) - - din = Signal(8) - counter = Signal(max=9) - self.sync += [ - If(start, counter.eq(0)), - If(scl_rising, - If(counter == 8, - counter.eq(0) - ).Else( - counter.eq(counter + 1), - din.eq(Cat(sda_i, din[:7])) - ) - ) - ] - - is_read = Signal() - update_is_read = Signal() - self.sync += If(update_is_read, is_read.eq(din[0])) - - offset_counter = Signal(max=128) - oc_load = Signal() - oc_inc = Signal() - self.sync += [ - If(oc_load, - offset_counter.eq(din) - ).Elif(oc_inc, - offset_counter.eq(offset_counter + 1) - ) - ] - rdport = self.mem.get_port() - self.specials += rdport - self.comb += rdport.adr.eq(offset_counter) - data_bit = Signal() - - zero_drv = Signal() - data_drv = Signal() - self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit)) - - data_drv_en = Signal() - data_drv_stop = Signal() - self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0)) - self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True)) - - fsm = FSM() - self.submodules += fsm - - fsm.act("WAIT_START") - fsm.act("RCV_ADDRESS", - If(counter == 8, - If(din[1:] == 0x50, - update_is_read.eq(1), - NextState("ACK_ADDRESS0") - ).Else( - NextState("WAIT_START") - ) - ) - ) - fsm.act("ACK_ADDRESS0", - If(~scl_i, NextState("ACK_ADDRESS1")) - ) - fsm.act("ACK_ADDRESS1", - zero_drv.eq(1), - If(scl_i, NextState("ACK_ADDRESS2")) - ) - fsm.act("ACK_ADDRESS2", - zero_drv.eq(1), - If(~scl_i, - If(is_read, - NextState("READ") - ).Else( - NextState("RCV_OFFSET") - ) - ) - ) - - fsm.act("RCV_OFFSET", - If(counter == 8, - oc_load.eq(1), - NextState("ACK_OFFSET0") - ) - ) - fsm.act("ACK_OFFSET0", - If(~scl_i, NextState("ACK_OFFSET1")) - ) - fsm.act("ACK_OFFSET1", - zero_drv.eq(1), - If(scl_i, NextState("ACK_OFFSET2")) - ) - fsm.act("ACK_OFFSET2", - zero_drv.eq(1), - If(~scl_i, NextState("RCV_ADDRESS")) - ) - - fsm.act("READ", - If(~scl_i, - If(counter == 8, - data_drv_stop.eq(1), - NextState("ACK_READ") - ).Else( - data_drv_en.eq(1) - ) - ) - ) - fsm.act("ACK_READ", - If(scl_rising, - oc_inc.eq(1), - If(sda_i, - NextState("WAIT_START") - ).Else( - NextState("READ") - ) - ) - ) - - for state in fsm.actions.keys(): - fsm.act(state, If(start, NextState("RCV_ADDRESS"))) - fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START"))) + def __init__(self, pads, default=_default_edid): + self._hpd_notif = CSRStatus() + self._hpd_en = CSRStorage() + self.specials.mem = Memory(8, 128, init=default) + + ### + + # HPD + if hasattr(pads, "hpd_notif"): + self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status) + else: + self.comb += self._hpd_notif.status.eq(1) + if hasattr(pads, "hpd_en"): + self.comb += pads.hpd_en.eq(self._hpd_en.storage) + + # EDID + scl_raw = Signal() + sda_i = Signal() + sda_drv = Signal() + _sda_drv_reg = Signal() + _sda_i_async = Signal() + self.sync += _sda_drv_reg.eq(sda_drv) + self.specials += [ + MultiReg(pads.scl, scl_raw), + Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async), + MultiReg(_sda_i_async, sda_i) + ] + + scl_i = Signal() + samp_count = Signal(6) + samp_carry = Signal() + self.sync += [ + Cat(samp_count, samp_carry).eq(samp_count + 1), + If(samp_carry, scl_i.eq(scl_raw)) + ] + + scl_r = Signal() + sda_r = Signal() + scl_rising = Signal() + sda_rising = Signal() + sda_falling = Signal() + self.sync += [ + scl_r.eq(scl_i), + sda_r.eq(sda_i) + ] + self.comb += [ + scl_rising.eq(scl_i & ~scl_r), + sda_rising.eq(sda_i & ~sda_r), + sda_falling.eq(~sda_i & sda_r) + ] + + start = Signal() + self.comb += start.eq(scl_i & sda_falling) + + din = Signal(8) + counter = Signal(max=9) + self.sync += [ + If(start, counter.eq(0)), + If(scl_rising, + If(counter == 8, + counter.eq(0) + ).Else( + counter.eq(counter + 1), + din.eq(Cat(sda_i, din[:7])) + ) + ) + ] + + is_read = Signal() + update_is_read = Signal() + self.sync += If(update_is_read, is_read.eq(din[0])) + + offset_counter = Signal(max=128) + oc_load = Signal() + oc_inc = Signal() + self.sync += [ + If(oc_load, + offset_counter.eq(din) + ).Elif(oc_inc, + offset_counter.eq(offset_counter + 1) + ) + ] + rdport = self.mem.get_port() + self.specials += rdport + self.comb += rdport.adr.eq(offset_counter) + data_bit = Signal() + + zero_drv = Signal() + data_drv = Signal() + self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit)) + + data_drv_en = Signal() + data_drv_stop = Signal() + self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0)) + self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True)) + + fsm = FSM() + self.submodules += fsm + + fsm.act("WAIT_START") + fsm.act("RCV_ADDRESS", + If(counter == 8, + If(din[1:] == 0x50, + update_is_read.eq(1), + NextState("ACK_ADDRESS0") + ).Else( + NextState("WAIT_START") + ) + ) + ) + fsm.act("ACK_ADDRESS0", + If(~scl_i, NextState("ACK_ADDRESS1")) + ) + fsm.act("ACK_ADDRESS1", + zero_drv.eq(1), + If(scl_i, NextState("ACK_ADDRESS2")) + ) + fsm.act("ACK_ADDRESS2", + zero_drv.eq(1), + If(~scl_i, + If(is_read, + NextState("READ") + ).Else( + NextState("RCV_OFFSET") + ) + ) + ) + + fsm.act("RCV_OFFSET", + If(counter == 8, + oc_load.eq(1), + NextState("ACK_OFFSET0") + ) + ) + fsm.act("ACK_OFFSET0", + If(~scl_i, NextState("ACK_OFFSET1")) + ) + fsm.act("ACK_OFFSET1", + zero_drv.eq(1), + If(scl_i, NextState("ACK_OFFSET2")) + ) + fsm.act("ACK_OFFSET2", + zero_drv.eq(1), + If(~scl_i, NextState("RCV_ADDRESS")) + ) + + fsm.act("READ", + If(~scl_i, + If(counter == 8, + data_drv_stop.eq(1), + NextState("ACK_READ") + ).Else( + data_drv_en.eq(1) + ) + ) + ) + fsm.act("ACK_READ", + If(scl_rising, + oc_inc.eq(1), + If(sda_i, + NextState("WAIT_START") + ).Else( + NextState("READ") + ) + ) + ) + + for state in fsm.actions.keys(): + fsm.act(state, If(start, NextState("RCV_ADDRESS"))) + fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START"))) diff --git a/misoclib/video/dvisampler/wer.py b/misoclib/video/dvisampler/wer.py index 2a8a0cce..f75d4452 100644 --- a/misoclib/video/dvisampler/wer.py +++ b/misoclib/video/dvisampler/wer.py @@ -6,54 +6,54 @@ from migen.genlib.cdc import PulseSynchronizer from misoclib.video.dvisampler.common import control_tokens class WER(Module, AutoCSR): - def __init__(self, period_bits=24): - self.data = Signal(10) - self._update = CSR() - self._value = CSRStatus(period_bits) - - ### - - # pipeline stage 1 - # we ignore the 10th (inversion) bit, as it is independent of the transition minimization - data_r = Signal(9) - self.sync.pix += data_r.eq(self.data[:9]) - - # pipeline stage 2 - transitions = Signal(8) - self.comb += [transitions[i].eq(data_r[i] ^ data_r[i+1]) for i in range(8)] - transition_count = Signal(max=9) - self.sync.pix += transition_count.eq(optree("+", [transitions[i] for i in range(8)])) - - is_control = Signal() - self.sync.pix += is_control.eq(optree("|", [data_r == ct for ct in control_tokens])) - - # pipeline stage 3 - is_error = Signal() - self.sync.pix += is_error.eq((transition_count > 4) & ~is_control) - - # counter - period_counter = Signal(period_bits) - period_done = Signal() - self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1) - - wer_counter = Signal(period_bits) - wer_counter_r = Signal(period_bits) - wer_counter_r_updated = Signal() - self.sync.pix += [ - wer_counter_r_updated.eq(period_done), - If(period_done, - wer_counter_r.eq(wer_counter), - wer_counter.eq(0) - ).Elif(is_error, - wer_counter.eq(wer_counter + 1) - ) - ] - - # sync to system clock domain - wer_counter_sys = Signal(period_bits) - self.submodules.ps_counter = PulseSynchronizer("pix", "sys") - self.comb += self.ps_counter.i.eq(wer_counter_r_updated) - self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r)) - - # register interface - self.sync += If(self._update.re, self._value.status.eq(wer_counter_sys)) + def __init__(self, period_bits=24): + self.data = Signal(10) + self._update = CSR() + self._value = CSRStatus(period_bits) + + ### + + # pipeline stage 1 + # we ignore the 10th (inversion) bit, as it is independent of the transition minimization + data_r = Signal(9) + self.sync.pix += data_r.eq(self.data[:9]) + + # pipeline stage 2 + transitions = Signal(8) + self.comb += [transitions[i].eq(data_r[i] ^ data_r[i+1]) for i in range(8)] + transition_count = Signal(max=9) + self.sync.pix += transition_count.eq(optree("+", [transitions[i] for i in range(8)])) + + is_control = Signal() + self.sync.pix += is_control.eq(optree("|", [data_r == ct for ct in control_tokens])) + + # pipeline stage 3 + is_error = Signal() + self.sync.pix += is_error.eq((transition_count > 4) & ~is_control) + + # counter + period_counter = Signal(period_bits) + period_done = Signal() + self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1) + + wer_counter = Signal(period_bits) + wer_counter_r = Signal(period_bits) + wer_counter_r_updated = Signal() + self.sync.pix += [ + wer_counter_r_updated.eq(period_done), + If(period_done, + wer_counter_r.eq(wer_counter), + wer_counter.eq(0) + ).Elif(is_error, + wer_counter.eq(wer_counter + 1) + ) + ] + + # sync to system clock domain + wer_counter_sys = Signal(period_bits) + self.submodules.ps_counter = PulseSynchronizer("pix", "sys") + self.comb += self.ps_counter.i.eq(wer_counter_r_updated) + self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r)) + + # register interface + self.sync += If(self._update.re, self._value.status.eq(wer_counter_sys)) diff --git a/misoclib/video/framebuffer/__init__.py b/misoclib/video/framebuffer/__init__.py index 433812cf..54f25d81 100644 --- a/misoclib/video/framebuffer/__init__.py +++ b/misoclib/video/framebuffer/__init__.py @@ -9,24 +9,24 @@ from misoclib.video.framebuffer.format import bpp, pixel_layout, FrameInitiator, from misoclib.video.framebuffer.phy import Driver class Framebuffer(Module, AutoCSR): - def __init__(self, pads_vga, pads_dvi, lasmim): - pack_factor = lasmim.dw//bpp + def __init__(self, pads_vga, pads_dvi, lasmim): + pack_factor = lasmim.dw//bpp - g = DataFlowGraph() + g = DataFlowGraph() - self.fi = FrameInitiator(lasmim.aw, pack_factor) + self.fi = FrameInitiator(lasmim.aw, pack_factor) - intseq = misc.IntSequence(lasmim.aw, lasmim.aw) - dma_out = AbstractActor(plumbing.Buffer) - g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr()) - g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out) + intseq = misc.IntSequence(lasmim.aw, lasmim.aw) + dma_out = AbstractActor(plumbing.Buffer) + g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr()) + g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out) - cast = structuring.Cast(lasmim.dw, pixel_layout(pack_factor), reverse_to=True) - vtg = VTG(pack_factor) - self.driver = Driver(pack_factor, pads_vga, pads_dvi) + cast = structuring.Cast(lasmim.dw, pixel_layout(pack_factor), reverse_to=True) + vtg = VTG(pack_factor) + self.driver = Driver(pack_factor, pads_vga, pads_dvi) - g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing") - g.add_connection(dma_out, cast) - g.add_connection(cast, vtg, sink_ep="pixels") - g.add_connection(vtg, self.driver) - self.submodules += CompositeActor(g) + g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing") + g.add_connection(dma_out, cast) + g.add_connection(cast, vtg, sink_ep="pixels") + g.add_connection(vtg, self.driver) + self.submodules += CompositeActor(g) diff --git a/misoclib/video/framebuffer/dvi.py b/misoclib/video/framebuffer/dvi.py index c53dd158..ac51493e 100644 --- a/misoclib/video/framebuffer/dvi.py +++ b/misoclib/video/framebuffer/dvi.py @@ -4,216 +4,216 @@ from migen.genlib.misc import optree control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011] class Encoder(Module): - def __init__(self): - self.d = Signal(8) - self.c = Signal(2) - self.de = Signal() - - self.out = Signal(10) - - ### - - # stage 1 - count number of 1s in data - d = Signal(8) - n1d = Signal(max=9) - self.sync += [ - n1d.eq(optree("+", [self.d[i] for i in range(8)])), - d.eq(self.d) - ] - - # stage 2 - add 9th bit - q_m = Signal(9) - q_m8_n = Signal() - self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0])) - for i in range(8): - if i: - curval = curval ^ d[i] ^ q_m8_n - else: - curval = d[0] - self.sync += q_m[i].eq(curval) - self.sync += q_m[8].eq(~q_m8_n) - - # stage 3 - count number of 1s and 0s in q_m[:8] - q_m_r = Signal(9) - n0q_m = Signal(max=9) - n1q_m = Signal(max=9) - self.sync += [ - n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])), - n1q_m.eq(optree("+", [q_m[i] for i in range(8)])), - q_m_r.eq(q_m) - ] - - # stage 4 - final encoding - cnt = Signal((6, True)) - - s_c = self.c - s_de = self.de - for p in range(3): - new_c = Signal(2) - new_de = Signal() - self.sync += new_c.eq(s_c), new_de.eq(s_de) - s_c, s_de = new_c, new_de - - self.sync += If(s_de, - If((cnt == 0) | (n1q_m == n0q_m), - self.out[9].eq(~q_m_r[8]), - self.out[8].eq(q_m_r[8]), - If(q_m_r[8], - self.out[:8].eq(q_m_r[:8]), - cnt.eq(cnt + n1q_m - n0q_m) - ).Else( - self.out[:8].eq(~q_m_r[:8]), - cnt.eq(cnt + n0q_m - n1q_m) - ) - ).Else( - If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)), - self.out[9].eq(1), - self.out[8].eq(q_m_r[8]), - self.out[:8].eq(~q_m_r[:8]), - cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m) - ).Else( - self.out[9].eq(0), - self.out[8].eq(q_m_r[8]), - self.out[:8].eq(q_m_r[:8]), - cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m) - ) - ) - ).Else( - self.out.eq(Array(control_tokens)[s_c]), - cnt.eq(0) - ) + def __init__(self): + self.d = Signal(8) + self.c = Signal(2) + self.de = Signal() + + self.out = Signal(10) + + ### + + # stage 1 - count number of 1s in data + d = Signal(8) + n1d = Signal(max=9) + self.sync += [ + n1d.eq(optree("+", [self.d[i] for i in range(8)])), + d.eq(self.d) + ] + + # stage 2 - add 9th bit + q_m = Signal(9) + q_m8_n = Signal() + self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0])) + for i in range(8): + if i: + curval = curval ^ d[i] ^ q_m8_n + else: + curval = d[0] + self.sync += q_m[i].eq(curval) + self.sync += q_m[8].eq(~q_m8_n) + + # stage 3 - count number of 1s and 0s in q_m[:8] + q_m_r = Signal(9) + n0q_m = Signal(max=9) + n1q_m = Signal(max=9) + self.sync += [ + n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])), + n1q_m.eq(optree("+", [q_m[i] for i in range(8)])), + q_m_r.eq(q_m) + ] + + # stage 4 - final encoding + cnt = Signal((6, True)) + + s_c = self.c + s_de = self.de + for p in range(3): + new_c = Signal(2) + new_de = Signal() + self.sync += new_c.eq(s_c), new_de.eq(s_de) + s_c, s_de = new_c, new_de + + self.sync += If(s_de, + If((cnt == 0) | (n1q_m == n0q_m), + self.out[9].eq(~q_m_r[8]), + self.out[8].eq(q_m_r[8]), + If(q_m_r[8], + self.out[:8].eq(q_m_r[:8]), + cnt.eq(cnt + n1q_m - n0q_m) + ).Else( + self.out[:8].eq(~q_m_r[:8]), + cnt.eq(cnt + n0q_m - n1q_m) + ) + ).Else( + If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)), + self.out[9].eq(1), + self.out[8].eq(q_m_r[8]), + self.out[:8].eq(~q_m_r[:8]), + cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m) + ).Else( + self.out[9].eq(0), + self.out[8].eq(q_m_r[8]), + self.out[:8].eq(q_m_r[:8]), + cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m) + ) + ) + ).Else( + self.out.eq(Array(control_tokens)[s_c]), + cnt.eq(0) + ) class _EncoderSerializer(Module): - def __init__(self, serdesstrobe, pad_p, pad_n): - self.submodules.encoder = RenameClockDomains(Encoder(), "pix") - self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de - - ### - - # 2X soft serialization - ed_2x = Signal(5) - self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:])) - - # 5X hard serialization - cascade_di = Signal() - cascade_do = Signal() - cascade_ti = Signal() - cascade_to = Signal() - pad_se = Signal() - self.specials += [ - Instance("OSERDES2", - p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", - p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL", - - o_OQ=pad_se, - i_OCE=1, i_IOCE=serdesstrobe, i_RST=0, - i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"), - i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0, - i_T1=0, i_T2=0, i_T3=0, i_T4=0, - i_TRAIN=0, i_TCE=1, - i_SHIFTIN1=1, i_SHIFTIN2=1, - i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to, - o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti), - Instance("OSERDES2", - p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", - p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL", - - i_OCE=1, i_IOCE=serdesstrobe, i_RST=0, - i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"), - i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3], - i_T1=0, i_T2=0, i_T3=0, i_T4=0, - i_TRAIN=0, i_TCE=1, - i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti, - i_SHIFTIN3=1, i_SHIFTIN4=1, - o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to), - Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n) - ] + def __init__(self, serdesstrobe, pad_p, pad_n): + self.submodules.encoder = RenameClockDomains(Encoder(), "pix") + self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de + + ### + + # 2X soft serialization + ed_2x = Signal(5) + self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:])) + + # 5X hard serialization + cascade_di = Signal() + cascade_do = Signal() + cascade_ti = Signal() + cascade_to = Signal() + pad_se = Signal() + self.specials += [ + Instance("OSERDES2", + p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", + p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL", + + o_OQ=pad_se, + i_OCE=1, i_IOCE=serdesstrobe, i_RST=0, + i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"), + i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0, + i_T1=0, i_T2=0, i_T3=0, i_T4=0, + i_TRAIN=0, i_TCE=1, + i_SHIFTIN1=1, i_SHIFTIN2=1, + i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to, + o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti), + Instance("OSERDES2", + p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", + p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL", + + i_OCE=1, i_IOCE=serdesstrobe, i_RST=0, + i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"), + i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3], + i_T1=0, i_T2=0, i_T3=0, i_T4=0, + i_TRAIN=0, i_TCE=1, + i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti, + i_SHIFTIN3=1, i_SHIFTIN4=1, + o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to), + Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n) + ] class PHY(Module): - def __init__(self, serdesstrobe, pads): - self.hsync = Signal() - self.vsync = Signal() - self.de = Signal() - self.r = Signal(8) - self.g = Signal(8) - self.b = Signal(8) - - ### - - self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n) - self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n) - self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n) - self.comb += [ - self.es0.d.eq(self.r), - self.es1.d.eq(self.g), - self.es2.d.eq(self.b), - self.es0.c.eq(Cat(self.hsync, self.vsync)), - self.es1.c.eq(0), - self.es2.c.eq(0), - self.es0.de.eq(self.de), - self.es1.de.eq(self.de), - self.es2.de.eq(self.de), - ] + def __init__(self, serdesstrobe, pads): + self.hsync = Signal() + self.vsync = Signal() + self.de = Signal() + self.r = Signal(8) + self.g = Signal(8) + self.b = Signal(8) + + ### + + self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n) + self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n) + self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n) + self.comb += [ + self.es0.d.eq(self.r), + self.es1.d.eq(self.g), + self.es2.d.eq(self.b), + self.es0.c.eq(Cat(self.hsync, self.vsync)), + self.es1.c.eq(0), + self.es2.c.eq(0), + self.es0.de.eq(self.de), + self.es1.de.eq(self.de), + self.es2.de.eq(self.de), + ] class _EncoderTB(Module): - def __init__(self, inputs): - self.outs = [] - self._iter_inputs = iter(inputs) - self._end_cycle = None - self.submodules.dut = Encoder() - self.comb += self.dut.de.eq(1) - - def do_simulation(self, selfp): - if self._end_cycle is None: - try: - nv = next(self._iter_inputs) - except StopIteration: - self._end_cycle = selfp.simulator.cycle_counter + 4 - else: - selfp.dut.d = nv - if selfp.simulator.cycle_counter == self._end_cycle: - raise StopSimulation - if selfp.simulator.cycle_counter > 4: - self.outs.append(selfp.dut.out) + def __init__(self, inputs): + self.outs = [] + self._iter_inputs = iter(inputs) + self._end_cycle = None + self.submodules.dut = Encoder() + self.comb += self.dut.de.eq(1) + + def do_simulation(self, selfp): + if self._end_cycle is None: + try: + nv = next(self._iter_inputs) + except StopIteration: + self._end_cycle = selfp.simulator.cycle_counter + 4 + else: + selfp.dut.d = nv + if selfp.simulator.cycle_counter == self._end_cycle: + raise StopSimulation + if selfp.simulator.cycle_counter > 4: + self.outs.append(selfp.dut.out) def _bit(i, n): - return (i >> n) & 1 + return (i >> n) & 1 def _decode_tmds(b): - try: - c = control_tokens.index(b) - de = False - except ValueError: - c = 0 - de = True - vsync = bool(c & 2) - hsync = bool(c & 1) + try: + c = control_tokens.index(b) + de = False + except ValueError: + c = 0 + de = True + vsync = bool(c & 2) + hsync = bool(c & 1) - value = _bit(b, 0) ^ _bit(b, 9) - for i in range(1, 8): - value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i + value = _bit(b, 0) ^ _bit(b, 9) + for i in range(1, 8): + value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i - return de, hsync, vsync, value + return de, hsync, vsync, value if __name__ == "__main__": - from migen.sim.generic import run_simulation - from random import Random - - rng = Random(788) - test_list = [rng.randrange(256) for i in range(500)] - tb = _EncoderTB(test_list) - run_simulation(tb) - - check = [_decode_tmds(out)[3] for out in tb.outs] - assert(check == test_list) - - nb0 = 0 - nb1 = 0 - for out in tb.outs: - for i in range(10): - if _bit(out, i): - nb1 += 1 - else: - nb0 += 1 - print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1)) + from migen.sim.generic import run_simulation + from random import Random + + rng = Random(788) + test_list = [rng.randrange(256) for i in range(500)] + tb = _EncoderTB(test_list) + run_simulation(tb) + + check = [_decode_tmds(out)[3] for out in tb.outs] + assert(check == test_list) + + nb0 = 0 + nb1 = 0 + for out in tb.outs: + for i in range(10): + if _bit(out, i): + nb1 += 1 + else: + nb0 += 1 + print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1)) diff --git a/misoclib/video/framebuffer/format.py b/misoclib/video/framebuffer/format.py index 29d94b9c..5b177644 100644 --- a/misoclib/video/framebuffer/format.py +++ b/misoclib/video/framebuffer/format.py @@ -11,134 +11,134 @@ _vbits = 12 bpp = 32 bpc = 10 pixel_layout_s = [ - ("pad", bpp-3*bpc), - ("r", bpc), - ("g", bpc), - ("b", bpc) + ("pad", bpp-3*bpc), + ("r", bpc), + ("g", bpc), + ("b", bpc) ] def pixel_layout(pack_factor): - return [("p"+str(i), pixel_layout_s) for i in range(pack_factor)] + return [("p"+str(i), pixel_layout_s) for i in range(pack_factor)] bpc_phy = 8 phy_layout_s = [ - ("r", bpc_phy), - ("g", bpc_phy), - ("b", bpc_phy) + ("r", bpc_phy), + ("g", bpc_phy), + ("b", bpc_phy) ] def phy_layout(pack_factor): - r = [("hsync", 1), ("vsync", 1), ("de", 1)] - for i in range(pack_factor): - r.append(("p"+str(i), phy_layout_s)) - return r + r = [("hsync", 1), ("vsync", 1), ("de", 1)] + for i in range(pack_factor): + r.append(("p"+str(i), phy_layout_s)) + return r class FrameInitiator(spi.SingleGenerator): - def __init__(self, bus_aw, pack_factor, ndmas=1): - h_alignment_bits = log2_int(pack_factor) - hbits_dyn = _hbits - h_alignment_bits - bus_alignment_bits = h_alignment_bits + log2_int(bpp//8) - layout = [ - ("hres", hbits_dyn, 640, h_alignment_bits), - ("hsync_start", hbits_dyn, 656, h_alignment_bits), - ("hsync_end", hbits_dyn, 752, h_alignment_bits), - ("hscan", hbits_dyn, 800, h_alignment_bits), - - ("vres", _vbits, 480), - ("vsync_start", _vbits, 492), - ("vsync_end", _vbits, 494), - ("vscan", _vbits, 525), - - ("length", bus_aw + bus_alignment_bits, 640*480*bpp//8, bus_alignment_bits) - ] - layout += [("base"+str(i), bus_aw + bus_alignment_bits, 0, bus_alignment_bits) - for i in range(ndmas)] - spi.SingleGenerator.__init__(self, layout, spi.MODE_CONTINUOUS) - - timing_subr = ["hres", "hsync_start", "hsync_end", "hscan", - "vres", "vsync_start", "vsync_end", "vscan"] - - def dma_subr(self, i=0): - return ["length", "base"+str(i)] + def __init__(self, bus_aw, pack_factor, ndmas=1): + h_alignment_bits = log2_int(pack_factor) + hbits_dyn = _hbits - h_alignment_bits + bus_alignment_bits = h_alignment_bits + log2_int(bpp//8) + layout = [ + ("hres", hbits_dyn, 640, h_alignment_bits), + ("hsync_start", hbits_dyn, 656, h_alignment_bits), + ("hsync_end", hbits_dyn, 752, h_alignment_bits), + ("hscan", hbits_dyn, 800, h_alignment_bits), + + ("vres", _vbits, 480), + ("vsync_start", _vbits, 492), + ("vsync_end", _vbits, 494), + ("vscan", _vbits, 525), + + ("length", bus_aw + bus_alignment_bits, 640*480*bpp//8, bus_alignment_bits) + ] + layout += [("base"+str(i), bus_aw + bus_alignment_bits, 0, bus_alignment_bits) + for i in range(ndmas)] + spi.SingleGenerator.__init__(self, layout, spi.MODE_CONTINUOUS) + + timing_subr = ["hres", "hsync_start", "hsync_end", "hscan", + "vres", "vsync_start", "vsync_end", "vscan"] + + def dma_subr(self, i=0): + return ["length", "base"+str(i)] class VTG(Module): - def __init__(self, pack_factor): - hbits_dyn = _hbits - log2_int(pack_factor) - timing_layout = [ - ("hres", hbits_dyn), - ("hsync_start", hbits_dyn), - ("hsync_end", hbits_dyn), - ("hscan", hbits_dyn), - ("vres", _vbits), - ("vsync_start", _vbits), - ("vsync_end", _vbits), - ("vscan", _vbits)] - self.timing = Sink(timing_layout) - self.pixels = Sink(pixel_layout(pack_factor)) - self.phy = Source(phy_layout(pack_factor)) - self.busy = Signal() - - ### - - hactive = Signal() - vactive = Signal() - active = Signal() - - hcounter = Signal(hbits_dyn) - vcounter = Signal(_vbits) - - skip = bpc - bpc_phy - self.comb += [ - active.eq(hactive & vactive), - If(active, - [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:]) - for p in ["p"+str(i) for i in range(pack_factor)] for c in ["r", "g", "b"]], - self.phy.de.eq(1) - ), - self.pixels.ack.eq(self.phy.ack & active) - ] - - load_timing = Signal() - tr = Record(timing_layout) - self.sync += If(load_timing, tr.eq(self.timing.payload)) - - generate_en = Signal() - generate_frame_done = Signal() - self.sync += [ - generate_frame_done.eq(0), - If(generate_en, - hcounter.eq(hcounter + 1), - - If(hcounter == 0, hactive.eq(1)), - If(hcounter == tr.hres, hactive.eq(0)), - If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)), - If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)), - If(hcounter == tr.hscan, - hcounter.eq(0), - If(vcounter == tr.vscan, - vcounter.eq(0), - generate_frame_done.eq(1) - ).Else( - vcounter.eq(vcounter + 1) - ) - ), - - If(vcounter == 0, vactive.eq(1)), - If(vcounter == tr.vres, vactive.eq(0)), - If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)), - If(vcounter == tr.vsync_end, self.phy.vsync.eq(0)) - ) - ] - - self.submodules.fsm = FSM() - self.fsm.act("GET_TIMING", - self.timing.ack.eq(1), - load_timing.eq(1), - If(self.timing.stb, NextState("GENERATE")) - ) - self.fsm.act("GENERATE", - self.busy.eq(1), - If(~active | self.pixels.stb, - self.phy.stb.eq(1), - If(self.phy.ack, generate_en.eq(1)) - ), - If(generate_frame_done, NextState("GET_TIMING")) - ) + def __init__(self, pack_factor): + hbits_dyn = _hbits - log2_int(pack_factor) + timing_layout = [ + ("hres", hbits_dyn), + ("hsync_start", hbits_dyn), + ("hsync_end", hbits_dyn), + ("hscan", hbits_dyn), + ("vres", _vbits), + ("vsync_start", _vbits), + ("vsync_end", _vbits), + ("vscan", _vbits)] + self.timing = Sink(timing_layout) + self.pixels = Sink(pixel_layout(pack_factor)) + self.phy = Source(phy_layout(pack_factor)) + self.busy = Signal() + + ### + + hactive = Signal() + vactive = Signal() + active = Signal() + + hcounter = Signal(hbits_dyn) + vcounter = Signal(_vbits) + + skip = bpc - bpc_phy + self.comb += [ + active.eq(hactive & vactive), + If(active, + [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:]) + for p in ["p"+str(i) for i in range(pack_factor)] for c in ["r", "g", "b"]], + self.phy.de.eq(1) + ), + self.pixels.ack.eq(self.phy.ack & active) + ] + + load_timing = Signal() + tr = Record(timing_layout) + self.sync += If(load_timing, tr.eq(self.timing.payload)) + + generate_en = Signal() + generate_frame_done = Signal() + self.sync += [ + generate_frame_done.eq(0), + If(generate_en, + hcounter.eq(hcounter + 1), + + If(hcounter == 0, hactive.eq(1)), + If(hcounter == tr.hres, hactive.eq(0)), + If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)), + If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)), + If(hcounter == tr.hscan, + hcounter.eq(0), + If(vcounter == tr.vscan, + vcounter.eq(0), + generate_frame_done.eq(1) + ).Else( + vcounter.eq(vcounter + 1) + ) + ), + + If(vcounter == 0, vactive.eq(1)), + If(vcounter == tr.vres, vactive.eq(0)), + If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)), + If(vcounter == tr.vsync_end, self.phy.vsync.eq(0)) + ) + ] + + self.submodules.fsm = FSM() + self.fsm.act("GET_TIMING", + self.timing.ack.eq(1), + load_timing.eq(1), + If(self.timing.stb, NextState("GENERATE")) + ) + self.fsm.act("GENERATE", + self.busy.eq(1), + If(~active | self.pixels.stb, + self.phy.stb.eq(1), + If(self.phy.ack, generate_en.eq(1)) + ), + If(generate_frame_done, NextState("GET_TIMING")) + ) diff --git a/misoclib/video/framebuffer/phy.py b/misoclib/video/framebuffer/phy.py index 21d5c587..297fc025 100644 --- a/misoclib/video/framebuffer/phy.py +++ b/misoclib/video/framebuffer/phy.py @@ -8,212 +8,212 @@ from misoclib.video.framebuffer.format import bpc_phy, phy_layout from misoclib.video.framebuffer import dvi class _FIFO(Module): - def __init__(self, pack_factor): - self.phy = Sink(phy_layout(pack_factor)) - self.busy = Signal() - - self.pix_hsync = Signal() - self.pix_vsync = Signal() - self.pix_de = Signal() - self.pix_r = Signal(bpc_phy) - self.pix_g = Signal(bpc_phy) - self.pix_b = Signal(bpc_phy) - - ### - - fifo = RenameClockDomains(AsyncFIFO(phy_layout(pack_factor), 512), - {"write": "sys", "read": "pix"}) - self.submodules += fifo - self.comb += [ - self.phy.ack.eq(fifo.writable), - fifo.we.eq(self.phy.stb), - fifo.din.eq(self.phy.payload), - self.busy.eq(0) - ] - - unpack_counter = Signal(max=pack_factor) - assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2 - self.sync.pix += [ - unpack_counter.eq(unpack_counter + 1), - self.pix_hsync.eq(fifo.dout.hsync), - self.pix_vsync.eq(fifo.dout.vsync), - self.pix_de.eq(fifo.dout.de) - ] - for i in range(pack_factor): - pixel = getattr(fifo.dout, "p"+str(i)) - self.sync.pix += If(unpack_counter == i, - self.pix_r.eq(pixel.r), - self.pix_g.eq(pixel.g), - self.pix_b.eq(pixel.b) - ) - self.comb += fifo.re.eq(unpack_counter == (pack_factor - 1)) + def __init__(self, pack_factor): + self.phy = Sink(phy_layout(pack_factor)) + self.busy = Signal() + + self.pix_hsync = Signal() + self.pix_vsync = Signal() + self.pix_de = Signal() + self.pix_r = Signal(bpc_phy) + self.pix_g = Signal(bpc_phy) + self.pix_b = Signal(bpc_phy) + + ### + + fifo = RenameClockDomains(AsyncFIFO(phy_layout(pack_factor), 512), + {"write": "sys", "read": "pix"}) + self.submodules += fifo + self.comb += [ + self.phy.ack.eq(fifo.writable), + fifo.we.eq(self.phy.stb), + fifo.din.eq(self.phy.payload), + self.busy.eq(0) + ] + + unpack_counter = Signal(max=pack_factor) + assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2 + self.sync.pix += [ + unpack_counter.eq(unpack_counter + 1), + self.pix_hsync.eq(fifo.dout.hsync), + self.pix_vsync.eq(fifo.dout.vsync), + self.pix_de.eq(fifo.dout.de) + ] + for i in range(pack_factor): + pixel = getattr(fifo.dout, "p"+str(i)) + self.sync.pix += If(unpack_counter == i, + self.pix_r.eq(pixel.r), + self.pix_g.eq(pixel.g), + self.pix_b.eq(pixel.b) + ) + self.comb += fifo.re.eq(unpack_counter == (pack_factor - 1)) # This assumes a 50MHz base clock class _Clocking(Module, AutoCSR): - def __init__(self, pads_vga, pads_dvi): - self._cmd_data = CSRStorage(10) - self._send_cmd_data = CSR() - self._send_go = CSR() - self._status = CSRStatus(4) - - self.clock_domains.cd_pix = ClockDomain(reset_less=True) - if pads_dvi is not None: - self._pll_reset = CSRStorage() - self._pll_adr = CSRStorage(5) - self._pll_dat_r = CSRStatus(16) - self._pll_dat_w = CSRStorage(16) - self._pll_read = CSR() - self._pll_write = CSR() - self._pll_drdy = CSRStatus() - - self.clock_domains.cd_pix2x = ClockDomain(reset_less=True) - self.clock_domains.cd_pix10x = ClockDomain(reset_less=True) - self.serdesstrobe = Signal() - - ### - - # Generate 1x pixel clock - clk_pix_unbuffered = Signal() - pix_progdata = Signal() - pix_progen = Signal() - pix_progdone = Signal() - pix_locked = Signal() - self.specials += Instance("DCM_CLKGEN", - p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=1.0, p_CLKFX_MULTIPLY=2, - p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", - - i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered, - i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen, - o_PROGDONE=pix_progdone, o_LOCKED=pix_locked, - i_FREEZEDCM=0, i_RST=ResetSignal()) - - remaining_bits = Signal(max=11) - transmitting = Signal() - self.comb += transmitting.eq(remaining_bits != 0) - sr = Signal(10) - self.sync += [ - If(self._send_cmd_data.re, - remaining_bits.eq(10), - sr.eq(self._cmd_data.storage) - ).Elif(transmitting, - remaining_bits.eq(remaining_bits - 1), - sr.eq(sr[1:]) - ) - ] - self.comb += [ - pix_progdata.eq(transmitting & sr[0]), - pix_progen.eq(transmitting | self._send_go.re) - ] - - # enforce gap between commands - busy_counter = Signal(max=14) - busy = Signal() - self.comb += busy.eq(busy_counter != 0) - self.sync += If(self._send_cmd_data.re, - busy_counter.eq(13) - ).Elif(busy, - busy_counter.eq(busy_counter - 1) - ) - - mult_locked = Signal() - self.comb += self._status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked)) - - # Clock multiplication and buffering - if pads_dvi is None: - # Just buffer 1x pixel clock - self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk) - self.comb += mult_locked.eq(pix_locked) - else: - # Route unbuffered 1x pixel clock to PLL - # Generate 1x, 2x and 10x IO pixel clocks - clkfbout = Signal() - pll_locked = Signal() - pll_clk0 = Signal() - pll_clk1 = Signal() - pll_clk2 = Signal() - locked_async = Signal() - pll_drdy = Signal() - self.sync += If(self._pll_read.re | self._pll_write.re, - self._pll_drdy.status.eq(0) - ).Elif(pll_drdy, - self._pll_drdy.status.eq(1) - ) - self.specials += [ - Instance("PLL_ADV", - p_CLKFBOUT_MULT=10, - p_CLKOUT0_DIVIDE=1, # pix10x - p_CLKOUT1_DIVIDE=5, # pix2x - p_CLKOUT2_DIVIDE=10, # pix - p_COMPENSATION="INTERNAL", - - i_CLKINSEL=1, - i_CLKIN1=clk_pix_unbuffered, - o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2, - o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout, - o_LOCKED=pll_locked, - i_RST=~pix_locked | self._pll_reset.storage, - - i_DADDR=self._pll_adr.storage, - o_DO=self._pll_dat_r.status, - i_DI=self._pll_dat_w.storage, - i_DEN=self._pll_read.re | self._pll_write.re, - i_DWE=self._pll_write.re, - o_DRDY=pll_drdy, - i_DCLK=ClockSignal()), - Instance("BUFPLL", p_DIVIDE=5, - i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked, - o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe), - Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk), - Instance("BUFG", name="dviout_pix_bufg", i_I=pll_clk2, o_O=self.cd_pix.clk), - MultiReg(locked_async, mult_locked, "sys") - ] - - # Drive VGA/DVI clock pads - if pads_vga is not None: - self.specials += Instance("ODDR2", - p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC", - o_Q=pads_vga.clk, - i_C0=ClockSignal("pix"), - i_C1=~ClockSignal("pix"), - i_CE=1, i_D0=1, i_D1=0, - i_R=0, i_S=0) - if pads_dvi is not None: - dvi_clk_se = Signal() - self.specials += Instance("ODDR2", - p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC", - o_Q=dvi_clk_se, - i_C0=ClockSignal("pix"), - i_C1=~ClockSignal("pix"), - i_CE=1, i_D0=1, i_D1=0, - i_R=0, i_S=0) - self.specials += Instance("OBUFDS", i_I=dvi_clk_se, - o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n) + def __init__(self, pads_vga, pads_dvi): + self._cmd_data = CSRStorage(10) + self._send_cmd_data = CSR() + self._send_go = CSR() + self._status = CSRStatus(4) + + self.clock_domains.cd_pix = ClockDomain(reset_less=True) + if pads_dvi is not None: + self._pll_reset = CSRStorage() + self._pll_adr = CSRStorage(5) + self._pll_dat_r = CSRStatus(16) + self._pll_dat_w = CSRStorage(16) + self._pll_read = CSR() + self._pll_write = CSR() + self._pll_drdy = CSRStatus() + + self.clock_domains.cd_pix2x = ClockDomain(reset_less=True) + self.clock_domains.cd_pix10x = ClockDomain(reset_less=True) + self.serdesstrobe = Signal() + + ### + + # Generate 1x pixel clock + clk_pix_unbuffered = Signal() + pix_progdata = Signal() + pix_progen = Signal() + pix_progdone = Signal() + pix_locked = Signal() + self.specials += Instance("DCM_CLKGEN", + p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=1.0, p_CLKFX_MULTIPLY=2, + p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", + + i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered, + i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen, + o_PROGDONE=pix_progdone, o_LOCKED=pix_locked, + i_FREEZEDCM=0, i_RST=ResetSignal()) + + remaining_bits = Signal(max=11) + transmitting = Signal() + self.comb += transmitting.eq(remaining_bits != 0) + sr = Signal(10) + self.sync += [ + If(self._send_cmd_data.re, + remaining_bits.eq(10), + sr.eq(self._cmd_data.storage) + ).Elif(transmitting, + remaining_bits.eq(remaining_bits - 1), + sr.eq(sr[1:]) + ) + ] + self.comb += [ + pix_progdata.eq(transmitting & sr[0]), + pix_progen.eq(transmitting | self._send_go.re) + ] + + # enforce gap between commands + busy_counter = Signal(max=14) + busy = Signal() + self.comb += busy.eq(busy_counter != 0) + self.sync += If(self._send_cmd_data.re, + busy_counter.eq(13) + ).Elif(busy, + busy_counter.eq(busy_counter - 1) + ) + + mult_locked = Signal() + self.comb += self._status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked)) + + # Clock multiplication and buffering + if pads_dvi is None: + # Just buffer 1x pixel clock + self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk) + self.comb += mult_locked.eq(pix_locked) + else: + # Route unbuffered 1x pixel clock to PLL + # Generate 1x, 2x and 10x IO pixel clocks + clkfbout = Signal() + pll_locked = Signal() + pll_clk0 = Signal() + pll_clk1 = Signal() + pll_clk2 = Signal() + locked_async = Signal() + pll_drdy = Signal() + self.sync += If(self._pll_read.re | self._pll_write.re, + self._pll_drdy.status.eq(0) + ).Elif(pll_drdy, + self._pll_drdy.status.eq(1) + ) + self.specials += [ + Instance("PLL_ADV", + p_CLKFBOUT_MULT=10, + p_CLKOUT0_DIVIDE=1, # pix10x + p_CLKOUT1_DIVIDE=5, # pix2x + p_CLKOUT2_DIVIDE=10, # pix + p_COMPENSATION="INTERNAL", + + i_CLKINSEL=1, + i_CLKIN1=clk_pix_unbuffered, + o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2, + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout, + o_LOCKED=pll_locked, + i_RST=~pix_locked | self._pll_reset.storage, + + i_DADDR=self._pll_adr.storage, + o_DO=self._pll_dat_r.status, + i_DI=self._pll_dat_w.storage, + i_DEN=self._pll_read.re | self._pll_write.re, + i_DWE=self._pll_write.re, + o_DRDY=pll_drdy, + i_DCLK=ClockSignal()), + Instance("BUFPLL", p_DIVIDE=5, + i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked, + o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe), + Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk), + Instance("BUFG", name="dviout_pix_bufg", i_I=pll_clk2, o_O=self.cd_pix.clk), + MultiReg(locked_async, mult_locked, "sys") + ] + + # Drive VGA/DVI clock pads + if pads_vga is not None: + self.specials += Instance("ODDR2", + p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC", + o_Q=pads_vga.clk, + i_C0=ClockSignal("pix"), + i_C1=~ClockSignal("pix"), + i_CE=1, i_D0=1, i_D1=0, + i_R=0, i_S=0) + if pads_dvi is not None: + dvi_clk_se = Signal() + self.specials += Instance("ODDR2", + p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC", + o_Q=dvi_clk_se, + i_C0=ClockSignal("pix"), + i_C1=~ClockSignal("pix"), + i_CE=1, i_D0=1, i_D1=0, + i_R=0, i_S=0) + self.specials += Instance("OBUFDS", i_I=dvi_clk_se, + o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n) class Driver(Module, AutoCSR): - def __init__(self, pack_factor, pads_vga, pads_dvi): - fifo = _FIFO(pack_factor) - self.submodules += fifo - self.phy = fifo.phy - self.busy = fifo.busy - - self.submodules.clocking = _Clocking(pads_vga, pads_dvi) - - if pads_vga is not None: - self.comb += [ - pads_vga.hsync_n.eq(~fifo.pix_hsync), - pads_vga.vsync_n.eq(~fifo.pix_vsync), - pads_vga.r.eq(fifo.pix_r), - pads_vga.g.eq(fifo.pix_g), - pads_vga.b.eq(fifo.pix_b), - pads_vga.psave_n.eq(1) - ] - if pads_dvi is not None: - self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi) - self.comb += [ - self.dvi_phy.hsync.eq(fifo.pix_hsync), - self.dvi_phy.vsync.eq(fifo.pix_vsync), - self.dvi_phy.de.eq(fifo.pix_de), - self.dvi_phy.r.eq(fifo.pix_r), - self.dvi_phy.g.eq(fifo.pix_g), - self.dvi_phy.b.eq(fifo.pix_b) - ] + def __init__(self, pack_factor, pads_vga, pads_dvi): + fifo = _FIFO(pack_factor) + self.submodules += fifo + self.phy = fifo.phy + self.busy = fifo.busy + + self.submodules.clocking = _Clocking(pads_vga, pads_dvi) + + if pads_vga is not None: + self.comb += [ + pads_vga.hsync_n.eq(~fifo.pix_hsync), + pads_vga.vsync_n.eq(~fifo.pix_vsync), + pads_vga.r.eq(fifo.pix_r), + pads_vga.g.eq(fifo.pix_g), + pads_vga.b.eq(fifo.pix_b), + pads_vga.psave_n.eq(1) + ] + if pads_dvi is not None: + self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi) + self.comb += [ + self.dvi_phy.hsync.eq(fifo.pix_hsync), + self.dvi_phy.vsync.eq(fifo.pix_vsync), + self.dvi_phy.de.eq(fifo.pix_de), + self.dvi_phy.r.eq(fifo.pix_r), + self.dvi_phy.g.eq(fifo.pix_g), + self.dvi_phy.b.eq(fifo.pix_b) + ] diff --git a/mkmscimg.py b/mkmscimg.py index 78e19119..dd78d4aa 100755 --- a/mkmscimg.py +++ b/mkmscimg.py @@ -4,9 +4,9 @@ import argparse import crc if __name__ == "__main__": - parser = argparse.ArgumentParser(description="CRC32 computation tool and MiSoC image file writer.") - parser.add_argument("input", help="input file") - parser.add_argument("-o", "--output", default=None, help="output file (if not specified, use input file)") - parser.add_argument("-f", "--fbi", default=False, action="store_true", help="build flash boot image (FBI) file") - args = parser.parse_args() - crc.insert_crc(args.input, args.fbi, args.output) + parser = argparse.ArgumentParser(description="CRC32 computation tool and MiSoC image file writer.") + parser.add_argument("input", help="input file") + parser.add_argument("-o", "--output", default=None, help="output file (if not specified, use input file)") + parser.add_argument("-f", "--fbi", default=False, action="store_true", help="build flash boot image (FBI) file") + args = parser.parse_args() + crc.insert_crc(args.input, args.fbi, args.output) diff --git a/setup.py b/setup.py index 24013e2b..fa49e6c7 100644 --- a/setup.py +++ b/setup.py @@ -9,29 +9,29 @@ README = open(os.path.join(here, "README")).read() required_version = (3, 3) if sys.version_info < required_version: - raise SystemExit("MiSoC requires python {0} or greater".format( - ".".join(map(str, required_version)))) + raise SystemExit("MiSoC requires python {0} or greater".format( + ".".join(map(str, required_version)))) setup( - name="misoclib", - version="unknown", - description="a high performance and small footprint SoC based on Migen", - long_description=README, - author="Sebastien Bourdeauducq", - author_email="sb@m-labs.hk", - url="http://m-labs.hk", - download_url="https://github.com/m-labs/misoc", - packages=find_packages(here), - license="BSD", - platforms=["Any"], - keywords="HDL ASIC FPGA hardware design", - classifiers=[ - "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", - "Environment :: Console", - "Development Status :: Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - ], + name="misoclib", + version="unknown", + description="a high performance and small footprint SoC based on Migen", + long_description=README, + author="Sebastien Bourdeauducq", + author_email="sb@m-labs.hk", + url="http://m-labs.hk", + download_url="https://github.com/m-labs/misoc", + packages=find_packages(here), + license="BSD", + platforms=["Any"], + keywords="HDL ASIC FPGA hardware design", + classifiers=[ + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Environment :: Console", + "Development Status :: Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + ], ) diff --git a/targets/de0nano.py b/targets/de0nano.py index 01850f5a..8a6802fc 100644 --- a/targets/de0nano.py +++ b/targets/de0nano.py @@ -6,90 +6,90 @@ from misoclib.mem.sdram.core.lasmicon import LASMIconSettings from misoclib.soc.sdram import SDRAMSoC class _PLL(Module): - def __init__(self, period_in, name, phase_shift, operation_mode): - self.clk_in = Signal() - self.clk_out = Signal() + def __init__(self, period_in, name, phase_shift, operation_mode): + self.clk_in = Signal() + self.clk_out = Signal() - self.specials += Instance("ALTPLL", - p_bandwidth_type = "AUTO", - p_clk0_divide_by = 1, - p_clk0_duty_cycle = 50, - p_clk0_multiply_by = 2, - p_clk0_phase_shift = "{}".format(str(phase_shift)), - p_compensate_clock = "CLK0", - p_inclk0_input_frequency = int(period_in*1000), - p_intended_device_family = "Cyclone IV E", - p_lpm_hint = "CBX_MODULE_PREFIX={}_pll".format(name), - p_lpm_type = "altpll", - p_operation_mode = operation_mode, - i_inclk=self.clk_in, - o_clk=self.clk_out, - i_areset=0, - i_clkena=0x3f, - i_clkswitch=0, - i_configupdate=0, - i_extclkena=0xf, - i_fbin=1, - i_pfdena=1, - i_phasecounterselect=0xf, - i_phasestep=1, - i_phaseupdown=1, - i_pllena=1, - i_scanaclr=0, - i_scanclk=0, - i_scanclkena=1, - i_scandata=0, - i_scanread=0, - i_scanwrite=0 - ) + self.specials += Instance("ALTPLL", + p_bandwidth_type = "AUTO", + p_clk0_divide_by = 1, + p_clk0_duty_cycle = 50, + p_clk0_multiply_by = 2, + p_clk0_phase_shift = "{}".format(str(phase_shift)), + p_compensate_clock = "CLK0", + p_inclk0_input_frequency = int(period_in*1000), + p_intended_device_family = "Cyclone IV E", + p_lpm_hint = "CBX_MODULE_PREFIX={}_pll".format(name), + p_lpm_type = "altpll", + p_operation_mode = operation_mode, + i_inclk=self.clk_in, + o_clk=self.clk_out, + i_areset=0, + i_clkena=0x3f, + i_clkswitch=0, + i_configupdate=0, + i_extclkena=0xf, + i_fbin=1, + i_pfdena=1, + i_phasecounterselect=0xf, + i_phasestep=1, + i_phaseupdown=1, + i_pllena=1, + i_scanaclr=0, + i_scanclk=0, + i_scanclkena=1, + i_scandata=0, + i_scanread=0, + i_scanwrite=0 + ) class _CRG(Module): - def __init__(self, platform): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys_ps = ClockDomain() - self.clock_domains.cd_por = ClockDomain(reset_less=True) + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys_ps = ClockDomain() + self.clock_domains.cd_por = ClockDomain(reset_less=True) - clk50 = platform.request("clk50") + clk50 = platform.request("clk50") - sys_pll = _PLL(20, "sys", 0, "NORMAL") - self.submodules += sys_pll - self.comb += [ - sys_pll.clk_in.eq(clk50), - self.cd_sys.clk.eq(sys_pll.clk_out) - ] + sys_pll = _PLL(20, "sys", 0, "NORMAL") + self.submodules += sys_pll + self.comb += [ + sys_pll.clk_in.eq(clk50), + self.cd_sys.clk.eq(sys_pll.clk_out) + ] - sdram_pll = _PLL(20, "sdram", -3000, "ZERO_DELAY_BUFFER") - self.submodules += sdram_pll - self.comb += [ - sdram_pll.clk_in.eq(clk50), - self.cd_sys_ps.clk.eq(sdram_pll.clk_out) - ] + sdram_pll = _PLL(20, "sdram", -3000, "ZERO_DELAY_BUFFER") + self.submodules += sdram_pll + self.comb += [ + sdram_pll.clk_in.eq(clk50), + self.cd_sys_ps.clk.eq(sdram_pll.clk_out) + ] - # Power on Reset (vendor agnostic) - rst_n = Signal() - self.sync.por += rst_n.eq(1) - self.comb += [ - self.cd_por.clk.eq(self.cd_sys.clk), - self.cd_sys.rst.eq(~rst_n), - self.cd_sys_ps.rst.eq(~rst_n) - ] + # Power on Reset (vendor agnostic) + rst_n = Signal() + self.sync.por += rst_n.eq(1) + self.comb += [ + self.cd_por.clk.eq(self.cd_sys.clk), + self.cd_sys.rst.eq(~rst_n), + self.cd_sys_ps.rst.eq(~rst_n) + ] - self.comb += platform.request("sdram_clock").eq(self.cd_sys_ps.clk) + self.comb += platform.request("sdram_clock").eq(self.cd_sys_ps.clk) class BaseSoC(SDRAMSoC): - default_platform = "de0nano" + default_platform = "de0nano" - def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): - SDRAMSoC.__init__(self, platform, - clk_freq=100*1000000, - integrated_rom_size=0x8000, - sdram_controller_settings=sdram_controller_settings, - **kwargs) + def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): + SDRAMSoC.__init__(self, platform, + clk_freq=100*1000000, + integrated_rom_size=0x8000, + sdram_controller_settings=sdram_controller_settings, + **kwargs) - self.submodules.crg = _CRG(platform) + self.submodules.crg = _CRG(platform) - if not self.integrated_main_ram_size: - self.submodules.sdrphy = gensdrphy.GENSDRPHY(platform.request("sdram"), IS42S16160(self.clk_freq)) - self.register_sdram_phy(self.sdrphy) + if not self.integrated_main_ram_size: + self.submodules.sdrphy = gensdrphy.GENSDRPHY(platform.request("sdram"), IS42S16160(self.clk_freq)) + self.register_sdram_phy(self.sdrphy) default_subtarget = BaseSoC diff --git a/targets/kc705.py b/targets/kc705.py index b45ec4c2..e5ceba10 100644 --- a/targets/kc705.py +++ b/targets/kc705.py @@ -12,115 +12,115 @@ from misoclib.com.liteeth.phy import LiteEthPHY from misoclib.com.liteeth.mac import LiteEthMAC class _CRG(Module): - def __init__(self, platform): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) - self.clock_domains.cd_clk200 = ClockDomain() - - clk200 = platform.request("clk200") - clk200_se = Signal() - self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se) - - rst = platform.request("cpu_reset") - - pll_locked = Signal() - pll_fb = Signal() - self.pll_sys = Signal() - pll_sys4x = Signal() - pll_clk200 = Signal() - self.specials += [ - Instance("PLLE2_BASE", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - # VCO @ 1GHz - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0, - p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1, - i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, - - # 125MHz - p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=self.pll_sys, - - # 500MHz - p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_sys4x, - - # 200MHz - p_CLKOUT2_DIVIDE=5, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_clk200, - - p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=, - - p_CLKOUT4_DIVIDE=4, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4= - ), - Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), - Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), - Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), - AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), - AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | rst), - ] - - reset_counter = Signal(4, reset=15) - ic_reset = Signal(reset=1) - self.sync.clk200 += \ - If(reset_counter != 0, - reset_counter.eq(reset_counter - 1) - ).Else( - ic_reset.eq(0) - ) - self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) + self.clock_domains.cd_clk200 = ClockDomain() + + clk200 = platform.request("clk200") + clk200_se = Signal() + self.specials += Instance("IBUFDS", i_I=clk200.p, i_IB=clk200.n, o_O=clk200_se) + + rst = platform.request("cpu_reset") + + pll_locked = Signal() + pll_fb = Signal() + self.pll_sys = Signal() + pll_sys4x = Signal() + pll_clk200 = Signal() + self.specials += [ + Instance("PLLE2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + # VCO @ 1GHz + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0, + p_CLKFBOUT_MULT=5, p_DIVCLK_DIVIDE=1, + i_CLKIN1=clk200_se, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + + # 125MHz + p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=self.pll_sys, + + # 500MHz + p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_sys4x, + + # 200MHz + p_CLKOUT2_DIVIDE=5, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_clk200, + + p_CLKOUT3_DIVIDE=2, p_CLKOUT3_PHASE=0.0, #o_CLKOUT3=, + + p_CLKOUT4_DIVIDE=4, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4= + ), + Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), + Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), + Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), + AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | rst), + ] + + reset_counter = Signal(4, reset=15) + ic_reset = Signal(reset=1) + self.sync.clk200 += \ + If(reset_counter != 0, + reset_counter.eq(reset_counter - 1) + ).Else( + ic_reset.eq(0) + ) + self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) class BaseSoC(SDRAMSoC): - default_platform = "kc705" - - csr_map = { - "spiflash": 16, - "ddrphy": 17, - } - csr_map.update(SDRAMSoC.csr_map) - - def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): - SDRAMSoC.__init__(self, platform, - clk_freq=125*1000000, cpu_reset_address=0xaf0000, - sdram_controller_settings=sdram_controller_settings, - **kwargs) - - self.submodules.crg = _CRG(platform) - - if not self.integrated_main_ram_size: - self.submodules.ddrphy = k7ddrphy.K7DDRPHY(platform.request("ddram"), MT8JTF12864(self.clk_freq)) - self.register_sdram_phy(self.ddrphy) - - if not self.integrated_rom_size: - spiflash_pads = platform.request("spiflash") - spiflash_pads.clk = Signal() - self.specials += Instance("STARTUPE2", - i_CLK=0, i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=0, - i_USRCCLKO=spiflash_pads.clk, i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1) - self.submodules.spiflash = spiflash.SpiFlash(spiflash_pads, dummy=11, div=2) - self.flash_boot_address = 0xb00000 - self.register_rom(self.spiflash.bus) + default_platform = "kc705" + + csr_map = { + "spiflash": 16, + "ddrphy": 17, + } + csr_map.update(SDRAMSoC.csr_map) + + def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): + SDRAMSoC.__init__(self, platform, + clk_freq=125*1000000, cpu_reset_address=0xaf0000, + sdram_controller_settings=sdram_controller_settings, + **kwargs) + + self.submodules.crg = _CRG(platform) + + if not self.integrated_main_ram_size: + self.submodules.ddrphy = k7ddrphy.K7DDRPHY(platform.request("ddram"), MT8JTF12864(self.clk_freq)) + self.register_sdram_phy(self.ddrphy) + + if not self.integrated_rom_size: + spiflash_pads = platform.request("spiflash") + spiflash_pads.clk = Signal() + self.specials += Instance("STARTUPE2", + i_CLK=0, i_GSR=0, i_GTS=0, i_KEYCLEARB=0, i_PACK=0, + i_USRCCLKO=spiflash_pads.clk, i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1) + self.submodules.spiflash = spiflash.SpiFlash(spiflash_pads, dummy=11, div=2) + self.flash_boot_address = 0xb00000 + self.register_rom(self.spiflash.bus) class MiniSoC(BaseSoC): - csr_map = { - "ethphy": 18, - "ethmac": 19, - } - csr_map.update(BaseSoC.csr_map) - - interrupt_map = { - "ethmac": 2, - } - interrupt_map.update(BaseSoC.interrupt_map) - - mem_map = { - "ethmac": 0x30000000, # (shadow @0xb0000000) - } - mem_map.update(BaseSoC.mem_map) - - def __init__(self, platform, **kwargs): - BaseSoC.__init__(self, platform, **kwargs) - - self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth")) - self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone") - self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) - self.add_memory_region("ethmac", self.mem_map["ethmac"]+0x80000000, 0x2000) + csr_map = { + "ethphy": 18, + "ethmac": 19, + } + csr_map.update(BaseSoC.csr_map) + + interrupt_map = { + "ethmac": 2, + } + interrupt_map.update(BaseSoC.interrupt_map) + + mem_map = { + "ethmac": 0x30000000, # (shadow @0xb0000000) + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, platform, **kwargs): + BaseSoC.__init__(self, platform, **kwargs) + + self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth")) + self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone") + self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) + self.add_memory_region("ethmac", self.mem_map["ethmac"]+0x80000000, 0x2000) default_subtarget = BaseSoC diff --git a/targets/minispartan6.py b/targets/minispartan6.py index 1da8bbfc..dd0a287a 100644 --- a/targets/minispartan6.py +++ b/targets/minispartan6.py @@ -9,69 +9,69 @@ from misoclib.mem.sdram.core.lasmicon import LASMIconSettings from misoclib.soc.sdram import SDRAMSoC class _CRG(Module): - def __init__(self, platform, clk_freq): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys_ps = ClockDomain() + def __init__(self, platform, clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys_ps = ClockDomain() - f0 = 32*1000000 - clk32 = platform.request("clk32") - clk32a = Signal() - self.specials += Instance("IBUFG", i_I=clk32, o_O=clk32a) - clk32b = Signal() - self.specials += Instance("BUFIO2", p_DIVIDE=1, - p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", - i_I=clk32a, o_DIVCLK=clk32b) - f = Fraction(int(clk_freq), int(f0)) - n, m, p = f.denominator, f.numerator, 8 - assert f0/n*m == clk_freq - pll_lckd = Signal() - pll_fb = Signal() - pll = Signal(6) - self.specials.pll = Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", - p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", - p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", - i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, - p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., - i_CLKIN1=clk32b, i_CLKIN2=0, i_CLKINSEL=1, - p_CLKIN1_PERIOD=1000000000/f0, p_CLKIN2_PERIOD=0., - i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, - o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, - o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, - o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, - o_CLKOUT3=pll[3], p_CLKOUT3_DUTY_CYCLE=.5, - o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5, - o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5, - p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//1, - p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//1, - p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=p//1, - p_CLKOUT3_PHASE=0., p_CLKOUT3_DIVIDE=p//1, - p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//1, # sys - p_CLKOUT5_PHASE=270., p_CLKOUT5_DIVIDE=p//1, # sys_ps - ) - self.specials += Instance("BUFG", i_I=pll[4], o_O=self.cd_sys.clk) - self.specials += Instance("BUFG", i_I=pll[5], o_O=self.cd_sys_ps.clk) - self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd) + f0 = 32*1000000 + clk32 = platform.request("clk32") + clk32a = Signal() + self.specials += Instance("IBUFG", i_I=clk32, o_O=clk32a) + clk32b = Signal() + self.specials += Instance("BUFIO2", p_DIVIDE=1, + p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", + i_I=clk32a, o_DIVCLK=clk32b) + f = Fraction(int(clk_freq), int(f0)) + n, m, p = f.denominator, f.numerator, 8 + assert f0/n*m == clk_freq + pll_lckd = Signal() + pll_fb = Signal() + pll = Signal(6) + self.specials.pll = Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", + p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., + i_CLKIN1=clk32b, i_CLKIN2=0, i_CLKINSEL=1, + p_CLKIN1_PERIOD=1000000000/f0, p_CLKIN2_PERIOD=0., + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, + o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, + o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, + o_CLKOUT3=pll[3], p_CLKOUT3_DUTY_CYCLE=.5, + o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5, + o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//1, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//1, + p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=p//1, + p_CLKOUT3_PHASE=0., p_CLKOUT3_DIVIDE=p//1, + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//1, # sys + p_CLKOUT5_PHASE=270., p_CLKOUT5_DIVIDE=p//1, # sys_ps + ) + self.specials += Instance("BUFG", i_I=pll[4], o_O=self.cd_sys.clk) + self.specials += Instance("BUFG", i_I=pll[5], o_O=self.cd_sys_ps.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd) - self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", - p_INIT=0, p_SRTYPE="SYNC", - i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, - i_C0=self.cd_sys.clk, i_C1=~self.cd_sys.clk, - o_Q=platform.request("sdram_clock")) + self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, + i_C0=self.cd_sys.clk, i_C1=~self.cd_sys.clk, + o_Q=platform.request("sdram_clock")) class BaseSoC(SDRAMSoC): - default_platform = "minispartan6" + default_platform = "minispartan6" - def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): - clk_freq = 80*1000000 - SDRAMSoC.__init__(self, platform, clk_freq, - integrated_rom_size=0x8000, - sdram_controller_settings=sdram_controller_settings, - **kwargs) + def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): + clk_freq = 80*1000000 + SDRAMSoC.__init__(self, platform, clk_freq, + integrated_rom_size=0x8000, + sdram_controller_settings=sdram_controller_settings, + **kwargs) - self.submodules.crg = _CRG(platform, clk_freq) + self.submodules.crg = _CRG(platform, clk_freq) - if not self.integrated_main_ram_size: - self.submodules.sdrphy = gensdrphy.GENSDRPHY(platform.request("sdram"), AS4C16M16(clk_freq)) - self.register_sdram_phy(self.sdrphy) + if not self.integrated_main_ram_size: + self.submodules.sdrphy = gensdrphy.GENSDRPHY(platform.request("sdram"), AS4C16M16(clk_freq)) + self.register_sdram_phy(self.sdrphy) default_subtarget = BaseSoC diff --git a/targets/mlabs_video.py b/targets/mlabs_video.py index f8946069..30af6423 100644 --- a/targets/mlabs_video.py +++ b/targets/mlabs_video.py @@ -18,100 +18,100 @@ from misoclib.com.liteeth.phy import LiteEthPHY from misoclib.com.liteeth.mac import LiteEthMAC class _MXClockPads: - def __init__(self, platform): - self.clk50 = platform.request("clk50") - self.trigger_reset = 0 - try: - self.trigger_reset = platform.request("user_btn", 1) - except ConstraintError: - pass - self.norflash_rst_n = platform.request("norflash_rst_n") - ddram_clock = platform.request("ddram_clock") - self.ddr_clk_p = ddram_clock.p - self.ddr_clk_n = ddram_clock.n + def __init__(self, platform): + self.clk50 = platform.request("clk50") + self.trigger_reset = 0 + try: + self.trigger_reset = platform.request("user_btn", 1) + except ConstraintError: + pass + self.norflash_rst_n = platform.request("norflash_rst_n") + ddram_clock = platform.request("ddram_clock") + self.ddr_clk_p = ddram_clock.p + self.ddr_clk_n = ddram_clock.n class BaseSoC(SDRAMSoC): - default_platform = "mixxeo" # also supports m1 - - def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): - SDRAMSoC.__init__(self, platform, - clk_freq=(83 + Fraction(1, 3))*1000000, - cpu_reset_address=0x00180000, - sdram_controller_settings=sdram_controller_settings, - **kwargs) - - self.submodules.crg = mxcrg.MXCRG(_MXClockPads(platform), self.clk_freq) - - if not self.integrated_main_ram_size: - self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), MT46V32M16(self.clk_freq), - rd_bitslip=0, wr_bitslip=3, dqs_ddr_alignment="C1") - self.register_sdram_phy(self.ddrphy) - self.comb += [ - self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), - self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb) - ] - - if not self.integrated_rom_size: - clk_period_ns = 1000000000/self.clk_freq - self.submodules.norflash = norflash16.NorFlash16(platform.request("norflash"), - ceil(110/clk_period_ns), ceil(50/clk_period_ns)) - self.flash_boot_address = 0x001a0000 - self.register_rom(self.norflash.bus) - - platform.add_platform_command(""" + default_platform = "mixxeo" # also supports m1 + + def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): + SDRAMSoC.__init__(self, platform, + clk_freq=(83 + Fraction(1, 3))*1000000, + cpu_reset_address=0x00180000, + sdram_controller_settings=sdram_controller_settings, + **kwargs) + + self.submodules.crg = mxcrg.MXCRG(_MXClockPads(platform), self.clk_freq) + + if not self.integrated_main_ram_size: + self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), MT46V32M16(self.clk_freq), + rd_bitslip=0, wr_bitslip=3, dqs_ddr_alignment="C1") + self.register_sdram_phy(self.ddrphy) + self.comb += [ + self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), + self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb) + ] + + if not self.integrated_rom_size: + clk_period_ns = 1000000000/self.clk_freq + self.submodules.norflash = norflash16.NorFlash16(platform.request("norflash"), + ceil(110/clk_period_ns), ceil(50/clk_period_ns)) + self.flash_boot_address = 0x001a0000 + self.register_rom(self.norflash.bus) + + platform.add_platform_command(""" INST "mxcrg/wr_bufpll" LOC = "BUFPLL_X0Y2"; INST "mxcrg/rd_bufpll" LOC = "BUFPLL_X0Y3"; """) - platform.add_source_dir(os.path.join("misoclib", "others", "mxcrg")) + platform.add_source_dir(os.path.join("misoclib", "others", "mxcrg")) class MiniSoC(BaseSoC): - csr_map = { - "ethphy": 16, - "ethmac": 17, - } - csr_map.update(BaseSoC.csr_map) - - interrupt_map = { - "ethmac": 2, - } - interrupt_map.update(BaseSoC.interrupt_map) - - mem_map = { - "ethmac": 0x30000000, # (shadow @0xb0000000) - } - mem_map.update(BaseSoC.mem_map) - - def __init__(self, platform, **kwargs): - BaseSoC.__init__(self, platform, **kwargs) - - if platform.name == "mixxeo": - self.submodules.leds = gpio.GPIOOut(platform.request("user_led")) - if platform.name == "m1": - self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) - self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", i) for i in range(2))) - - self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth")) - self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone") - self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) - self.add_memory_region("ethmac", self.mem_map["ethmac"]+0x80000000, 0x2000) + csr_map = { + "ethphy": 16, + "ethmac": 17, + } + csr_map.update(BaseSoC.csr_map) + + interrupt_map = { + "ethmac": 2, + } + interrupt_map.update(BaseSoC.interrupt_map) + + mem_map = { + "ethmac": 0x30000000, # (shadow @0xb0000000) + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, platform, **kwargs): + BaseSoC.__init__(self, platform, **kwargs) + + if platform.name == "mixxeo": + self.submodules.leds = gpio.GPIOOut(platform.request("user_led")) + if platform.name == "m1": + self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) + self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", i) for i in range(2))) + + self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth")) + self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone") + self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) + self.add_memory_region("ethmac", self.mem_map["ethmac"]+0x80000000, 0x2000) def get_vga_dvi(platform): - try: - pads_vga = platform.request("vga_out") - except ConstraintError: - pads_vga = None - try: - pads_dvi = platform.request("dvi_out") - except ConstraintError: - pads_dvi = None - else: - platform.add_platform_command(""" + try: + pads_vga = platform.request("vga_out") + except ConstraintError: + pads_vga = None + try: + pads_dvi = platform.request("dvi_out") + except ConstraintError: + pads_dvi = None + else: + platform.add_platform_command(""" PIN "dviout_pix_bufg.O" CLOCK_DEDICATED_ROUTE = FALSE; """) - return pads_vga, pads_dvi + return pads_vga, pads_dvi def add_vga_tig(platform, fb): - platform.add_platform_command(""" + platform.add_platform_command(""" NET "{vga_clk}" TNM_NET = "GRPvga_clk"; NET "sys_clk" TNM_NET = "GRPsys_clk"; TIMESPEC "TSise_sucks1" = FROM "GRPvga_clk" TO "GRPsys_clk" TIG; @@ -119,15 +119,15 @@ TIMESPEC "TSise_sucks2" = FROM "GRPsys_clk" TO "GRPvga_clk" TIG; """, vga_clk=fb.driver.clocking.cd_pix.clk) class FramebufferSoC(MiniSoC): - csr_map = { - "fb": 18, - } - csr_map.update(MiniSoC.csr_map) - - def __init__(self, platform, **kwargs): - MiniSoC.__init__(self, platform, **kwargs) - pads_vga, pads_dvi = get_vga_dvi(platform) - self.submodules.fb = framebuffer.Framebuffer(pads_vga, pads_dvi, self.sdram.crossbar.get_master()) - add_vga_tig(platform, self.fb) + csr_map = { + "fb": 18, + } + csr_map.update(MiniSoC.csr_map) + + def __init__(self, platform, **kwargs): + MiniSoC.__init__(self, platform, **kwargs) + pads_vga, pads_dvi = get_vga_dvi(platform) + self.submodules.fb = framebuffer.Framebuffer(pads_vga, pads_dvi, self.sdram.crossbar.get_master()) + add_vga_tig(platform, self.fb) default_subtarget = FramebufferSoC diff --git a/targets/pipistrello.py b/targets/pipistrello.py index 94cb2291..a5a4d63f 100644 --- a/targets/pipistrello.py +++ b/targets/pipistrello.py @@ -10,111 +10,111 @@ from misoclib.mem.flash import spiflash from misoclib.soc.sdram import SDRAMSoC class _CRG(Module): - def __init__(self, platform, clk_freq): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sdram_half = ClockDomain() - self.clock_domains.cd_sdram_full_wr = ClockDomain() - self.clock_domains.cd_sdram_full_rd = ClockDomain() + def __init__(self, platform, clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sdram_half = ClockDomain() + self.clock_domains.cd_sdram_full_wr = ClockDomain() + self.clock_domains.cd_sdram_full_rd = ClockDomain() - self.clk4x_wr_strb = Signal() - self.clk4x_rd_strb = Signal() + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() - f0 = 50*1000000 - clk50 = platform.request("clk50") - clk50a = Signal() - self.specials += Instance("IBUFG", i_I=clk50, o_O=clk50a) - clk50b = Signal() - self.specials += Instance("BUFIO2", p_DIVIDE=1, - p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", - i_I=clk50a, o_DIVCLK=clk50b) - f = Fraction(int(clk_freq), int(f0)) - n, m = f.denominator, f.numerator - assert f0/n*m == clk_freq - p = 8 - pll_lckd = Signal() - pll_fb = Signal() - pll = Signal(6) - self.specials.pll = Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", - p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", - p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", - i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, - p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., - i_CLKIN1=clk50b, i_CLKIN2=0, i_CLKINSEL=1, - p_CLKIN1_PERIOD=1000000000/f0, p_CLKIN2_PERIOD=0., - i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, - o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, - o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, - o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, - o_CLKOUT3=pll[3], p_CLKOUT3_DUTY_CYCLE=.5, - o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5, - o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5, - p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//4, # sdram wr rd - p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//8, - p_CLKOUT2_PHASE=270., p_CLKOUT2_DIVIDE=p//2, # sdram dqs adr ctrl - p_CLKOUT3_PHASE=250., p_CLKOUT3_DIVIDE=p//2, # off-chip ddr - p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//1, - p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=p//1, # sys - ) - self.specials += Instance("BUFG", i_I=pll[5], o_O=self.cd_sys.clk) - reset = platform.request("user_btn") - self.clock_domains.cd_por = ClockDomain() - por = Signal(max=1 << 11, reset=(1 << 11) - 1) - self.sync.por += If(por != 0, por.eq(por - 1)) - self.comb += self.cd_por.clk.eq(self.cd_sys.clk) - self.specials += AsyncResetSynchronizer(self.cd_por, reset) - self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0)) - self.specials += Instance("BUFG", i_I=pll[2], o_O=self.cd_sdram_half.clk) - self.specials += Instance("BUFPLL", p_DIVIDE=4, - i_PLLIN=pll[0], i_GCLK=self.cd_sys.clk, - i_LOCKED=pll_lckd, o_IOCLK=self.cd_sdram_full_wr.clk, - o_SERDESSTROBE=self.clk4x_wr_strb) - self.comb += [ - self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk), - self.clk4x_rd_strb.eq(self.clk4x_wr_strb), - ] - clk_sdram_half_shifted = Signal() - self.specials += Instance("BUFG", i_I=pll[3], o_O=clk_sdram_half_shifted) - clk = platform.request("ddram_clock") - self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", - p_INIT=0, p_SRTYPE="SYNC", - i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1, - i_C0=clk_sdram_half_shifted, i_C1=~clk_sdram_half_shifted, - o_Q=clk.p) - self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", - p_INIT=0, p_SRTYPE="SYNC", - i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, - i_C0=clk_sdram_half_shifted, i_C1=~clk_sdram_half_shifted, - o_Q=clk.n) + f0 = 50*1000000 + clk50 = platform.request("clk50") + clk50a = Signal() + self.specials += Instance("IBUFG", i_I=clk50, o_O=clk50a) + clk50b = Signal() + self.specials += Instance("BUFIO2", p_DIVIDE=1, + p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", + i_I=clk50a, o_DIVCLK=clk50b) + f = Fraction(int(clk_freq), int(f0)) + n, m = f.denominator, f.numerator + assert f0/n*m == clk_freq + p = 8 + pll_lckd = Signal() + pll_fb = Signal() + pll = Signal(6) + self.specials.pll = Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", + p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., + i_CLKIN1=clk50b, i_CLKIN2=0, i_CLKINSEL=1, + p_CLKIN1_PERIOD=1000000000/f0, p_CLKIN2_PERIOD=0., + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, + o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, + o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, + o_CLKOUT3=pll[3], p_CLKOUT3_DUTY_CYCLE=.5, + o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5, + o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//4, # sdram wr rd + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//8, + p_CLKOUT2_PHASE=270., p_CLKOUT2_DIVIDE=p//2, # sdram dqs adr ctrl + p_CLKOUT3_PHASE=250., p_CLKOUT3_DIVIDE=p//2, # off-chip ddr + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//1, + p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=p//1, # sys + ) + self.specials += Instance("BUFG", i_I=pll[5], o_O=self.cd_sys.clk) + reset = platform.request("user_btn") + self.clock_domains.cd_por = ClockDomain() + por = Signal(max=1 << 11, reset=(1 << 11) - 1) + self.sync.por += If(por != 0, por.eq(por - 1)) + self.comb += self.cd_por.clk.eq(self.cd_sys.clk) + self.specials += AsyncResetSynchronizer(self.cd_por, reset) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0)) + self.specials += Instance("BUFG", i_I=pll[2], o_O=self.cd_sdram_half.clk) + self.specials += Instance("BUFPLL", p_DIVIDE=4, + i_PLLIN=pll[0], i_GCLK=self.cd_sys.clk, + i_LOCKED=pll_lckd, o_IOCLK=self.cd_sdram_full_wr.clk, + o_SERDESSTROBE=self.clk4x_wr_strb) + self.comb += [ + self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk), + self.clk4x_rd_strb.eq(self.clk4x_wr_strb), + ] + clk_sdram_half_shifted = Signal() + self.specials += Instance("BUFG", i_I=pll[3], o_O=clk_sdram_half_shifted) + clk = platform.request("ddram_clock") + self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, i_C1=~clk_sdram_half_shifted, + o_Q=clk.p) + self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, i_C1=~clk_sdram_half_shifted, + o_Q=clk.n) class BaseSoC(SDRAMSoC): - default_platform = "pipistrello" + default_platform = "pipistrello" - csr_map = { - "spiflash": 16, - } - csr_map.update(SDRAMSoC.csr_map) + csr_map = { + "spiflash": 16, + } + csr_map.update(SDRAMSoC.csr_map) - def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): - clk_freq = 75*1000000 - SDRAMSoC.__init__(self, platform, clk_freq, - cpu_reset_address=0x170000, # 1.5 MB - sdram_controller_settings=sdram_controller_settings, - **kwargs) + def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): + clk_freq = 75*1000000 + SDRAMSoC.__init__(self, platform, clk_freq, + cpu_reset_address=0x170000, # 1.5 MB + sdram_controller_settings=sdram_controller_settings, + **kwargs) - self.submodules.crg = _CRG(platform, clk_freq) + self.submodules.crg = _CRG(platform, clk_freq) - if not self.integrated_main_ram_size: - self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), MT46H32M16(self.clk_freq), - rd_bitslip=1, wr_bitslip=3, dqs_ddr_alignment="C1") - self.comb += [ - self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), - self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb), - ] - self.register_sdram_phy(self.ddrphy) + if not self.integrated_main_ram_size: + self.submodules.ddrphy = s6ddrphy.S6DDRPHY(platform.request("ddram"), MT46H32M16(self.clk_freq), + rd_bitslip=1, wr_bitslip=3, dqs_ddr_alignment="C1") + self.comb += [ + self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), + self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb), + ] + self.register_sdram_phy(self.ddrphy) - if not self.integrated_rom_size: - self.submodules.spiflash = spiflash.SpiFlash(platform.request("spiflash4x"), dummy=10, div=4) - self.flash_boot_address = 0x180000 - self.register_rom(self.spiflash.bus, 0x1000000) + if not self.integrated_rom_size: + self.submodules.spiflash = spiflash.SpiFlash(platform.request("spiflash4x"), dummy=10, div=4) + self.flash_boot_address = 0x180000 + self.register_rom(self.spiflash.bus, 0x1000000) default_subtarget = BaseSoC diff --git a/targets/ppro.py b/targets/ppro.py index ce6c10a8..d93341c2 100644 --- a/targets/ppro.py +++ b/targets/ppro.py @@ -10,79 +10,79 @@ from misoclib.mem.flash import spiflash from misoclib.soc.sdram import SDRAMSoC class _CRG(Module): - def __init__(self, platform, clk_freq): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys_ps = ClockDomain() + def __init__(self, platform, clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys_ps = ClockDomain() - f0 = 32*1000000 - clk32 = platform.request("clk32") - clk32a = Signal() - self.specials += Instance("IBUFG", i_I=clk32, o_O=clk32a) - clk32b = Signal() - self.specials += Instance("BUFIO2", p_DIVIDE=1, - p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", - i_I=clk32a, o_DIVCLK=clk32b) - f = Fraction(int(clk_freq), int(f0)) - n, m, p = f.denominator, f.numerator, 8 - assert f0/n*m == clk_freq - pll_lckd = Signal() - pll_fb = Signal() - pll = Signal(6) - self.specials.pll = Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", - p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", - p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", - i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, - p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., - i_CLKIN1=clk32b, i_CLKIN2=0, i_CLKINSEL=1, - p_CLKIN1_PERIOD=1000000000/f0, p_CLKIN2_PERIOD=0., - i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, - o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, - o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, - o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, - o_CLKOUT3=pll[3], p_CLKOUT3_DUTY_CYCLE=.5, - o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5, - o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5, - p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//1, - p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//1, - p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=p//1, - p_CLKOUT3_PHASE=0., p_CLKOUT3_DIVIDE=p//1, - p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//1, # sys - p_CLKOUT5_PHASE=270., p_CLKOUT5_DIVIDE=p//1, # sys_ps - ) - self.specials += Instance("BUFG", i_I=pll[4], o_O=self.cd_sys.clk) - self.specials += Instance("BUFG", i_I=pll[5], o_O=self.cd_sys_ps.clk) - self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd) + f0 = 32*1000000 + clk32 = platform.request("clk32") + clk32a = Signal() + self.specials += Instance("IBUFG", i_I=clk32, o_O=clk32a) + clk32b = Signal() + self.specials += Instance("BUFIO2", p_DIVIDE=1, + p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE", + i_I=clk32a, o_DIVCLK=clk32b) + f = Fraction(int(clk_freq), int(f0)) + n, m, p = f.denominator, f.numerator, 8 + assert f0/n*m == clk_freq + pll_lckd = Signal() + pll_fb = Signal() + pll = Signal(6) + self.specials.pll = Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", + p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., + i_CLKIN1=clk32b, i_CLKIN2=0, i_CLKINSEL=1, + p_CLKIN1_PERIOD=1000000000/f0, p_CLKIN2_PERIOD=0., + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, + o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, + o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, + o_CLKOUT3=pll[3], p_CLKOUT3_DUTY_CYCLE=.5, + o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5, + o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//1, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//1, + p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=p//1, + p_CLKOUT3_PHASE=0., p_CLKOUT3_DIVIDE=p//1, + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//1, # sys + p_CLKOUT5_PHASE=270., p_CLKOUT5_DIVIDE=p//1, # sys_ps + ) + self.specials += Instance("BUFG", i_I=pll[4], o_O=self.cd_sys.clk) + self.specials += Instance("BUFG", i_I=pll[5], o_O=self.cd_sys_ps.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd) - self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", - p_INIT=0, p_SRTYPE="SYNC", - i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, - i_C0=self.cd_sys.clk, i_C1=~self.cd_sys.clk, - o_Q=platform.request("sdram_clock")) + self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1, + i_C0=self.cd_sys.clk, i_C1=~self.cd_sys.clk, + o_Q=platform.request("sdram_clock")) class BaseSoC(SDRAMSoC): - default_platform = "papilio_pro" + default_platform = "papilio_pro" - csr_map = { - "spiflash": 16, - } - csr_map.update(SDRAMSoC.csr_map) + csr_map = { + "spiflash": 16, + } + csr_map.update(SDRAMSoC.csr_map) - def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): - clk_freq = 80*1000000 - SDRAMSoC.__init__(self, platform, clk_freq, - cpu_reset_address=0x60000, - sdram_controller_settings=sdram_controller_settings, - **kwargs) + def __init__(self, platform, sdram_controller_settings=LASMIconSettings(), **kwargs): + clk_freq = 80*1000000 + SDRAMSoC.__init__(self, platform, clk_freq, + cpu_reset_address=0x60000, + sdram_controller_settings=sdram_controller_settings, + **kwargs) - self.submodules.crg = _CRG(platform, clk_freq) + self.submodules.crg = _CRG(platform, clk_freq) - if not self.integrated_main_ram_size: - self.submodules.sdrphy = gensdrphy.GENSDRPHY(platform.request("sdram"), MT48LC4M16(clk_freq)) - self.register_sdram_phy(self.sdrphy) + if not self.integrated_main_ram_size: + self.submodules.sdrphy = gensdrphy.GENSDRPHY(platform.request("sdram"), MT48LC4M16(clk_freq)) + self.register_sdram_phy(self.sdrphy) - if not self.integrated_rom_size: - self.submodules.spiflash = spiflash.SpiFlash(platform.request("spiflash2x"), dummy=4, div=6) - self.flash_boot_address = 0x70000 - self.register_rom(self.spiflash.bus) + if not self.integrated_rom_size: + self.submodules.spiflash = spiflash.SpiFlash(platform.request("spiflash2x"), dummy=4, div=6) + self.flash_boot_address = 0x70000 + self.register_rom(self.spiflash.bus) default_subtarget = BaseSoC diff --git a/targets/simple.py b/targets/simple.py index 60b2d52e..56313901 100644 --- a/targets/simple.py +++ b/targets/simple.py @@ -7,37 +7,37 @@ from misoclib.com.liteeth.phy import LiteEthPHY from misoclib.com.liteeth.mac import LiteEthMAC class BaseSoC(SoC): - def __init__(self, platform, **kwargs): - SoC.__init__(self, platform, - clk_freq=int((1/(platform.default_clk_period))*1000000000), - integrated_rom_size=0x8000, - integrated_main_ram_size=16*1024, - **kwargs) - self.submodules.crg = CRG(platform.request(platform.default_clk_name)) + def __init__(self, platform, **kwargs): + SoC.__init__(self, platform, + clk_freq=int((1/(platform.default_clk_period))*1000000000), + integrated_rom_size=0x8000, + integrated_main_ram_size=16*1024, + **kwargs) + self.submodules.crg = CRG(platform.request(platform.default_clk_name)) class MiniSoC(BaseSoC): - csr_map = { - "ethphy": 20, - "ethmac": 21 - } - csr_map.update(BaseSoC.csr_map) - - interrupt_map = { - "ethmac": 2, - } - interrupt_map.update(BaseSoC.interrupt_map) - - mem_map = { - "ethmac": 0x30000000, # (shadow @0xb0000000) - } - mem_map.update(BaseSoC.mem_map) - - def __init__(self, platform, **kwargs): - BaseSoC.__init__(self, platform, **kwargs) - - self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth")) - self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone", with_hw_preamble_crc=False) - self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) - self.add_memory_region("ethmac", self.mem_map["ethmac"]+0x80000000, 0x2000) + csr_map = { + "ethphy": 20, + "ethmac": 21 + } + csr_map.update(BaseSoC.csr_map) + + interrupt_map = { + "ethmac": 2, + } + interrupt_map.update(BaseSoC.interrupt_map) + + mem_map = { + "ethmac": 0x30000000, # (shadow @0xb0000000) + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, platform, **kwargs): + BaseSoC.__init__(self, platform, **kwargs) + + self.submodules.ethphy = LiteEthPHY(platform.request("eth_clocks"), platform.request("eth")) + self.submodules.ethmac = LiteEthMAC(phy=self.ethphy, dw=32, interface="wishbone", with_hw_preamble_crc=False) + self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus) + self.add_memory_region("ethmac", self.mem_map["ethmac"]+0x80000000, 0x2000) default_subtarget = BaseSoC diff --git a/targets/versa.py b/targets/versa.py index 6bce5f0a..55cfb286 100644 --- a/targets/versa.py +++ b/targets/versa.py @@ -5,13 +5,13 @@ from migen.genlib.io import CRG from misoclib.soc import SoC class BaseSoC(SoC): - default_platform = "versa" - def __init__(self, platform, **kwargs): - SoC.__init__(self, platform, - clk_freq=100*1000000, - integrated_rom_size=0x8000, - **kwargs) - self.submodules.crg = CRG(platform.request("clk100"), ~platform.request("rst_n")) - self.comb += platform.request("user_led", 0).eq(ResetSignal()) + default_platform = "versa" + def __init__(self, platform, **kwargs): + SoC.__init__(self, platform, + clk_freq=100*1000000, + integrated_rom_size=0x8000, + **kwargs) + self.submodules.crg = CRG(platform.request("clk100"), ~platform.request("rst_n")) + self.comb += platform.request("user_led", 0).eq(ResetSignal()) default_subtarget = BaseSoC diff --git a/tools/flterm.py b/tools/flterm.py index ea4045aa..ea87cf9c 100644 --- a/tools/flterm.py +++ b/tools/flterm.py @@ -20,269 +20,269 @@ sfl_ack_error = 'E' # XXX : can we get CRC16 from a standard Python library as it's done # for CRC32 with binascii? crc16_table = [ - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 ] def crc16(l): - crc = 0 - for d in l: - crc = crc16_table[((crc >> 8) ^ d) & 0xff] ^ (crc << 8) - return crc + crc = 0 + for d in l: + crc = crc16_table[((crc >> 8) ^ d) & 0xff] ^ (crc << 8) + return crc class SFLFrame: - def __init__(self): - self.length = None - self.cmd = None - self.payload = [] - self.crc = None - self.raw = [] - - def compute_crc(self): - crc_data = [] - crc_data.append(self.cmd) - for d in self.payload: - crc_data.append(d) - self.crc = crc16(crc_data) - return self.crc - - def encode(self): - self.raw = [] - self.raw.append(self.length) - self.compute_crc() - self.raw.append((self.crc & 0xff00) >> 8) - self.raw.append(self.crc & 0x00ff) - self.raw.append(self.cmd) - for d in self.payload: - self.raw.append(d) + def __init__(self): + self.length = None + self.cmd = None + self.payload = [] + self.crc = None + self.raw = [] + + def compute_crc(self): + crc_data = [] + crc_data.append(self.cmd) + for d in self.payload: + crc_data.append(d) + self.crc = crc16(crc_data) + return self.crc + + def encode(self): + self.raw = [] + self.raw.append(self.length) + self.compute_crc() + self.raw.append((self.crc & 0xff00) >> 8) + self.raw.append(self.crc & 0x00ff) + self.raw.append(self.cmd) + for d in self.payload: + self.raw.append(d) def get_file_data(filename): - with open(filename, "rb") as f: - data = [] - while True: - w = f.read(1) - if not w: - break - data.append(int.from_bytes(w, "big")) - return data + with open(filename, "rb") as f: + data = [] + while True: + w = f.read(1) + if not w: + break + data.append(int.from_bytes(w, "big")) + return data class Flterm: - def __init__(self, kernel_image, kernel_address): - self.kernel_image = kernel_image - self.kernel_address = kernel_address - - self.reader_alive = False - self.writer_alive = False - - self.detect_magic_str = " "*len(sfl_magic_req) - - def open(self, port, speed): - port = port if not port.isdigit() else int(port) - self.serial = serial.Serial(port, speed, timeout=0.25) - self.serial.flushOutput() - self.serial.flushInput() - self.serial.close() # in case port was not correctly closed - self.serial.open() - - def close(self): - self.serial.close() - - def write_exact(self, data): - if isinstance(data, str): - self.serial.write(bytes(data, "utf-8")) - else: - self.serial.write(serial.to_bytes(data)) - - def send_frame(self, frame): - frame.encode() - retry = 1 - while retry: - self.write_exact(frame.raw) - # Get the reply from the device - reply = character(self.serial.read()) - if reply == sfl_ack_success: - retry = 0 - elif reply == sfl_ack_crcerror: - retry = 1 - else: - print("[FLTERM] Got unknown reply '{}' from the device, aborting.".format(reply)) - return 0 - return 1 - - def upload(self, filename, address): - data = get_file_data(filename) - print("[FLTERM] Uploading {} ({} bytes)...".format(filename, len(data))) - current_address = address - position = 0 - length = len(data) - start = time.time() - while len(data) != 0: - print("{}%\r".format(100*position//length), end="") - frame = SFLFrame() - if len(data) > 251: - frame_data = data[:251] - frame.length = len(frame_data)+4 - frame.cmd = sfl_cmd_load - frame.payload.append((current_address & 0xff000000) >> 24) - frame.payload.append((current_address & 0x00ff0000) >> 16) - frame.payload.append((current_address & 0x0000ff00) >> 8) - frame.payload.append((current_address & 0x000000ff) >> 0) - for d in frame_data: - frame.payload.append(d) - if self.send_frame(frame) == 0: - return - current_address += len(frame_data) - position += len(frame_data) - try: - data = data[251:] - except: - data = [] - end = time.time() - elapsed = end - start - print("[FLTERM] Upload complete ({0:.1f}KB/s).".format(length/(elapsed*1024))) - return length - - def boot(self): - print("[FLTERM] Booting the device.") - frame = SFLFrame() - frame.length = 4 - frame.cmd = sfl_cmd_jump - frame.payload.append((self.kernel_address & 0xff000000) >> 24) - frame.payload.append((self.kernel_address & 0x00ff0000) >> 16) - frame.payload.append((self.kernel_address & 0x0000ff00) >> 8) - frame.payload.append((self.kernel_address & 0x000000ff) >> 0) - self.send_frame(frame) - - def detect_magic(self, data): - if data is not "": - self.detect_magic_str = self.detect_magic_str[1:] + data - return self.detect_magic_str == sfl_magic_req - else: - return False - - def answer_magic(self): - print("[FLTERM] Received firmware download request from the device.") - if os.path.exists(self.kernel_image): - self.write_exact(sfl_magic_ack) - self.upload(self.kernel_image, self.kernel_address) - self.boot() - print("[FLTERM] Done."); - - def reader(self): - try: - while self.reader_alive: - c = character(self.serial.read()) - if c == '\r': - sys.stdout.write('\n') - else: - sys.stdout.write(c) - sys.stdout.flush() - - if self.kernel_image is not None: - if self.detect_magic(c): - self.answer_magic() - - except serial.SerialException: - self.reader_alive = False - raise - - def start_reader(self): - self.reader_alive = True - self.reader_thread = threading.Thread(target=self.reader) - self.reader_thread.setDaemon(True) - self.reader_thread.start() - - def stop_reader(self): - self.reader_alive = False - self.reader_thread.join() - - def writer(self): - try: - while self.writer_alive: - try: - b = console.getkey() - except KeyboardInterrupt: - b = serial.to_bytes([3]) - c = character(b) - if c == chr(0x03): - self.stop() - elif c == '\n': - self.serial.write(LF) - else: - self.serial.write(b) - except: - self.writer_alive = False - raise - - def start_writer(self): - self.writer_alive = True - self.writer_thread = threading.Thread(target=self.writer) - self.writer_thread.setDaemon(True) - self.writer_thread.start() - - def stop_writer(self): - self.writer_alive = False - self.writer_thread.join() - - def start(self): - print("[FLTERM] Starting....") - self.start_reader() - self.start_writer() - - def stop(self): - self.reader_alive = False - self.writer_alive = False - - def join(self, writer_only=False): - self.writer_thread.join() - if not writer_only: - self.reader_thread.join() + def __init__(self, kernel_image, kernel_address): + self.kernel_image = kernel_image + self.kernel_address = kernel_address + + self.reader_alive = False + self.writer_alive = False + + self.detect_magic_str = " "*len(sfl_magic_req) + + def open(self, port, speed): + port = port if not port.isdigit() else int(port) + self.serial = serial.Serial(port, speed, timeout=0.25) + self.serial.flushOutput() + self.serial.flushInput() + self.serial.close() # in case port was not correctly closed + self.serial.open() + + def close(self): + self.serial.close() + + def write_exact(self, data): + if isinstance(data, str): + self.serial.write(bytes(data, "utf-8")) + else: + self.serial.write(serial.to_bytes(data)) + + def send_frame(self, frame): + frame.encode() + retry = 1 + while retry: + self.write_exact(frame.raw) + # Get the reply from the device + reply = character(self.serial.read()) + if reply == sfl_ack_success: + retry = 0 + elif reply == sfl_ack_crcerror: + retry = 1 + else: + print("[FLTERM] Got unknown reply '{}' from the device, aborting.".format(reply)) + return 0 + return 1 + + def upload(self, filename, address): + data = get_file_data(filename) + print("[FLTERM] Uploading {} ({} bytes)...".format(filename, len(data))) + current_address = address + position = 0 + length = len(data) + start = time.time() + while len(data) != 0: + print("{}%\r".format(100*position//length), end="") + frame = SFLFrame() + if len(data) > 251: + frame_data = data[:251] + frame.length = len(frame_data)+4 + frame.cmd = sfl_cmd_load + frame.payload.append((current_address & 0xff000000) >> 24) + frame.payload.append((current_address & 0x00ff0000) >> 16) + frame.payload.append((current_address & 0x0000ff00) >> 8) + frame.payload.append((current_address & 0x000000ff) >> 0) + for d in frame_data: + frame.payload.append(d) + if self.send_frame(frame) == 0: + return + current_address += len(frame_data) + position += len(frame_data) + try: + data = data[251:] + except: + data = [] + end = time.time() + elapsed = end - start + print("[FLTERM] Upload complete ({0:.1f}KB/s).".format(length/(elapsed*1024))) + return length + + def boot(self): + print("[FLTERM] Booting the device.") + frame = SFLFrame() + frame.length = 4 + frame.cmd = sfl_cmd_jump + frame.payload.append((self.kernel_address & 0xff000000) >> 24) + frame.payload.append((self.kernel_address & 0x00ff0000) >> 16) + frame.payload.append((self.kernel_address & 0x0000ff00) >> 8) + frame.payload.append((self.kernel_address & 0x000000ff) >> 0) + self.send_frame(frame) + + def detect_magic(self, data): + if data is not "": + self.detect_magic_str = self.detect_magic_str[1:] + data + return self.detect_magic_str == sfl_magic_req + else: + return False + + def answer_magic(self): + print("[FLTERM] Received firmware download request from the device.") + if os.path.exists(self.kernel_image): + self.write_exact(sfl_magic_ack) + self.upload(self.kernel_image, self.kernel_address) + self.boot() + print("[FLTERM] Done."); + + def reader(self): + try: + while self.reader_alive: + c = character(self.serial.read()) + if c == '\r': + sys.stdout.write('\n') + else: + sys.stdout.write(c) + sys.stdout.flush() + + if self.kernel_image is not None: + if self.detect_magic(c): + self.answer_magic() + + except serial.SerialException: + self.reader_alive = False + raise + + def start_reader(self): + self.reader_alive = True + self.reader_thread = threading.Thread(target=self.reader) + self.reader_thread.setDaemon(True) + self.reader_thread.start() + + def stop_reader(self): + self.reader_alive = False + self.reader_thread.join() + + def writer(self): + try: + while self.writer_alive: + try: + b = console.getkey() + except KeyboardInterrupt: + b = serial.to_bytes([3]) + c = character(b) + if c == chr(0x03): + self.stop() + elif c == '\n': + self.serial.write(LF) + else: + self.serial.write(b) + except: + self.writer_alive = False + raise + + def start_writer(self): + self.writer_alive = True + self.writer_thread = threading.Thread(target=self.writer) + self.writer_thread.setDaemon(True) + self.writer_thread.start() + + def stop_writer(self): + self.writer_alive = False + self.writer_thread.join() + + def start(self): + print("[FLTERM] Starting....") + self.start_reader() + self.start_writer() + + def stop(self): + self.reader_alive = False + self.writer_alive = False + + def join(self, writer_only=False): + self.writer_thread.join() + if not writer_only: + self.reader_thread.join() def _get_args(): - parser = argparse.ArgumentParser() - parser.add_argument("--port", default="2", help="serial port") - parser.add_argument("--speed", default=115200, help="serial baudrate") - parser.add_argument("--kernel", default=None, help="kernel image") - parser.add_argument("--kernel_adr", default=0x40000000, help="kernel address") - return parser.parse_args() + parser = argparse.ArgumentParser() + parser.add_argument("--port", default="2", help="serial port") + parser.add_argument("--speed", default=115200, help="serial baudrate") + parser.add_argument("--kernel", default=None, help="kernel image") + parser.add_argument("--kernel_adr", default=0x40000000, help="kernel address") + return parser.parse_args() if __name__ == "__main__": - args = _get_args() - flterm = Flterm(args.kernel, args.kernel_adr) - flterm.open(args.port, args.speed) - flterm.start() - try: - flterm.join(True) - except KeyboardInterrupt: - pass - flterm.join() + args = _get_args() + flterm = Flterm(args.kernel, args.kernel_adr) + flterm.open(args.port, args.speed) + flterm.start() + try: + flterm.join(True) + except KeyboardInterrupt: + pass + flterm.join() -- 2.30.2