Exemple #1
0
class FFTTB:
    """
    R22 SDF FFT testbench class.
    """
    def __init__(self, dut, num_samples, input_width):
        clk = Clock(dut.clk_i, 40)
        clk_3x = Clock(dut.clk_3x_i, 120)
        self.multiclock = MultiClock([clk, clk_3x])
        self.dut = dut
        self.re_inputs = random_samples(input_width, num_samples)
        self.im_inputs = random_samples(input_width, num_samples)
        self.outputs = np.fft.fft(self.re_inputs + 1j * self.im_inputs)

    @cocotb.coroutine
    async def setup(self):
        self.multiclock.start_all_clocks()
        await self.reset()

    @cocotb.coroutine
    async def reset(self):
        await self.await_all_clocks()
        self.dut.rst_n <= 0
        await self.await_all_clocks()
        self.dut.rst_n <= 1

    @cocotb.coroutine
    async def await_all_clocks(self):
        """
        Wait for positive edge on both clocks before proceeding.
        """
        trigs = []
        for clk in self.multiclock.clocks:
            trigs.append(RisingEdge(clk.clk))

        await Combine(*trigs)

    def check_outputs(self, tolerance):
        """
        Check that the measured outputs are within the specified tolerance
        of the actual outputs. Raise a test failure if not. If the
        tolerance is satisfied, return a tuple of the difference
        values.
        """
        bit_rev_ctr = self.dut.data_ctr_o.value.integer
        rval = self.dut.data_re_o.value.signed_integer
        rexp = np.real(self.outputs)[bit_rev_ctr].item()
        rdiff = rval - rexp
        ival = self.dut.data_im_o.value.signed_integer
        iexp = np.imag(self.outputs)[bit_rev_ctr].item()
        idiff = ival - iexp
        if abs(rval - rexp) > tolerance:
            raise TestFailure(("Actual real output differs from expected."
                               " Actual: %d, expected: %d, difference: %d."
                               " Tolerance set at %d.") %
                              (rval, rexp, rval - rexp, tolerance))

        if abs(ival - iexp) > tolerance:
            raise TestFailure(("Actual imaginary output differs from expected."
                               " Actual: %d, expected: %d, difference: %d."
                               " Tolerance set at %d.") %
                              (ival, iexp, ival - iexp, tolerance))

        return (rdiff, idiff)

    @cocotb.coroutine
    async def write_inputs(self):
        """
        Send all calculated inputs to dut.
        """
        ctr = 0
        num_samples = len(self.re_inputs)
        while True:
            if ctr < num_samples:
                self.dut.data_re_i <= self.re_inputs[ctr].item()
                self.dut.data_im_i <= self.im_inputs[ctr].item()
            else:
                self.dut.data_re_i <= 0
                self.dut.data_im_i <= 0

            await RisingEdge(self.dut.clk_i)
            ctr += 1

    @cocotb.coroutine
    async def send_intermittent_resets(self):
        """
        Randomly send reset signals to FFT.
        """
        timestep = min(self.multiclock.clock_periods())
        while True:
            self.dut.rst_n <= 1
            time_on = timestep * np.random.randint(1e2, 1e4, dtype=int)
            await Timer(time_on)
            self.dut.rst_n <= 0
            time_off = timestep * np.random.randint(1e2, 1e3, dtype=int)
            await Timer(time_off)
Exemple #2
0
class TopTB:
    def __init__(self, dut):
        clk = Clock(dut.clk_i, 40)
        clk_7_5 = Clock(dut.clk_7_5mhz, 7.5)
        clk_120 = Clock(dut.clk_120mhz, 120)
        clk_80 = Clock(dut.clk_80mhz, 80)
        clk_20 = Clock(dut.clk_20mhz, 20)
        ftclk = Clock(dut.ft_clkout_i, 60)
        self.multiclock = MultiClock(
            [clk, clk_7_5, clk_120, clk_80, clk_20, ftclk])
        self.dut = dut

    @cocotb.coroutine
    async def setup(self):
        self.multiclock.start_all_clocks()
        self.dut.ft_rxf_n_i <= 1
        self.dut.ft_txe_n_i <= 1
        self.dut.ft_suspend_n_i <= 1
        await self.reset()

    @cocotb.coroutine
    async def reset(self):
        await self.await_all_clocks()
        self.dut.pll_lock <= 0
        await self.await_all_clocks()
        self.dut.pll_lock <= 1

    @cocotb.coroutine
    async def await_all_clocks(self):
        trigs = []
        for clk in self.multiclock.clocks:
            trigs.append(RisingEdge(clk.clk))

        await Combine(*trigs)

    @cocotb.coroutine
    async def rand_lose_lock(self):
        """
        Simulate random loss of PLL lock. This attempts to be somewhat
        physically accurate by mainting the lock for longer periods
        than it is lost.
        """
        time_unit = min(self.multiclock.clock_periods())
        while True:
            time_on = np.random.randint(1e3 * time_unit,
                                        1e4 * time_unit,
                                        dtype=int)
            await Timer(time_on)
            self.dut.pll_lock <= 0
            time_off = np.random.randint(1e1 * time_unit,
                                         1e2 * time_unit,
                                         dtype=int)
            await Timer(time_off)
            self.dut.pll_lock <= 1

    @cocotb.coroutine
    async def pc_request_mode(self, mode):
        """
        Simulate sending a request from the host PC for a certain kind of
        data. This is equivalent to using the fmcw -i flag. The valid
        values are the same. I.e. @mode can be 'raw', 'fir', 'window',
        or 'fft'.
        """
        if mode == "fft":
            mode_bits = 1
        elif mode == "window":
            mode_bits = 2
        elif mode == "fir":
            mode_bits = 3
        elif mode == "raw":
            mode_bits = 4
        else:
            raise ValueError("request_mode: invalid request")

        await RisingEdge(self.dut.ft_clkout_i)
        self.dut.ft_rxf_n_i <= 0
        self.dut.ft_data_io <= mode_bits
        await RisingEdge(self.dut.ft_clkout_i)
        self.dut.ft_data_io <= mode_bits
        await RisingEdge(self.dut.ft_clkout_i)
        self.dut.ft_data_io <= mode_bits
        await RisingEdge(self.dut.ft_clkout_i)
        await RisingEdge(self.dut.ft_clkout_i)
        await ReadOnly()
        while self.dut.ft_rd_n_o.value.integer:
            await RisingEdge(self.dut.ft_clkout_i)
            await ReadOnly()
        await RisingEdge(self.dut.ft_clkout_i)
        self.dut.ft_rxf_n_i <= 1

    @cocotb.coroutine
    async def pc_request_data(self):
        """
        Signal the PC is asking to read data from the FPGA.
        """
        await RisingEdge(self.dut.ft_clkout_i)
        self.dut.ft_txe_n_i <= 0
        await RisingEdge(self.dut.ft_clkout_i)

    @cocotb.coroutine
    # TODO add samples on falling edge for chan b
    async def gen_samples(self, inputs):
        sample_ctr = 0
        num_samples = len(inputs)
        while True:
            if sample_ctr == num_samples:
                sample_ctr = 0

            self.dut.adc_d_i <= BinaryValue(
                int(inputs[sample_ctr].item()), 12, binaryRepresentation=2)
            sample_ctr += 1
            await RisingEdge(self.dut.clk_i)