
from __future__ import division
from __future__ import print_function

import os

import myhdl
from myhdl import (Signal, ResetSignal, intbv, modbv,
                   always, always_comb, instance, delay,
                   traceSignals, Simulation,)

from elink import EMesh
from elink import EMeshSnapshot
from elink import emesh_fifo


def test_emesh_fifo():
    """
    """

    clock_a, clock_b = Signal(bool(0)), Signal(bool(0))
    reset = ResetSignal(0, active=1, async=False)
    emesh_a, emesh_b = EMesh(clock_a), EMesh(clock_b)
    input_data, output_data = [], []

    @always(delay(2500))
    def tbclka():
        clock_a.next = not clock_a

    @always(delay(1300))
    def tbclkb():
        clock_b.next = not clock_b

    def _test_stim():
        tbdut = emesh_fifo(reset, emesh_a, emesh_b)

        @instance
        def tbstim():
            yield delay(1111)
            for _ in range(5):
                yield clock_a.posedge

            # push a single packet and verify receipt on the other side
            yield emesh_a.write(0xDEEDA5A5, 0xDECAFBAD, 0xC0FFEE)
            input_data.append(EMeshSnapshot(emesh_a))

            for _ in range(10):
                yield clock_b.posedge

            assert len(output_data) == 1
            assert output_data[0] == input_data[0]

            raise myhdl.StopSimulation

        @always(clock_b.posedge)
        def tbcap():
            if emesh_b.txwr.access or emesh_b.txrd.access or emesh_b.txrr.access:
                print("output packet: {}".format(emesh_b))
                output_data.append(EMeshSnapshot(emesh_b))

            if emesh_a.txwr.access or emesh_a.txwr.data != 0:
                print("{}".format(emesh_a))

        # monitor an emesh (interface tracing limitations)
        emesh_a_access = Signal(bool(0))
        emesh_a_data = Signal(intbv(0)[32:0])

        emesh_b_access = Signal(bool(0))
        emesh_b_data = Signal(intbv(0)[32:0])

        cm = Signal(modbv(0)[8:])

        @always(emesh_b.clock.posedge)
        def tbmon():
            cm.next = cm + 1

            emesh_a_access.next = emesh_a.txwr.access
            emesh_a_data.next = emesh_a.txwr.data

            emesh_b_access.next = emesh_b.txwr.access
            emesh_b_data.next = emesh_b.txwr.data

        return tbclka, tbclkb, tbcap, tbmon, tbdut, tbstim

    traceSignals.timescale = '1ps'
    traceSignals.name = 'vcd/_test_emesh_fifo'
    if os.path.isfile(traceSignals.name+'.vcd'):
        os.remove(traceSignals.name+'.vcd')
    g = traceSignals(_test_stim)
    Simulation(g).run()
    #myhdl.toVerilog()


if __name__ == '__main__':
    test_emesh_fifo()