diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index af28d5ff3..1a58cc1b9 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -447,6 +447,41 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) return '\n'.join(cmd) + def generate_hyperram(self, block, verbose=True): + block_type = "HYPERRAM" + pads = block["pads"] + name = block["name"] + location = block["location"] + ctl_clk = block["ctl_clk"].name_override + cal_clk = block["cal_clk"].name_override + clk90_clk = block["clk90_clk"].name_override + + cmd = [] + cmd.append('design.create_block("{}", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "CK_N_HI_PIN", "{}", "{}")'.format(name, pads.clkn_h.name, block_type)) + cmd.append('design.set_property("{}", "CK_N_LO_PIN", "{}", "{}")'.format(name, pads.clkn_l.name, block_type)) + cmd.append('design.set_property("{}", "CK_P_HI_PIN", "{}", "{}")'.format(name, pads.clkp_h.name, block_type)) + cmd.append('design.set_property("{}", "CK_P_LO_PIN", "{}", "{}")'.format(name, pads.clkp_l.name, block_type)) + cmd.append('design.set_property("{}", "CLK90_PIN", "{}", "{}")'.format(name, clk90_clk, block_type)) + cmd.append('design.set_property("{}", "CLKCAL_PIN", "{}", "{}")'.format(name, cal_clk, block_type)) + cmd.append('design.set_property("{}", "CLK_PIN", "{}", "{}")'.format(name, ctl_clk, block_type)) + cmd.append('design.set_property("{}", "CS_N_PIN", "{}", "{}")'.format(name, pads.csn.name, block_type)) + cmd.append('design.set_property("{}", "DQ_IN_HI_PIN", "{}", "{}")'.format(name, pads.dq_i_h.name, block_type)) + cmd.append('design.set_property("{}", "DQ_IN_LO_PIN", "{}", "{}")'.format(name, pads.dq_i_l.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OE_PIN", "{}", "{}")'.format(name, pads.dq_oe.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OUT_HI_PIN", "{}", "{}")'.format(name, pads.dq_o_h.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OUT_LO_PIN", "{}", "{}")'.format(name, pads.dq_o_l.name, block_type)) + cmd.append('design.set_property("{}", "RST_N_PIN", "{}", "{}")'.format(name, pads.rstn.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_IN_HI_PIN", "{}", "{}")'.format(name, pads.rwds_i_h.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_IN_LO_PIN", "{}", "{}")'.format(name, pads.rwds_i_l.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OE_PIN", "{}", "{}")'.format(name, pads.rwds_oe.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OUT_HI_PIN", "{}", "{}")'.format(name, pads.rwds_o_h.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OUT_LO_PIN", "{}", "{}")'.format(name, pads.rwds_o_l.name, block_type)) + + cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) + + return '\n'.join(cmd) + '\n' + def generate(self, partnumber): output = "" for block in self.blocks: @@ -463,6 +498,8 @@ design.create("{2}", "{3}", "./../gateware", overwrite=True) output += self.generate_mipi_rx(block) if block["type"] == "LVDS": output += self.generate_lvds(block) + if block["type"] == "HYPERRAM": + output += self.generate_hyperram(block) if block["type"] == "JTAG": output += self.generate_jtag(block) return output diff --git a/litex/soc/cores/ram/efinix_hyperram.py b/litex/soc/cores/ram/efinix_hyperram.py new file mode 100644 index 000000000..509b8bcea --- /dev/null +++ b/litex/soc/cores/ram/efinix_hyperram.py @@ -0,0 +1,138 @@ +# +# This file is part of LiteHyperBus +# +# Copyright (c) 2023 Gwenhael Goavec-Merou +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +from litex.build.generic_platform import * + +from litex.gen import * +from litex.gen.genlib.misc import WaitTimer + +from litex.build.io import DifferentialOutput + +from litex.soc.interconnect import wishbone + +from litex.soc.cores.clock.efinix import TITANIUMPLL + +from litex.soc.cores.hyperbus import HyperRAM + +# HyperRAM (efinix F100) --------------------------------------------------------------------------- + +class EfinixHyperRAM(HyperRAM): + """ HyperRAM wrapper for efinix F100 (internal) + """ + def __init__(self, platform, latency=6, clock_domain="sys", sys_clk_freq=None): + + # # # + + assert sys_clk_freq is not None and sys_clk_freq * 2 < 250e6 + + _io = [ + ("hyperram", 0, + Subsignal("clkp_h", 0, Pins(1)), + Subsignal("clkp_l", 0, Pins(1)), + Subsignal("clkn_h", 0, Pins(1)), + Subsignal("clkn_l", 0, Pins(1)), + Subsignal("dq_o_h", 0, Pins(16)), + Subsignal("dq_o_l", 0, Pins(16)), + Subsignal("dq_i_h", 0, Pins(16)), + Subsignal("dq_i_l", 0, Pins(16)), + Subsignal("dq_oe", 0, Pins(16)), + Subsignal("rwds_o_h", 0, Pins(2)), + Subsignal("rwds_o_l", 0, Pins(2)), + Subsignal("rwds_i_h", 0, Pins(2)), + Subsignal("rwds_i_l", 0, Pins(2)), + Subsignal("rwds_oe", 0, Pins(2)), + Subsignal("csn", 0, Pins(1)), + Subsignal("rstn", 0, Pins(1)), + )] + + # PLL dyn phase shift + + platform.add_extension([ + ("shift_ena", 0, Pins(1)), + ("shift_sel", 0, Pins(1)), + ("shift", 0, Pins(1)), + ]) + + _dps_pads = { + "shift_ena" : platform.request("shift_ena"), + "shift_sel" : platform.request("shift_sel"), + "shift" : platform.request("shift"), + } + platform.toolchain.excluded_ios.append(_dps_pads["shift_ena"]) + platform.toolchain.excluded_ios.append(_dps_pads["shift_sel"]) + platform.toolchain.excluded_ios.append(_dps_pads["shift"]) + + # PLL. + self.pll = pll = TITANIUMPLL(platform, dyn_phase_shift_pads=_dps_pads) + pll.register_clkin(ClockDomain(clock_domain).clk, sys_clk_freq, clock_domain) + pll.create_clkout(None, sys_clk_freq) + pll.create_clkout(None, sys_clk_freq*2, name="hp_clk", with_reset=True) + pll.create_clkout(None, sys_clk_freq*2, phase=90, name="hp90_clk", with_reset=True) + pll.create_clkout(None, sys_clk_freq*2, name="hpcal_clk", with_reset=True, dyn_phase=True) + + + # connect HyperRAM to interface designer block + class HPPads: + def __init__(self): + self.dq = TSTriple(16) + self.rwds = TSTriple(2) + self.cs_n = Signal(1) + self.rst_n = Signal(1) + self.clk = Signal(1) + + _hp_pads = HPPads() + platform.add_extension(_io) + self.io_pads = _io_pads = platform.request("hyperram") + + self.comb += [ + _io_pads.clkp_l.eq(_hp_pads.clk), + _io_pads.clkp_h.eq(_hp_pads.clk), + _io_pads.clkn_l.eq(~_hp_pads.clk), + _io_pads.clkn_h.eq(~_hp_pads.clk), + _io_pads.dq_o_h.eq(_hp_pads.dq.o), + _io_pads.dq_o_l.eq(_hp_pads.dq.o), + _hp_pads.dq.i.eq(_io_pads.dq_i_h | _io_pads.dq_i_l), + _io_pads.dq_oe.eq(Replicate(_hp_pads.dq.oe[0], 16)), + _io_pads.rwds_o_h.eq(_hp_pads.rwds.o), + _io_pads.rwds_o_l.eq(_hp_pads.rwds.o), + _hp_pads.rwds.i.eq(_io_pads.rwds_i_h | _io_pads.rwds_i_l), + _io_pads.rwds_oe.eq(Replicate(_hp_pads.rwds.oe[0], 2)), + _io_pads.csn.eq(_hp_pads.cs_n), + _io_pads.rstn.eq(_hp_pads.rst_n), + ] + + block = { + "type" : "HYPERRAM", + "name" : "hp_inst", + "location" : "HYPER_RAM0", + "pads" : _io_pads, + "ctl_clk" : ClockDomain("hp").clk, + "cal_clk" : ClockDomain("hpcal").clk, + "clk90_clk" : ClockDomain("hp90").clk, + } + + platform.toolchain.ifacewriter.blocks.append(block) + + platform.toolchain.excluded_ios.append(_io_pads.clkp_h) + platform.toolchain.excluded_ios.append(_io_pads.clkp_l) + platform.toolchain.excluded_ios.append(_io_pads.clkn_h) + platform.toolchain.excluded_ios.append(_io_pads.clkn_l) + platform.toolchain.excluded_ios.append(_io_pads.dq_o_h) + platform.toolchain.excluded_ios.append(_io_pads.dq_o_l) + platform.toolchain.excluded_ios.append(_io_pads.dq_i_h) + platform.toolchain.excluded_ios.append(_io_pads.dq_i_l) + platform.toolchain.excluded_ios.append(_io_pads.dq_oe) + platform.toolchain.excluded_ios.append(_io_pads.rwds_o_h) + platform.toolchain.excluded_ios.append(_io_pads.rwds_o_l) + platform.toolchain.excluded_ios.append(_io_pads.rwds_i_l) + platform.toolchain.excluded_ios.append(_io_pads.rwds_i_h) + platform.toolchain.excluded_ios.append(_io_pads.rwds_oe) + platform.toolchain.excluded_ios.append(_io_pads.csn) + platform.toolchain.excluded_ios.append(_io_pads.rstn) + + HyperRAM.__init__(self, _hp_pads, latency, sys_clk_freq)