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)
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)
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.
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("""\
__ ___ _ ____ _____
/ |/ / (_) / __/__ / ___/
/ /|_/ / / / _\ \/ _ \/ /__
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: {}
*/
""".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)
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)
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)
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)
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
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)
+ ]
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)
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
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")
# 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)
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
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"))
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)
+ ]
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)
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)
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")
+ )
_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")
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")
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")
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
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()
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)
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)
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)
+ )
+ ]
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"))
+ )
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
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)
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)
+ ]
@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)
# 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")
+ )
+ )
+ )
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)
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)
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")]
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]))
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 <hw/common.h>\n#include <generated/csr.h>\n#include <hw/flags.h>\n\n"
+ r = "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n"
+ r += "#include <hw/common.h>\n#include <generated/csr.h>\n#include <hw/flags.h>\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)
#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
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)
+ )
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]),
+ ]
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)
+ ]
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())
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")
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
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")
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")
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")
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}();
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)
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)
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))
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)
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 <hw/common.h>\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 <hw/common.h>\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
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)
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"}
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)
+ )
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)
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)
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)
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)
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)
+ ]
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)
# 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()
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")))
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))
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)
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))
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"))
+ )
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)
+ ]
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)
\r
required_version = (3, 3)\r
if sys.version_info < required_version:\r
- raise SystemExit("MiSoC requires python {0} or greater".format(\r
- ".".join(map(str, required_version))))\r
+ raise SystemExit("MiSoC requires python {0} or greater".format(\r
+ ".".join(map(str, required_version))))\r
\r
setup(\r
- name="misoclib",\r
- version="unknown",\r
- description="a high performance and small footprint SoC based on Migen",\r
- long_description=README,\r
- author="Sebastien Bourdeauducq",\r
- author_email="sb@m-labs.hk",\r
- url="http://m-labs.hk",\r
- download_url="https://github.com/m-labs/misoc",\r
- packages=find_packages(here),\r
- license="BSD",\r
- platforms=["Any"],\r
- keywords="HDL ASIC FPGA hardware design",\r
- classifiers=[\r
- "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",\r
- "Environment :: Console",\r
- "Development Status :: Alpha",\r
- "Intended Audience :: Developers",\r
- "License :: OSI Approved :: BSD License",\r
- "Operating System :: OS Independent",\r
- "Programming Language :: Python",\r
- ],\r
+ name="misoclib",\r
+ version="unknown",\r
+ description="a high performance and small footprint SoC based on Migen",\r
+ long_description=README,\r
+ author="Sebastien Bourdeauducq",\r
+ author_email="sb@m-labs.hk",\r
+ url="http://m-labs.hk",\r
+ download_url="https://github.com/m-labs/misoc",\r
+ packages=find_packages(here),\r
+ license="BSD",\r
+ platforms=["Any"],\r
+ keywords="HDL ASIC FPGA hardware design",\r
+ classifiers=[\r
+ "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",\r
+ "Environment :: Console",\r
+ "Development Status :: Alpha",\r
+ "Intended Audience :: Developers",\r
+ "License :: OSI Approved :: BSD License",\r
+ "Operating System :: OS Independent",\r
+ "Programming Language :: Python",\r
+ ],\r
)\r
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
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
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
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;
""", 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
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
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
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
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
# 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()