Example #1
0
def get_deps_fpga_emu(cell_name=None, impl_file=None, override=None):
    # set defaults
    if override is None:
        override = {}

    deps = []
    deps += get_deps(cell_name=cell_name,
                     impl_file=impl_file,
                     view_order=['fpga_models', 'pack', 'chip_src'],
                     includes=[
                         get_dir('inc/fpga'),
                         svreal.get_svreal_header().parent,
                         msdsl.get_msdsl_header().parent
                     ],
                     defines={
                         'DT_WIDTH': 25,
                         'DT_EXPONENT': -46,
                         'VIVADO': None
                     },
                     skip={
                         'svreal', 'assign_real', 'comp_real', 'add_sub_real',
                         'ite_real', 'dff_real', 'mul_real', 'mem_digital',
                         'sync_rom_real', 'DW_tap'
                     },
                     no_descend={
                         'chan_core', 'tx_core', 'osc_model_core',
                         'clk_delay_core', 'rx_adc_core', 'analog_slice'
                     },
                     override=override)

    return deps
Example #2
0
    def compile_and_run(self,
                        target='system-verilog',
                        ext_srcs=None,
                        inc_dirs=None,
                        ext_model_file=True,
                        tmp_dir=None,
                        disp_type=None,
                        real_type=RealType.FixedPoint,
                        defines=None,
                        **kwargs):
        # set defaults
        if ext_srcs is None:
            ext_srcs = []
        if inc_dirs is None:
            inc_dirs = []
        if tmp_dir is None:
            tmp_dir = not self.debug_mode
        if disp_type is None:
            disp_type = 'on_error' if (not self.debug_mode) else 'realtime'
        if defines is None:
            defines = {}

        # add to ext_srcs
        if real_type == RealType.HardFloat:
            ext_srcs = get_hard_float_sources() + ext_srcs

        # add to inc_dirs
        inc_dirs = [get_svreal_header().parent,
                    get_msdsl_header().parent] + inc_dirs
        if real_type == RealType.HardFloat:
            inc_dirs = get_hard_float_inc_dirs() + inc_dirs

        # add defines as needed for the real number type
        defines = defines.copy()
        if real_type == RealType.FixedPoint:
            pass
        elif real_type == RealType.FloatReal:
            defines['FLOAT_REAL'] = None
        elif real_type == RealType.HardFloat:
            defines['HARD_FLOAT'] = None

        # call the command
        super().compile_and_run(target='system-verilog',
                                ext_srcs=ext_srcs,
                                inc_dirs=inc_dirs,
                                defines=defines,
                                ext_model_file=ext_model_file,
                                tmp_dir=tmp_dir,
                                disp_type=disp_type,
                                **kwargs)
def test_clk_delay(simulator_name, float_real):
    # set defaults
    if simulator_name is None:
        simulator_name = 'vivado'

    # declare circuit
    class dut(m.Circuit):
        name = 'test_clk_delay'
        io = m.IO(code=m.In(m.Bits[N_BITS]),
                  clk_i_val=m.BitIn,
                  clk_o_val=m.BitOut,
                  dt_req=fault.RealIn,
                  emu_dt=fault.RealOut,
                  jitter_seed=m.In(m.Bits[32]),
                  jitter_rms=fault.RealIn,
                  emu_clk=m.In(m.Clock),
                  emu_rst=m.BitIn)

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

    # utility function for easier waveform debug
    def check_result(emu_dt, clk_val, abs_tol=DEL_PREC):
        t.delay((TCLK / 2) - DELTA)
        t.poke(dut.emu_clk, 0)
        t.delay(TCLK / 2)
        t.expect(dut.emu_dt, emu_dt, abs_tol=abs_tol)
        t.expect(dut.clk_o_val, clk_val)
        t.poke(dut.emu_clk, 1)
        t.delay(DELTA)

    # compute nominal delay
    del_nom = (DEL_CODE / (2.0**N_BITS)) * T_PER

    # initialize
    t.zero_inputs()
    t.poke(dut.code, DEL_CODE)
    t.poke(dut.emu_rst, 1)

    # apply reset
    t.poke(dut.emu_clk, 1)
    t.delay(TCLK / 2)
    t.poke(dut.emu_clk, 0)
    t.delay(TCLK / 2)

    # clear reset
    t.poke(dut.emu_rst, 0)

    # run a few cycles
    for _ in range(3):
        t.poke(dut.emu_clk, 1)
        t.delay(TCLK / 2)
        t.poke(dut.emu_clk, 0)
        t.delay(TCLK / 2)
    t.poke(dut.emu_clk, 1)
    t.delay(DELTA)

    # raise clock val
    t.poke(dut.clk_i_val, 1)
    t.poke(dut.dt_req, (0.123e-9) / 4)
    check_result((0.123e-9) / 4, 0)

    # wait some time (expect dt_req ~ 0.1 ns)
    t.poke(dut.clk_i_val, 1)
    t.poke(dut.dt_req, 0.234e-9)
    check_result(del_nom, 1)

    # lower clk_val, wait some time (expect dt_req ~ 0.345 ns)
    t.poke(dut.clk_i_val, 0)
    t.poke(dut.dt_req, (0.345e-9) / 4)
    check_result((0.345e-9) / 4, 1)

    # wait some time (expect dt_req ~ 0.1 ns)
    t.poke(dut.clk_i_val, 0)
    t.poke(dut.dt_req, (0.456e-9) / 4)
    check_result(del_nom, 0)

    # raise clk_val, wait some time (expect dt_req ~ 0.567 ns)
    t.poke(dut.clk_i_val, 1)
    t.poke(dut.dt_req, (0.567e-9) / 4)
    check_result((0.567e-9) / 4, 0)

    # wait some time (expect dt_req ~ 0.1 ns)
    t.poke(dut.clk_i_val, 1)
    t.poke(dut.dt_req, (0.678e-9) / 4)
    check_result(del_nom, 1)

    # lower clk_val, wait some time (expect dt_req ~ 0.789 ns)
    t.poke(dut.clk_i_val, 0)
    t.poke(dut.dt_req, (0.789e-9) / 4)
    check_result((0.789e-9) / 4, 1)

    # run the simulation
    defines = {'DT_WIDTH': 25, 'DT_EXPONENT': -46}
    if float_real:
        defines['FLOAT_REAL'] = None
    t.compile_and_run(
        target='system-verilog',
        directory=BUILD_DIR,
        simulator=simulator_name,
        ext_srcs=[
            get_file('build/fpga_models/clk_delay_core/clk_delay_core.sv'),
            get_file('tests/fpga_block_tests/clk_delay/test_clk_delay.sv')
        ],
        inc_dirs=[get_svreal_header().parent,
                  get_msdsl_header().parent],
        ext_model_file=True,
        defines=defines,
        disp_type='realtime')
def test_chan_model(simulator_name):
    # set defaults
    if simulator_name is None:
        simulator_name = 'vivado'

    # declare circuit
    class dut(m.Circuit):
        name = 'test_chan_model'
        io = m.IO(in_=fault.RealIn,
                  out=fault.RealOut,
                  dt_sig=fault.RealIn,
                  clk=m.In(m.Clock),
                  cke=m.BitIn,
                  rst=m.BitIn,
                  wdata0=m.In(m.Bits[CFG['func_widths'][0]]),
                  wdata1=m.In(m.Bits[CFG['func_widths'][1]]),
                  waddr=m.In(m.Bits[int(ceil(log2(CFG['func_numel'])))]),
                  we=m.BitIn)

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

    def cycle(k=1):
        for _ in range(k):
            t.delay(TPER / 2 - DELTA)
            t.poke(dut.clk, 0)
            t.delay(TPER / 2)
            t.poke(dut.clk, 1)
            t.delay(DELTA)

    # initialize
    t.zero_inputs()
    t.poke(dut.rst, 1)
    cycle()
    t.poke(dut.rst, 0)

    # initialize step response functions
    placeholder = PlaceholderFunction(domain=CFG['func_domain'],
                                      order=CFG['func_order'],
                                      numel=CFG['func_numel'],
                                      coeff_widths=CFG['func_widths'],
                                      coeff_exps=CFG['func_exps'])
    coeffs_bin = placeholder.get_coeffs_bin_fmt(CHAN.interp)
    t.poke(dut.we, 1)
    for i in range(placeholder.numel):
        t.poke(dut.wdata0, coeffs_bin[0][i])
        t.poke(dut.wdata1, coeffs_bin[1][i])
        t.poke(dut.waddr, i)
        cycle()
    t.poke(dut.we, 0)

    # values
    val1 = +1.23
    val2 = -2.34
    val3 = +3.45

    # timesteps
    dt0 = (1e-9) / 16
    dt1 = (2e-9) / 16
    dt2 = (3e-9) / 16
    dt3 = (4e-9) / 16
    dt4 = (5e-9) / 16
    dt5 = (6e-9) / 16
    dt6 = (7e-9) / 16
    dt7 = (8e-9) / 16
    dt8 = (9e-9) / 16

    # action sequence
    t.poke(dut.cke, 0)
    t.poke(dut.dt_sig, dt0)
    t.poke(dut.in_, 0.0)
    cycle()

    t.poke(dut.cke, 1)
    t.poke(dut.dt_sig, dt1)
    t.poke(dut.in_, 0.0)
    cycle()
    meas1 = t.get_value(dut.out)

    t.poke(dut.cke, 0)
    t.poke(dut.dt_sig, dt2)
    t.poke(dut.in_, val1)
    cycle()
    meas2 = t.get_value(dut.out)

    t.poke(dut.cke, 0)
    t.poke(dut.dt_sig, dt3)
    t.poke(dut.in_, val1)
    cycle()
    meas3 = t.get_value(dut.out)

    t.poke(dut.cke, 1)
    t.poke(dut.dt_sig, dt4)
    t.poke(dut.in_, val1)
    cycle()
    meas4 = t.get_value(dut.out)

    t.poke(dut.cke, 0)
    t.poke(dut.dt_sig, dt5)
    t.poke(dut.in_, val2)
    cycle()
    meas5 = t.get_value(dut.out)

    t.poke(dut.cke, 1)
    t.poke(dut.dt_sig, dt6)
    t.poke(dut.in_, val2)
    cycle()
    meas6 = t.get_value(dut.out)

    t.poke(dut.cke, 0)
    t.poke(dut.dt_sig, dt7)
    t.poke(dut.in_, val3)
    cycle()
    meas7 = t.get_value(dut.out)

    t.poke(dut.cke, 0)
    t.poke(dut.dt_sig, dt8)
    t.poke(dut.in_, val3)
    cycle()
    meas8 = t.get_value(dut.out)

    # compute expected outputs
    chan = Filter.from_file(get_file('build/chip_src/adapt_fir/chan.npy'))
    f = chan.interp
    expt1 = 0
    expt2 = val1 * f(dt2)
    expt3 = val1 * f(dt2 + dt3)
    expt4 = val1 * f(dt2 + dt3 + dt4)
    expt5 = val1 * (f(dt2 + dt3 + dt4 + dt5) - f(dt5)) + val2 * f(dt5)
    expt6 = val1 * (f(dt2 + dt3 + dt4 + dt5 + dt6) -
                    f(dt5 + dt6)) + val2 * f(dt5 + dt6)
    expt7 = (val1 *
             (f(dt2 + dt3 + dt4 + dt5 + dt6 + dt7) - f(dt5 + dt6 + dt7)) +
             val2 * (f(dt5 + dt6 + dt7) - f(dt7)) + val3 * f(dt7))

    # define parameters
    parameters = {
        'width0': CFG['func_widths'][0],
        'width1': CFG['func_widths'][1],
        'naddr': int(ceil(log2(CFG['func_numel'])))
    }

    # run the simulation
    t.compile_and_run(
        target='system-verilog',
        directory=BUILD_DIR,
        simulator=simulator_name,
        ext_srcs=[
            get_file('build/fpga_models/chan_core/chan_core.sv'),
            get_file('tests/fpga_block_tests/chan_model/test_chan_model.sv')
        ],
        inc_dirs=[get_svreal_header().parent,
                  get_msdsl_header().parent],
        ext_model_file=True,
        disp_type='realtime',
        parameters=parameters,
        dump_waveforms=False,
        timescale='1ns/1ps',
        num_cycles=1e12)

    # check outputs
    def check_output(name, meas, expct, abs_tol=0.001):
        print(f'checking {name}: measured {meas.value}, expected {expct}')
        if (expct - abs_tol) <= meas.value <= (expct + abs_tol):
            print('OK')
        else:
            raise Exception('Failed')

    check_output('expr1', meas1, expt1)
    check_output('expr2', meas2, expt2)
    check_output('expr3', meas3, expt3)
    check_output('expr4', meas4, expt4)
    check_output('expr5', meas5, expt5)
    check_output('expr6', meas6, expt6)
    check_output('expr7', meas7, expt7)
Example #5
0
def test_analog_slice(simulator_name, slice_offset, dump_waveforms, num_tests=100):
    # set seed for repeatable behavior
    random.seed(0)

    # set defaults
    if simulator_name is None:
        simulator_name = 'vivado'

    # determine the real-number formatting
    real_type = get_dragonphy_real_type()
    if real_type in {RealType.FixedPoint, RealType.FloatReal}:
        func_widths = CFG['func_widths']
    elif real_type == RealType.HardFloat:
        func_widths = [DEF_HARD_FLOAT_WIDTH, DEF_HARD_FLOAT_WIDTH]
    else:
        raise Exception('Unsupported RealType.')

    # declare circuit
    class dut(m.Circuit):
        name = 'test_analog_slice'
        io = m.IO(
            chunk=m.In(m.Bits[CFG['chunk_width']]),
            chunk_idx=m.In(m.Bits[int(ceil(log2(CFG['num_chunks'])))]),
            pi_ctl=m.In(m.Bits[CFG['pi_ctl_width']]),
            slice_offset=m.In(m.Bits[int(ceil(log2(CFG['slices_per_bank'])))]),
            sample_ctl=m.BitIn,
            incr_sum=m.BitIn,
            write_output=m.BitIn,
            out_sgn=m.BitOut,
            out_mag=m.Out(m.Bits[CFG['n_adc']]),
            clk=m.BitIn,
            rst=m.BitIn,
            jitter_rms=fault.RealIn,
            noise_rms=fault.RealIn,
            wdata0=m.In(m.Bits[func_widths[0]]),
            wdata1=m.In(m.Bits[func_widths[1]]),
            waddr=m.In(m.Bits[9]),
            we=m.BitIn
        )

    # create the tester
    t = fault.Tester(dut)

    def cycle(k=1):
        for _ in range(k):
            t.delay(TPER/2 - DELTA)
            t.poke(dut.clk, 0)
            t.delay(TPER/2)
            t.poke(dut.clk, 1)
            t.delay(DELTA)

    def to_bv(lis):
        return int(''.join(str(elem) for elem in lis), 2)

    # build up a list of test cases
    test_cases = []
    for x in range(num_tests):
        pi_ctl = random.randint(0, (1 << CFG['pi_ctl_width']) - 1)
        all_bits = [random.randint(0, 1) for _ in range(CFG['chunk_width'] * CFG['num_chunks'])]
        test_cases.append([pi_ctl, all_bits])

    # initialize
    # two cycles of reset -- one to reset DFFs, then another to read out ROM values
    # after the addresses are no longer X
    t.zero_inputs()
    t.poke(dut.slice_offset, slice_offset)
    t.poke(dut.rst, 1)
    cycle(2)
    t.poke(dut.rst, 0)

    # initialize step response functions
    placeholder = PlaceholderFunction(domain=CFG['func_domain'], order=CFG['func_order'],
                                      numel=CFG['func_numel'], coeff_widths=CFG['func_widths'],
                                      coeff_exps=CFG['func_exps'], real_type=real_type)
    coeffs_bin = placeholder.get_coeffs_bin_fmt(CHAN.interp)
    t.poke(dut.we, 1)
    for i in range(placeholder.numel):
        t.poke(dut.wdata0, coeffs_bin[0][i])
        t.poke(dut.wdata1, coeffs_bin[1][i])
        t.poke(dut.waddr, i)
        cycle()
    t.poke(dut.we, 0)
    
    # f cycle
    t.poke(dut.chunk, 0)
    t.poke(dut.chunk_idx, 0)
    t.poke(dut.pi_ctl, test_cases[0][0])
    t.poke(dut.sample_ctl, 1)
    t.poke(dut.incr_sum, 1)
    t.poke(dut.write_output, 1)
    cycle()

    # loop through test cases
    for i in range(num_tests):
        for j in range(2+CFG['num_chunks']):
            if j < CFG['num_chunks']:
                t.poke(dut.chunk, to_bv(test_cases[i][1][(j*CFG['chunk_width']):((j+1)*CFG['chunk_width'])]))
                t.poke(dut.chunk_idx, j)
            else:
                t.poke(dut.chunk, 0)
                t.poke(dut.chunk_idx, 0)

            if j != (CFG['num_chunks']+1):
                t.poke(dut.sample_ctl, 0)
                t.poke(dut.write_output, 0)
            else:
                if i != (num_tests-1):
                    t.poke(dut.pi_ctl, test_cases[i+1][0])
                t.poke(dut.sample_ctl, 1)
                t.poke(dut.write_output, 1)

            if j != 1:
                t.poke(dut.incr_sum, 1)
            else:
                t.poke(dut.incr_sum, 0)

            cycle()

        # gather results
        test_cases[i].extend([t.get_value(dut.out_sgn), t.get_value(dut.out_mag)])

    # define macros
    defines = {}

    # include directories
    inc_dirs = [
        get_svreal_header().parent,
        get_msdsl_header().parent
    ]

    # source files
    ext_srcs = [
        get_file('build/fpga_models/analog_slice/analog_slice.sv'),
        THIS_DIR / 'test_analog_slice.sv'
    ]

    # adjust for HardFloat if needed
    if real_type == RealType.HardFloat:
        ext_srcs = get_hard_float_sources() + ext_srcs
        inc_dirs = get_hard_float_inc_dirs() + inc_dirs
        defines['HARD_FLOAT'] = None
        defines['FUNC_DATA_WIDTH'] = DEF_HARD_FLOAT_WIDTH

    # waveform dumping options
    flags = []
    if simulator_name == 'ncsim':
        flags += ['-unbuffered']

    # run the simulation
    t.compile_and_run(
        target='system-verilog',
        directory=BUILD_DIR,
        simulator=simulator_name,
        defines=defines,
        inc_dirs=inc_dirs,
        ext_srcs=ext_srcs,
        parameters={
            'chunk_width': CFG['chunk_width'],
            'num_chunks': CFG['num_chunks']
        },
        ext_model_file=True,
        disp_type='realtime',
        dump_waveforms=dump_waveforms,
        flags=flags,
        timescale='1fs/1fs',
        num_cycles=1e12
    )

    # process the results
    for k, (pi_ctl, all_bits, sgn_meas, mag_meas) in enumerate(test_cases):
        # compute the expected ADC value
        analog_sample = channel_model(slice_offset, pi_ctl, all_bits)
        sgn_expct, mag_expct = adc_model(analog_sample)

        # print measured and expected
        print(f'Test case #{k}: slice_offset={slice_offset}, pi_ctl={pi_ctl}, all_bits={all_bits}')
        print(f'[measured] sgn: {sgn_meas.value}, mag: {mag_meas.value}')
        print(f'[expected] sgn: {sgn_expct}, mag: {mag_expct}, analog_sample: {analog_sample}')

        # check result
        check_adc_result(sgn_meas.value, mag_meas.value, sgn_expct, mag_expct)

    # declare success
    print('Success!')
Example #6
0
def test_analog_core(simulator_name, dump_waveforms, num_tests=100):
    # set seed for repeatable behavior
    random.seed(0)

    # set defaults
    if simulator_name is None:
        simulator_name = 'vivado'

    # determine the real-number formatting
    real_type = get_dragonphy_real_type()
    if real_type in {RealType.FixedPoint, RealType.FloatReal}:
        func_widths = CFG['func_widths']
    elif real_type == RealType.HardFloat:
        func_widths = [DEF_HARD_FLOAT_WIDTH, DEF_HARD_FLOAT_WIDTH]
    else:
        raise Exception('Unsupported RealType.')

    # set up the IO definitions
    io_dict = {}
    io_dict['bits'] = m.In(m.Bits[16])
    for k in range(4):
        io_dict[f'ctl_pi_{k}'] = m.In(m.Bits[9])
    for k in range(16):
        io_dict[f'adder_out_{k}'] = m.Out(m.Bits[8])
    io_dict.update(dict(
        sign_out=m.Out(m.Bits[16]),
        clk=m.BitIn,
        rst= m.BitIn,
        jitter_rms_int= m.In(m.Bits[7]),
        noise_rms_int= m.In(m.Bits[11]),
        chan_wdata_0=m.In(m.Bits[func_widths[0]]),
        chan_wdata_1=m.In(m.Bits[func_widths[1]]),
        chan_waddr=m.In(m.Bits[9]),
        chan_we=m.BitIn
    ))

    # declare circuit
    class dut(m.Circuit):
        name = 'test_analog_core'
        io = m.IO(**io_dict)

    # create the tester
    t = fault.Tester(dut)

    def cycle(k=1):
        for _ in range(k):
            t.delay(TPER/2 - DELTA)
            t.poke(dut.clk, 0)
            t.delay(TPER/2)
            t.poke(dut.clk, 1)
            t.delay(DELTA)

    def to_bv(lis):
        return int(''.join(str(elem) for elem in lis), 2)

    def poke_bits(bits):
        t.poke(dut.bits, to_bv(bits))

    def poke_pi_ctl(pi_ctl):
        for k in range(4):
            t.poke(getattr(dut, f'ctl_pi_{k}'), pi_ctl[k])

    def get_adder_out():
        retval = []
        for k in range(16):
            retval.append(t.get_value(getattr(dut, f'adder_out_{k}')))
        return retval

    # build up a list of test cases
    test_cases = []
    for x in range(num_tests):
        pi_ctl = [random.randint(0, (1 << CFG['pi_ctl_width']) - 1) for _ in range(4)]
        new_bits = [random.randint(0, 1) for _ in range(16)]
        test_cases.append([pi_ctl, new_bits])

    # initialize
    t.zero_inputs()
    t.poke(dut.rst, 1)
    cycle(2)
    t.poke(dut.rst, 0)
    for j in range(1 + CFG['num_chunks']):
        cycle()

    # initialize step response functions
    placeholder = PlaceholderFunction(domain=CFG['func_domain'], order=CFG['func_order'],
                                      numel=CFG['func_numel'], coeff_widths=CFG['func_widths'],
                                      coeff_exps=CFG['func_exps'], real_type=real_type)
    coeffs_bin = placeholder.get_coeffs_bin_fmt(CHAN.interp)
    t.poke(dut.chan_we, 1)
    for i in range(placeholder.numel):
        t.poke(dut.chan_wdata_0, coeffs_bin[0][i])
        t.poke(dut.chan_wdata_1, coeffs_bin[1][i])
        t.poke(dut.chan_waddr, i)
        cycle()
    t.poke(dut.chan_we, 0)

    # run test cases
    results = []
    for pi_ctl, new_bits in test_cases:
        poke_bits(new_bits)
        poke_pi_ctl(pi_ctl)
        for j in range(2+CFG['num_chunks']):
            cycle()
        results.append([t.get_value(dut.sign_out), get_adder_out()])

    # run a few cycles at the end for better waveform visibility
    cycle(5)

    # define macros
    defines = {
        'FPGA_MACRO_MODEL': True,
        'CHUNK_WIDTH': CFG['chunk_width'],
        'NUM_CHUNKS': CFG['num_chunks']
    }

    # include directories
    inc_dirs = [
        get_svreal_header().parent,
        get_msdsl_header().parent,
        get_dir('inc/fpga')
    ]

    # source files
    ext_srcs = get_deps_fpga_emu(impl_file=THIS_DIR/'test_analog_core.sv')

    # adjust for HardFloat if needed
    if real_type == RealType.HardFloat:
        ext_srcs = get_hard_float_sources() + ext_srcs
        inc_dirs = get_hard_float_inc_dirs() + inc_dirs
        defines['HARD_FLOAT'] = None
        defines['FUNC_DATA_WIDTH'] = DEF_HARD_FLOAT_WIDTH

    # waveform dumping options
    flags = []
    if simulator_name == 'ncsim':
        flags += ['-unbuffered']
    if dump_waveforms:
        defines['DUMP_WAVEFORMS'] = None
        if simulator_name == 'ncsim':
            flags += ['-access', '+r']

    # run the simulation
    t.compile_and_run(
        target='system-verilog',
        directory=BUILD_DIR,
        simulator=simulator_name,
        defines=defines,
        inc_dirs=inc_dirs,
        ext_srcs=ext_srcs,
        ext_model_file=True,
        disp_type='realtime',
        dump_waveforms=False,
        flags=flags,
        timescale='1fs/1fs',
        num_cycles=1e12
    )

    # process the results
    for k in range(1, len(test_cases)-1):
        # extract out parameters
        pi_ctl, new_bits = test_cases[k]
        prev_bits = test_cases[k-1][1]

        # compute the expected ADC value
        analog_sample, sgn_expct, mag_expct = [], [], []
        all_bits = new_bits + prev_bits
        for idx in range(16):
            # determine the analog value sampled on this channel
            analog_sample.append(channel_model(idx%4, pi_ctl[idx//4], all_bits))

            # determine what the ADC output should be
            adc_out = adc_model(analog_sample[-1])
            sgn_expct.append(adc_out[0])
            mag_expct.append(adc_out[1])

        # extract out results
        sgn_meas = [(results[k+1][0].value >> idx) & 1 for idx in range(16)]
        mag_meas = [elem.value for elem in results[k+1][1]]

        # print measured and expected
        print(f'Test case #{k}: pi_ctl={pi_ctl}, all_bits={new_bits}')
        print(f'[measured] sgn: {sgn_meas}, mag: {mag_meas}')
        print(f'[expected] sgn: {sgn_expct}, mag: {mag_expct}, analog_sample: {analog_sample}')

        # check results
        for sm, mm, se, me in zip(sgn_meas, mag_meas, sgn_expct, mag_expct):
            check_adc_result(sm, mm, se, me)

    # declare success
    print('Success!')
Example #7
0
def test_adc_model(simulator_name, should_print=False):
    # set defaults
    if simulator_name is None:
        simulator_name = 'vivado'

    # declare circuit
    class dut(m.Circuit):
        name = 'test_adc_model'
        io = m.IO(
            in_=fault.RealIn,
            clk_val=m.BitIn,
            out_mag=m.Out(m.Bits[CFG['n']]),
            out_sgn=m.BitOut,
            noise_seed=m.In(m.Bits[32]),
            noise_rms=fault.RealIn,
            emu_rst=m.BitIn,
            emu_clk=m.ClockIn
        )

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

    # initialize
    t.zero_inputs()
    t.poke(dut.emu_rst, 1)
    t.step(4)

    # clear reset
    t.poke(dut.emu_rst, 0)
    t.step(4)

    # create mechanism to run trials
    def run_trial(in_):
        # set input
        t.poke(dut.in_, in_)
        t.step(4)

        # toggle clock
        t.poke(dut.clk_val, 1)
        t.step(4)
        t.poke(dut.clk_val, 0)
        t.step(4)

        # print output if desired
        if should_print:
            t.print('in_: %0f, out_sgn: %0d, out_mag: %0d\n',
                    dut.in_, dut.out_sgn, dut.out_mag)

        # get expected output
        expct_sgn, expct_mag = model(in_=in_)

        # check results
        t.expect(dut.out_sgn, expct_sgn)
        t.expect(dut.out_mag, expct_mag)

    # specify trials to be run
    delta = 0.1*CFG['vref']
    for in_ in np.linspace(-CFG['vref']-delta, CFG['vref']+delta, 100):
        run_trial(in_=in_)

    # run the simulation
    t.compile_and_run(
        target='system-verilog',
        directory=BUILD_DIR,
        simulator=simulator_name,
        ext_srcs=[get_file('build/fpga_models/rx_adc_core/rx_adc_core.sv'),
                  get_file('tests/fpga_block_tests/adc_model/test_adc_model.sv')],
        inc_dirs=[get_svreal_header().parent, get_msdsl_header().parent],
        ext_model_file=True,
        disp_type='realtime',
        parameters={'n': CFG['n']},
        dump_waveforms=False
    )