def test_sim(simulator_name, n=8):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # declare circuit
    class dut(m.Circuit):
        name = 'histogram_data_gen'
        io = m.IO(clk=m.ClockIn,
                  mode=m.In(m.Bits[3]),
                  in0=m.In(m.Bits[n]),
                  in1=m.In(m.Bits[n]),
                  out=m.Out(m.Bits[n]))

    # create tester
    t = fault.Tester(dut, dut.clk)

    # initialize with the right equation
    t.zero_inputs()

    # run a few cycles
    t.step(10)

    # test uniform mode
    t.poke(dut.mode, UNIFORM)
    t.step(4)
    unif_vec = []
    for _ in range(1 << n):
        unif_vec.append(t.get_value(dut.out))
        t.step(2)

    # test constant mode
    t.poke(dut.mode, CONSTANT)
    t.poke(dut.in0, 42)
    t.step(4)
    const_vec = []
    for _ in range(1 << n):
        const_vec.append(t.get_value(dut.out))
        t.step(2)

    # test "include" mode
    t.poke(dut.mode, INCL)
    t.poke(dut.in0, 34)
    t.poke(dut.in1, 56)
    t.step(4)
    incl_vec = []
    for _ in range(1 << n):
        incl_vec.append(t.get_value(dut.out))
        t.step(2)

    # test "exclude" mode
    t.poke(dut.mode, EXCL)
    t.poke(dut.in0, 12)
    t.poke(dut.in1, 243)
    t.step(4)
    excl_vec = []
    for _ in range(1 << n):
        excl_vec.append(t.get_value(dut.out))
        t.step(2)

    # test "alternate" mode
    t.poke(dut.mode, ALT)
    t.poke(dut.in0, 78)
    t.poke(dut.in1, 89)
    t.step(4)
    alt_vec = []
    for _ in range(1 << n):
        alt_vec.append(t.get_value(dut.out))
        t.step(2)

    ##################
    # run simulation #
    ##################

    t.compile_and_run(
        target='system-verilog',
        simulator=simulator_name,
        ext_srcs=get_deps_cpu_sim(cell_name='histogram_data_gen'),
        parameters={
            'n': n,
        },
        ext_model_file=True,
        disp_type='realtime',
        dump_waveforms=False,
        directory=BUILD_DIR,
        num_cycles=1e12)

    ###################
    # convert results #
    ###################

    def conv(x):
        return [elem.value for elem in x]

    unif_vec = conv(unif_vec)
    const_vec = conv(const_vec)
    incl_vec = conv(incl_vec)
    excl_vec = conv(excl_vec)
    alt_vec = conv(alt_vec)

    #################
    # print results #
    #################

    print(f'unif_vec: {unif_vec}')
    print()
    print(f'const_vec: {const_vec}')
    print()
    print(f'incl_vec: {incl_vec}')
    print()
    print(f'excl_vec: {excl_vec}')
    print()
    print(f'alt_vec: {alt_vec}')
    print()

    #################
    # check results #
    #################

    # uniform
    assert list(sorted(unif_vec)) == list(
        range(1 << n)), 'Output of uniform data generator unexpected.'

    # constant
    assert const_vec == [42] * (
        1 << n), 'Output of constant data generator unexpected.'

    # include
    per = 56 - 34 + 1
    nper = len(incl_vec) // per
    expct = []
    for k in range(34, 57):
        expct += [k] * nper
    assert list(sorted(
        incl_vec[:nper *
                 per])) == expct, 'Output of "include" pattern unexpected.'

    # exclude
    per = (11 - 0 + 1) + (255 - 244 + 1)
    nper = len(excl_vec) // per
    expct = []
    for k in range(0, 12):
        expct += [k] * nper
    for k in range(244, 256):
        expct += [k] * nper
    assert list(sorted(
        excl_vec[:nper *
                 per])) == expct, 'Output of "exclude" pattern unexpected.'

    # alternating
    assert alt_vec[:2] == [78, 89] or alt_vec[:2] == [89, 78]
    assert alt_vec == alt_vec[:2] * (
        1 << (n - 1)), 'Output of alternating data generator unexpected.'

    ###################
    # declare success #
    ###################

    print('Success!')
Example #2
0
t.zero_inputs()
t.poke(dut.rst, 1)
t.step(2)

# clear reset
t.poke(dut.rst, 0)
t.step(2)

# read out bits
hist = []
for _ in range(32 * 16):
    hist.append(t.get_value(dut.out))
    t.step(2)

# run the simulation
ext_srcs = get_deps_cpu_sim(impl_file=THIS_DIR / 'gather.sv')
t.compile_and_run(target='system-verilog',
                  directory=BUILD_DIR,
                  simulator='iverilog',
                  ext_srcs=ext_srcs,
                  ext_model_file=True,
                  disp_type='realtime',
                  dump_waveforms=True)

# print result
hist = [elem.value for elem in hist]
inits = [list() for _ in range(16)]
for k, elem in enumerate(hist):
    inits[k % 16].append(elem)
for k, init in enumerate(inits):
    assert len(init) == 32
Example #3
0
def test_sim(simulator_name, Nadc=8, Nrange=4, Navg=10):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # declare circuit
    class dut(m.Circuit):
        name = 'calib_sample_avg'
        io = m.IO(din=m.In(m.SInt[Nadc]),
                  Navg=m.In(m.Bits[Nrange]),
                  clk=m.ClockIn,
                  update=m.BitIn,
                  rstb=m.BitIn,
                  avg_out=m.Out(m.SInt[Nadc]),
                  sum_out=m.Out(m.SInt[Nadc + (2**Nrange)]))

    # create tester
    t = fault.Tester(dut, dut.clk)

    # define data vectors
    data_vecs = [
        [-42] * (1 << Navg), [+42] * (1 << Navg), [0] * (1 << Navg),
        [
            random.randint(-(1 << (Nadc - 1)), (1 << (Nadc - 1)) - 1)
            for _ in range(1 << Navg)
        ],
        [random.randint(0, (1 << (Nadc - 1)) - 1) for _ in range(1 << Navg)],
        [random.randint(-(1 << (Nadc - 1)), 0) for _ in range(1 << Navg)]
    ]

    # define averaging test
    def run_avg(data, last):
        # middle values
        t.poke(dut.update, 0)
        for elem in data[1:]:
            t.poke(dut.din, elem)
            t.step(2)

        # final value
        t.poke(dut.update, 1)
        t.poke(dut.din, last)
        t.step(2)

        # get values for average and sum
        avg_out = t.get_value(dut.avg_out)
        sum_out = t.get_value(dut.sum_out)

        return avg_out, sum_out

    # initialize
    t.zero_inputs()
    t.poke(dut.Navg, Navg)

    # run a few cycles
    t.step(10)
    t.poke(dut.rstb, 1)
    t.step(2)

    # first value
    t.poke(dut.update, 1)
    t.poke(dut.din, data_vecs[0][0])
    t.step(2)

    # run averaging trials
    results = []
    for k in range(len(data_vecs)):
        if k <= (len(data_vecs) - 2):
            last = data_vecs[k + 1][0]
        else:
            last = 0
        results.append(run_avg(data_vecs[k], last))

    # run a few extra cycles for better visibility
    t.poke(dut.update, 0)
    t.step(10)

    ##################
    # run simulation #
    ##################

    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=get_deps_cpu_sim(cell_name=dut.name),
                      parameters={
                          'Nadc': Nadc,
                          'Nrange': Nrange
                      },
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=False,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    ##################
    # convert values #
    ##################

    def to_signed(x, n):
        if x >= (1 << (n - 1)):
            return x - (1 << n)
        else:
            return x

    results = [(to_signed(res[0].value,
                          Nadc), to_signed(res[1].value, Nadc + (2**Nrange)))
               for res in results]

    print('results', results)

    ################
    # check values #
    ################

    for (avg_out, sum_out), data_vec in zip(results, data_vecs):
        assert sum_out == sum(data_vec), 'Mismatch in sum.'
        assert avg_out == sum(data_vec) >> Navg, 'Mismatch in average.'

    ###################
    # declare success #
    ###################

    print('Success!')
Example #4
0
def test_sim(simulator_name, Nadc=8, Nrange=4, Navg=7, Nbin=6, DZ=3):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # declare circuit
    class dut(m.Circuit):
        name = 'calib_hist_measure'
        io = m.IO(rstb=m.BitIn,
                  clk=m.ClockIn,
                  update=m.BitIn,
                  din=m.In(m.SInt[Nadc]),
                  din_avg=m.In(m.SInt[Nadc]),
                  Nbin=m.In(m.Bits[Nrange]),
                  DZ=m.In(m.Bits[Nrange]),
                  flip_feedback=m.BitIn,
                  hist_center=m.Out(m.Bits[2**Nrange]),
                  hist_side=m.Out(m.Bits[2**Nrange]),
                  hist_comp_out=m.Out(m.SInt[2]))

    # create tester
    t = fault.Tester(dut, dut.clk)

    # define data vectors
    data_vecs = [
        [0] * (1 << Navg),
        [+13] * (1 << Navg),
        [-13] * (1 << Navg),
        [+25] * (1 << Navg),
        [-25] * (1 << Navg),
        [random.randint(-25, 25) for _ in range(1 << Navg)],
        [random.randint(0, 25) for _ in range(1 << Navg)],
        [random.randint(-25, 0) for _ in range(1 << Navg)],
    ]

    # define averaging test
    def run_hist(data):
        # first value
        t.poke(dut.update, 1)
        t.poke(dut.din, data[0])
        t.step(2)

        # middle values
        t.poke(dut.update, 0)
        for elem in data[1:]:
            t.poke(dut.din, elem)
            t.step(2)

        # get values for average and sum
        hist_center = t.get_value(dut.hist_center)
        hist_side = t.get_value(dut.hist_side)
        hist_comp_out = t.get_value(dut.hist_comp_out)

        return hist_center, hist_side, hist_comp_out

    # initialize
    t.zero_inputs()
    t.poke(dut.din_avg, 0)
    t.poke(dut.Nbin, Nbin)
    t.poke(dut.DZ, DZ)

    # run a few cycles
    t.step(10)
    t.poke(dut.rstb, 1)
    t.step(2)

    # run averaging trials
    results = []
    for k in range(len(data_vecs)):
        results.append(run_hist(data_vecs[k]))

    # run a few extra cycles for better visibility
    t.step(10)

    ##################
    # run simulation #
    ##################

    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=get_deps_cpu_sim(cell_name=dut.name),
                      parameters={
                          'Nadc': Nadc,
                          'Nrange': Nrange
                      },
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=False,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    ##################
    # convert values #
    ##################

    def to_signed(x, n):
        if x >= (1 << (n - 1)):
            return x - (1 << n)
        else:
            return x

    results = [(res[0].value, res[1].value, to_signed(res[2].value, 2))
               for res in results]

    print('results', results)

    ################
    # check values #
    ################

    for result, data_vec in zip(results, data_vecs):
        assert result == model(data=data_vec, Nbin=Nbin, DZ=DZ), \
            'Mismatch in measured vs. expected results.'

    ###################
    # declare success #
    ###################

    print('Success!')
def test_tx_data_gen(simulator_name,
                     dump_waveforms,
                     n_prbs=32,
                     n_ti=16,
                     sq_per=4,
                     pulse_per=3,
                     const_val=42,
                     prbs_eqn=0x100002):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # declare circuit
    class dut(m.Circuit):
        name = 'test'
        io = m.IO(clk=m.ClockIn,
                  rst=m.BitIn,
                  data_mode=m.In(m.Bits[3]),
                  data_per=m.In(m.Bits[16]),
                  data_in=m.In(m.Bits[n_ti]),
                  data_out=m.Out(m.Bits[n_ti]),
                  prbs_eqn=m.In(m.Bits[n_prbs]))

    # create tester
    t = fault.Tester(dut, dut.clk)

    # initialize with the right equation
    t.zero_inputs()
    t.poke(dut.rst, 1)
    t.poke(dut.data_mode, CONSTANT)
    t.poke(dut.data_in, const_val)
    t.poke(dut.prbs_eqn, prbs_eqn)

    # reset
    for _ in range(3):
        t.step(2)

    # run CONSTANT mode
    t.poke(dut.rst, 0)
    const_vals = []
    for _ in range(50):
        t.step(2)
        const_vals.append(t.get_value(dut.data_out))

    # reset
    t.poke(dut.rst, 1)
    for _ in range(3):
        t.step(2)

    # run PULSE mode
    t.poke(dut.rst, 0)
    t.poke(dut.data_mode, PULSE)
    t.poke(dut.data_in, 1)
    t.poke(dut.data_per, pulse_per - 1)
    pulse_vals = []
    for _ in range(50):
        t.step(2)
        pulse_vals.append(t.get_value(dut.data_out))

    # reset
    t.poke(dut.rst, 1)
    for _ in range(3):
        t.step(2)

    # run SQUARE mode
    t.poke(dut.rst, 0)
    t.poke(dut.data_mode, SQUARE)
    t.poke(dut.data_per, sq_per - 1)
    square_vals = []
    for _ in range(50):
        t.step(2)
        square_vals.append(t.get_value(dut.data_out))

    # reset
    t.poke(dut.rst, 1)
    for _ in range(3):
        t.step(2)

    # run PRBS mode
    t.poke(dut.rst, 0)
    t.poke(dut.data_mode, PRBS)
    prbs_vals = []
    for _ in range(50):
        t.step(2)
        prbs_vals.append(t.get_value(dut.data_out))

    # run the test
    ext_srcs = get_deps_cpu_sim(impl_file=THIS_DIR / 'test.sv')
    parameters = {'Nti': n_ti, 'Nprbs': n_prbs}
    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=ext_srcs,
                      parameters=parameters,
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=dump_waveforms,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    # process results
    const_vals = [x.value for x in const_vals]
    pulse_vals = [x.value for x in pulse_vals]
    square_vals = [x.value for x in square_vals]
    prbs_vals = [x.value for x in prbs_vals]

    # check constant results
    const_vals = const_vals[5:]
    assert all(x == const_val for x in const_vals)

    # check pulse results
    pulse_vals = pulse_vals[pulse_vals.index(1):]
    pulse_vals = pulse_vals[:(len(pulse_vals) // pulse_per) * pulse_per]
    assert pulse_vals == ([1] + [0] *
                          (pulse_per - 1)) * (len(pulse_vals) // pulse_per)

    # check square wave results
    sq_hi = (1 << n_ti) - 1
    sq_lo = 0
    square_vals = square_vals[square_vals.index(sq_hi):]
    square_vals = square_vals[:(len(square_vals) // (2 * sq_per)) *
                              (2 * sq_per)]
    assert square_vals == ([sq_hi] * sq_per +
                           [sq_lo] * sq_per) * (len(square_vals) //
                                                (2 * sq_per))

    # check PRBS results
    prbs_vals = prbs_vals[5:]  # first couple of values are invalid
    verify_prbs(prbs_vals=prbs_vals,
                prbs_eqn=prbs_eqn,
                n_ti=n_ti,
                n_prbs=n_prbs)

    # declare success
    print('Success!')
Example #6
0
def test_sim(simulator_name, ndiv, N=4, nper=5):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # declare circuit
    class dut(m.Circuit):
        name = 'avg_pulse_gen'
        io = m.IO(clk=m.ClockIn,
                  rstb=m.BitIn,
                  ndiv=m.In(m.Bits[N]),
                  out=m.BitOut)

    # create tester
    t = fault.Tester(dut, dut.clk)

    # initialize
    t.zero_inputs()
    t.poke(dut.ndiv, ndiv)

    # run a few cycles
    t.step(10)
    t.poke(dut.rstb, 1)

    # capture output
    results = []
    for k in range(nper * (2**ndiv)):
        results.append(t.get_value(dut.out))
        t.step(2)

    ##################
    # run simulation #
    ##################

    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=get_deps_cpu_sim(cell_name='avg_pulse_gen'),
                      parameters={
                          'N': N,
                      },
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=False,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    ##################
    # convert values #
    ##################

    results = [elem.value for elem in results]

    ################
    # check values #
    ################

    # trim initial zeros
    results = results[results.index(1):]

    # print the beginning of the list
    print('results', list_head(results))

    # trim to an integer number of periods
    nper_meas = len(results) // (2**ndiv)
    assert nper_meas >= (nper - 1), 'Not enough output periods observed.'
    results = results[:nper_meas * (2**ndiv)]

    # check that results match expectations
    expct = []
    for _ in range(nper_meas):
        expct += [1]
        expct += [0] * ((2**ndiv) - 1)

    # compare observed and expected outputs
    assert results == expct, 'Mismatch in measured vs. expected outputs.'

    ###################
    # declare success #
    ###################

    print('Success!')
def test_sim(simulator_name, n_data=8, n_count=64):
    # set the random seed for repeatable results
    seed(1)

    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # determine the stimulus vector
    counts = [randint(0, 4) for _ in range(1 << n_data)]
    data_vec = []
    for k, count in enumerate(counts):
        data_vec += [k] * count
    shuffle(data_vec)

    # declare circuit
    class dut(m.Circuit):
        name = 'histogram'
        io = m.IO(clk=m.ClockIn,
                  sram_ceb=m.BitIn,
                  mode=m.In(m.Bits[3]),
                  data=m.In(m.Bits[n_data]),
                  addr=m.In(m.Bits[n_data]),
                  count=m.Out(m.Bits[n_count]),
                  total=m.Out(m.Bits[n_count]))

    # create tester
    t = fault.Tester(dut, dut.clk)

    # initialize inputs
    t.zero_inputs()
    t.poke(dut.data, data_vec[0])

    # run a few cycles
    t.step(10)

    # clear the memory
    t.poke(dut.mode, CLEAR)
    t.step(2 * 300)

    # write values
    t.poke(dut.mode, RUN)
    for elem in data_vec[1:]:
        t.poke(dut.data, elem)
        t.step(2)

    # poke one final value
    # (will not be included in histogram)
    t.poke(dut.data, 0)
    t.step(2)

    # read values
    t.poke(dut.mode, FREEZE)

    results = []
    for k in range(1 << n_data):
        t.poke(dut.addr, k)
        t.step(8)
        results.append(t.get_value(dut.count))

    total = t.get_value(dut.total)

    # run the test
    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=get_deps_cpu_sim(cell_name='histogram'),
                      parameters={
                          'n_data': n_data,
                          'n_count': n_count
                      },
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=False,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    # convert results
    results = [result.value for result in results]
    total = total.value

    # print results
    print(f'total: {total}')
    print(f'results: {results}')

    # check results
    assert sum(
        results) == total, 'Mismatch between sum of bins and reported total.'
    assert sum(counts) == total, 'Total number of counts is unexpected.'
    assert counts == results, 'Mismatch in one or more histogram bins.'

    # declare success
    print('Success!')
Example #8
0
step_both()

# read out bits from "a"
hist_a = []
for _ in range(100 * 16):
    hist_a.append(t.get_value(dut.out_a))
    step_a()

# read out bits from "b"
hist_b = []
for _ in range(100):
    hist_b.append(t.get_value(dut.out_b))
    step_b()

# run the simulation
ext_srcs = get_deps_cpu_sim(impl_file=THIS_DIR / 'test.sv')
t.compile_and_run(target='system-verilog',
                  directory=BUILD_DIR,
                  simulator='iverilog',
                  ext_srcs=ext_srcs,
                  ext_model_file=True,
                  disp_type='realtime',
                  dump_waveforms=True)

# extract values
hist_a = [elem.value for elem in hist_a]
hist_b = [elem.value for elem in hist_b]

# post-process hist_b so that it can be directly compared with hist_a
hist_b_post = []
for elem in hist_b:
def test_ext_offset(simulator_name, offset):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # create tester
    t = fault.Tester(dut, dut.clk)

    # initialize
    t.zero_inputs()
    t.poke(dut.en_pfd_cal, 0)
    t.poke(dut.en_ext_pfd_offset, 1)
    t.poke(dut.ext_pfd_offset, offset)
    t.poke(dut.Nbin, Nbin)
    t.poke(dut.Navg, Navg)
    t.poke(dut.DZ, DZ)

    # run a few cycles
    t.step(10)
    t.poke(dut.rstb, 1)
    t.step(2)

    # send in data
    data_in = []
    data_out = []
    for k in range(-((1 << Nadc) - 1), 1 << Nadc):
        data_in.append(k)
        sgn, mag = adc_model(k, offset=offset)
        t.poke(dut.sign_out, sgn)
        t.poke(dut.din, mag)
        t.step(2)
        data_out.append(t.get_value(dut.dout))

    # run a few extra cycles for better visibility
    t.step(10)

    ##################
    # run simulation #
    ##################

    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=get_deps_cpu_sim(cell_name=dut.name),
                      parameters={
                          'Nadc': Nadc,
                          'Nrange': Nrange
                      },
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=False,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    ##################
    # convert values #
    ##################

    def to_signed(x, n):
        if x >= (1 << (n - 1)):
            return x - (1 << n)
        else:
            return x

    data_out = [to_signed(elem.value, Nadc) for elem in data_out]

    ################
    # check values #
    ################

    for x, y in zip(data_in, data_out):
        if x <= -(1 << (Nadc - 1)):
            assert y == -(1 << (Nadc - 1))
        elif x >= (1 << (Nadc - 1)) - 1:
            assert y == (1 << (Nadc - 1)) - 1
        else:
            assert x == y

    ###################
    # declare success #
    ###################

    print('Success!')
def test_int_offset(simulator_name, offset, init):
    # set defaults
    if simulator_name is None:
        if shutil.which('iverilog'):
            simulator_name = 'iverilog'
        else:
            simulator_name = 'ncsim'

    # create tester
    t = fault.Tester(dut, dut.clk)

    # initialize
    t.zero_inputs()
    t.poke(dut.en_pfd_cal, 0)
    t.poke(dut.en_ext_pfd_offset, 0)
    t.poke(dut.ext_pfd_offset, init)
    t.poke(dut.Nbin, Nbin)
    t.poke(dut.Navg, Navg)
    t.poke(dut.DZ, DZ)

    # run a few cycles
    t.step(10)
    t.poke(dut.rstb, 1)
    t.step(2)

    # run one update cycle
    t.poke(dut.update, 1)
    t.step(2)
    t.poke(dut.update, 0)
    t.step(2)

    # send in data
    n_data = 25 * (1 << Navg)
    data_in = [
        int(round(100 * sin(2 * pi * n / 123.456))) for n in range(n_data)
    ]
    data_out = []

    t.poke(dut.en_pfd_cal, 1)
    for k in range(n_data):
        # manage the update pulse
        if k % (1 << Navg) == 0:
            t.poke(dut.update, 1)
        else:
            t.poke(dut.update, 0)

        # send in the data
        sgn, mag = adc_model(data_in[k], offset=offset)
        t.poke(dut.sign_out, sgn)
        t.poke(dut.din, mag)
        t.step(2)
        data_out.append(t.get_value(dut.dout))

    # read out the pfd offset
    pfd_offset = t.get_value(dut.pfd_offset)

    # run a few extra cycles for better visibility
    t.step(10)

    ##################
    # run simulation #
    ##################

    t.compile_and_run(target='system-verilog',
                      simulator=simulator_name,
                      ext_srcs=get_deps_cpu_sim(cell_name=dut.name),
                      parameters={
                          'Nadc': Nadc,
                          'Nrange': Nrange
                      },
                      ext_model_file=True,
                      disp_type='realtime',
                      dump_waveforms=False,
                      directory=BUILD_DIR,
                      num_cycles=1e12)

    ##################
    # convert values #
    ##################

    def to_signed(x, n):
        if x >= (1 << (n - 1)):
            return x - (1 << n)
        else:
            return x

    pfd_offset = to_signed(pfd_offset.value, Nadc)

    print('pfd_offset', pfd_offset)

    data_out = [to_signed(elem.value, Nadc) for elem in data_out]

    ################
    # check values #
    ################

    assert int_is_close(pfd_offset, offset), 'Estimated pfd_offset is wrong.'

    for x, y in zip(data_in[-1000:], data_out[-1000:]):
        assert int_is_close(x, y), 'Mismatch in input and output data'

    ###################
    # declare success #
    ###################

    print('Success!')