#
# This file is part of LUNA.
#
# Copyright (c) 2020 <NAME> <<EMAIL>>
# SPDX-License-Identifier: BSD-3-Clause

""" ULX3S platform definitions.

This is a non-core platform. To use it, you'll need to set your LUNA_PLATFORM variable,
as appropriate:

    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_12F_Platform"
    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_25F_Platform"
    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_45F_Platform"
    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_85F_Platform"
"""

import os
import subprocess

from abc import ABCMeta, abstractmethod

from amaranth import *
from amaranth.build import *
import amaranth_boards.ulx3s as _ulx3s

from .core import LUNAPlatform


class ULX3SDomainGenerator(Elaboratable):
    """ Clock domain generator that creates the domain clocks for the ULX3S. """

    def elaborate(self, platform):
        m = Module()

        # Grab our default input clock.
        input_clock = platform.request(platform.default_clk, dir="i")

        # Create our domains; but don't do anything else for them, for now.
        m.domains.sync   = ClockDomain()
        m.domains.usb    = ClockDomain()
        m.domains.usb_io = ClockDomain()
        m.domains.fast   = ClockDomain()

        feedback = Signal()
        locked   = Signal()

        m.submodules.pll = Instance("EHXPLLL",
            i_RST=1,
            i_STDBY=0,
            i_CLKI=input_clock.i,
            i_PHASESEL0=0,
            i_PHASESEL1=0,
            i_PHASEDIR=1,
            i_PHASESTEP=1,
            i_PHASELOADREG=1,
            i_PLLWAKESYNC=0,
            i_ENCLKOP=0,
            i_CLKFB=feedback,

            o_LOCK=locked,
            o_CLKOP=feedback,
            o_CLKOS=ClockSignal("sync"),
            o_CLKOS2=ClockSignal("usb"),

            p_PLLRST_ENA="DISABLED",
            p_INTFB_WAKE="DISABLED",
            p_STDBY_ENABLE="DISABLED",
            p_DPHASE_SOURCE="DISABLED",
            p_OUTDIVIDER_MUXA="DIVA",
            p_OUTDIVIDER_MUXB="DIVB",
            p_OUTDIVIDER_MUXC="DIVC",
            p_OUTDIVIDER_MUXD="DIVD",
            p_CLKI_DIV=5,
            p_CLKOP_ENABLE="ENABLED",
            p_CLKOS2_ENABLE="ENABLED",
            p_CLKOP_DIV=48,
            p_CLKOP_CPHASE=9,
            p_CLKOP_FPHASE=0,
            p_CLKOS_ENABLE="ENABLED",
            p_CLKOS_DIV=10,
            p_CLKOS_CPHASE=0,
            p_CLKOS_FPHASE=0,
            p_CLKOS2_DIV=40,
            p_CLKOS2_CPHASE=0,
            p_CLKOS2_FPHASE=0,
            p_FEEDBK_PATH="CLKOP",
            p_CLKFB_DIV=2,

            a_FREQUENCY_PIN_CLKI="25",
            a_FREQUENCY_PIN_CLKOP="48",
            a_FREQUENCY_PIN_CLKOS="48",
            a_FREQUENCY_PIN_CLKOS2="12",
            a_ICP_CURRENT="12",
            a_LPF_RESISTOR="8",
            a_MFG_ENABLE_FILTEROPAMP="1",
            a_MFG_GMCREF_SEL="2",

        )

        # We'll use our 48MHz clock for everything _except_ the usb domain...
        m.d.comb += [
            ClockSignal("usb_io")  .eq(ClockSignal("sync")),
            ClockSignal("fast")    .eq(ClockSignal("sync")),

            ResetSignal("sync")    .eq(~locked),
            ResetSignal("fast")    .eq(~locked),
            ResetSignal("usb")     .eq(~locked),
            ResetSignal("usb_io")  .eq(~locked),
        ]

        return m


class ULX3S_12F_Platform(_ulx3s.ULX3S_12F_Platform, LUNAPlatform):
    name                   = "ULX3S (12F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator


class ULX3S_25F_Platform(_ulx3s.ULX3S_25F_Platform, LUNAPlatform):
    name                   = "ULX3S (25F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator


class ULX3S_45F_Platform(_ulx3s.ULX3S_45F_Platform, LUNAPlatform):
    name                   = "ULX3S (45F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator


class ULX3S_85F_Platform(_ulx3s.ULX3S_85F_Platform, LUNAPlatform):
    name                   = "ULX3S (85F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator

#
# This file is part of LUNA.
#
# Copyright (c) 2020 <NAME> <<EMAIL>>
# SPDX-License-Identifier: BSD-3-Clause

""" ULX3S platform definitions.

This is a non-core platform. To use it, you'll need to set your LUNA_PLATFORM variable,
as appropriate:

    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_12F_Platform"
    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_25F_Platform"
    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_45F_Platform"
    > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_85F_Platform"
"""

import os
import subprocess

from abc import ABCMeta, abstractmethod

from amaranth import *
from amaranth.build import *
import amaranth_boards.ulx3s as _ulx3s

from .core import LUNAPlatform


class ULX3SDomainGenerator(Elaboratable):
    """ Clock domain generator that creates the domain clocks for the ULX3S. """

    def elaborate(self, platform):
        m = Module()

        # Grab our default input clock.
        input_clock = platform.request(platform.default_clk, dir="i")

        # Create our domains; but don't do anything else for them, for now.
        m.domains.sync   = ClockDomain()
        m.domains.usb    = ClockDomain()
        m.domains.usb_io = ClockDomain()
        m.domains.fast   = ClockDomain()

        feedback = Signal()
        locked   = Signal()

        m.submodules.pll = Instance("EHXPLLL",
            i_RST=1,
            i_STDBY=0,
            i_CLKI=input_clock.i,
            i_PHASESEL0=0,
            i_PHASESEL1=0,
            i_PHASEDIR=1,
            i_PHASESTEP=1,
            i_PHASELOADREG=1,
            i_PLLWAKESYNC=0,
            i_ENCLKOP=0,
            i_CLKFB=feedback,

            o_LOCK=locked,
            o_CLKOP=feedback,
            o_CLKOS=ClockSignal("sync"),
            o_CLKOS2=ClockSignal("usb"),

            p_PLLRST_ENA="DISABLED",
            p_INTFB_WAKE="DISABLED",
            p_STDBY_ENABLE="DISABLED",
            p_DPHASE_SOURCE="DISABLED",
            p_OUTDIVIDER_MUXA="DIVA",
            p_OUTDIVIDER_MUXB="DIVB",
            p_OUTDIVIDER_MUXC="DIVC",
            p_OUTDIVIDER_MUXD="DIVD",
            p_CLKI_DIV=5,
            p_CLKOP_ENABLE="ENABLED",
            p_CLKOS2_ENABLE="ENABLED",
            p_CLKOP_DIV=48,
            p_CLKOP_CPHASE=9,
            p_CLKOP_FPHASE=0,
            p_CLKOS_ENABLE="ENABLED",
            p_CLKOS_DIV=10,
            p_CLKOS_CPHASE=0,
            p_CLKOS_FPHASE=0,
            p_CLKOS2_DIV=40,
            p_CLKOS2_CPHASE=0,
            p_CLKOS2_FPHASE=0,
            p_FEEDBK_PATH="CLKOP",
            p_CLKFB_DIV=2,

            a_FREQUENCY_PIN_CLKI="25",
            a_FREQUENCY_PIN_CLKOP="48",
            a_FREQUENCY_PIN_CLKOS="48",
            a_FREQUENCY_PIN_CLKOS2="12",
            a_ICP_CURRENT="12",
            a_LPF_RESISTOR="8",
            a_MFG_ENABLE_FILTEROPAMP="1",
            a_MFG_GMCREF_SEL="2",

        )

        # We'll use our 48MHz clock for everything _except_ the usb domain...
        m.d.comb += [
            ClockSignal("usb_io")  .eq(ClockSignal("sync")),
            ClockSignal("fast")    .eq(ClockSignal("sync")),

            ResetSignal("sync")    .eq(~locked),
            ResetSignal("fast")    .eq(~locked),
            ResetSignal("usb")     .eq(~locked),
            ResetSignal("usb_io")  .eq(~locked),
        ]

        return m


class ULX3S_12F_Platform(_ulx3s.ULX3S_12F_Platform, LUNAPlatform):
    name                   = "ULX3S (12F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator


class ULX3S_25F_Platform(_ulx3s.ULX3S_25F_Platform, LUNAPlatform):
    name                   = "ULX3S (25F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator


class ULX3S_45F_Platform(_ulx3s.ULX3S_45F_Platform, LUNAPlatform):
    name                   = "ULX3S (45F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator


class ULX3S_85F_Platform(_ulx3s.ULX3S_85F_Platform, LUNAPlatform):
    name                   = "ULX3S (85F)"
    default_usb_connection = "usb"
    clock_domain_generator = ULX3SDomainGenerator

# # This file is part of LUNA. # # Copyright (c) 2020 <NAME> <<EMAIL>> # SPDX-License-Identifier: BSD-3-Clause ULX3S platform definitions.  This is a non-core platform. To use it, you'll need to set your LUNA_PLATFORM variable, as appropriate:      > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_12F_Platform"     > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_25F_Platform"     > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_45F_Platform"     > export LUNA_PLATFORM="luna.gateware.platform.ulx3s:ULX3S_85F_Platform" Clock domain generator that creates the domain clocks for the ULX3S. # Grab our default input clock. # Create our domains; but don't do anything else for them, for now. # We'll use our 48MHz clock for everything _except_ the usb domain...