from amaranth import *
from amaranth.lib.io import pin_layout
from amaranth_soc.wishbone.bus import Interface


__all__ = ["LiteEth", "rgmii_layout"]


# TODO maybe this should just call liteeth_gen to close the loop?
class LiteEth(Elaboratable, Interface):
    def __init__(self):

        # Addr width is 13 bits to accomodate 0x1FFF, which is well p
        Interface.__init__(self, addr_width=13, data_width=32, granularity=8, features=["cti", "bte", "err"])

        self.rgmii_eth_clocks_tx = Signal()

        self.interrupt = Signal()


    # TODO this really shouldn't technically happen here, because we can elaborate one module multiple times,
    # but since I use it once it isn't actually a problem.
    def elaborate(self, platform):
        platform.add_file("liteeth_core.v", open("liteeth/gateware/liteeth_core.v", 'r').read())

        m = Module()


        # TODO I have to provide TX/RX clocks myself
        core = Instance(
            "liteeth_core",
            i_sys_clock=ClockSignal(),

            # RGMII signals
            o_rgmii_eth_clocks_tx=self.rgmii_eth_clocks_tx,

            # Wishbone all the things
            i_wishbone_adr=self.adr,
            i_wishbone_dat_w=self.dat_w,
            o_wishbone_dat_r=self.dat_r,
            i_wishbone_sel=self.sel,
            i_wishbone_cyc=self.cyc,
            o_wishbone_ack=self.ack,
            i_wishbone_we=self.we,
            i_wishbone_cti=self.cti,
            i_wishbone_bte=self.bte,
            o_wishbone_err=self.err,

            o_interrupt=self.interrupt,
        )

        m.submodules.core = core

        return m


rgmii_layout = [
    ("clocks_tx", pin_layout(1, "o")),
    ("clocks_rx", pin_layout(1, "i")),
    ("rst_n", pin_layout(1, "o")),
    ("int_n", pin_layout(1, "i")),

    # TODO is this not IO? why does LiteEth say input?
    # I think the answer is it uses a primitive, not 100% right now
    ("mdio", pin_layout(1, "i")),
    ("mdc", pin_layout(1, "o")),
    ("rx_ctl", pin_layout(1, "i")),
    ("rx_data", pin_layout(4, "i")),
    ("tx_ctl", pin_layout(1, "o")),
    ("tx_data", pin_layout(4, "o")),
]

