Example #1
0
def getFPGADict(simulation):
    """
    getFPGADict: Illustration of conversion of user-defined physics values
    (contained in the simulation object, which is obtained from the JSON parser)
    and the FPGA register values, contained in the output dictionary
    linac_reg_dict.  error_cnt is an error count reported from the
    floating-point to fix-point arithmetic conversions and scaling.
    """

    from read_regmap import get_map
    regmap = get_map(base_dir + "/../_autogen/regmap_cryomodule.json")
    c_reg_base = get_reg_info(regmap, [],
                              'llrf_' + str(0) + '_xxxx')['base_addr']

    # Initialize empty FPGA register objects
    simulation.Init_FPGA_Registers(regmap, [])

    # Compute FPGA register values based on configuration parameters
    flat_reg_dict, error_cnt = simulation.Compute_FPGA_Registers()

    # Replace computed values directly in register map
    for key, value in flat_reg_dict.iteritems():
        regmap[key] = value

    # Make sure all values are Register instances
    for key, value in regmap.iteritems():
        if not isinstance(value, Register):
            regmap[key] = Register(**value)

    return regmap, error_cnt, c_reg_base
Example #2
0
    def init_llrf_settings(self):
	temp = get_map(os.path.join(base_dir, 'parameters/llrf_core_expand.json'))
	temp = temp['cryomodule']['regmap']
	self.app_reg_prefix = 'cryomodule_'

        self.wave_samp_per_name = get_reg_info(temp, [0], 'wave_samp_per')['name'].replace(self.app_reg_prefix, '')
        self.wave_shift_name = get_reg_info(temp, [0], 'wave_shift')['name'].replace(self.app_reg_prefix, '')
        self.chan_keep_name = get_reg_info(temp, [0], 'chan_keep')['name'].replace(self.app_reg_prefix, '')

        json_path = os.path.join(base_dir, 'parameters/llrf_core_expand.json')
        self.core_llrf = RegMapExpand(base=0, add_prefix=False, path=json_path)
        self.regmap.update(self.core_llrf.regmap)
        self.regmap_short.update(self.core_llrf.regmap_short)
        self.reg_addr_dict.update(self.core_llrf.reg_addr_dict)

        # see llrf_core.json
        self._cbuf_flip_name = 'DSP_CBUF_FLIP'
        self._slow_name = 'DSP_SLOW'
        self._cbuf_name = 'DSP_CBUF'
        self._cbuf_mode_channel_name = 'DSP_CBUF_MODE'
        self.config_rom_name = 'DSP_CONFIG_ROM'

        self.buf_dw = 16
        self.cbuf_width = 13
        self.adc_bits = 16
        self.shift_base = 1  # ccfilt.v
        self.wave_samp_per = 1
        self.wave_shift = 3
        self.num_dds = 7
        self.den_dds = 33
        self.clk_freq = 75e6
        self.chn_names = ['Field', 'Forward', 'Reflected', 'PhRef']
        self.chn_names.extend(['Null'] * 2)
        self.slow_buf_len = 2*len(self.chn_names) + 2
        self.cbuf_mode_list = ['default'] + ['Counter'] + self.chn_names[:3] + ['Drive']
        self.chn_sel = self.chn_names[:4]
        self.prng_data = {}
        # self.init_llrf_settings()
        self.to_fpga = PhysicsToFPGA(**{x['name']:x['value'] for x in physics_regs})
        self.cic_period = self.den_dds
        # channel FIR configurations may vary
        self.FIR_GAIN = 1.
        self.mon_gains, self.fir_gains = {}, {}

        for ch in self.chn_names:
            self.mon_gains[ch] = self.FIR_GAIN
            self.fir_gains[ch] = self.FIR_GAIN
        self.lo_gain = int((1 << 15) / self.CORDIC_GAIN)
        self.lo_dds_gain = self.lo_gain * 4 * self.CORDIC_GAIN / (1 << 17)
        self.adc_freq = 150e6
        self.time_step_adc = 1./self.adc_freq
        self.time_step_mon = self.wave_samp_per / self.clk_freq
        self.trace_len = (1 << 11)/len(self.chn_sel)
Example #3
0
def getFPGADict(simulation):
    """getFPGADict: Illustration of conversion of user-defined physics values (contained in the simulation object,
    which is obtained from the JSON parser) and the FPGA register values, contained in the output dictionary linac_reg_dict.
    error_cnt is an error count reported from the floating-point to fix-point arithmetic conversions and scaling.
    """

    from read_regmap import get_map
    regmap = get_map("./_autogen/regmap_cryomodule.json")
    hierarchy = ["station", "cav4_elec", ["mode_", 3]]

    # Initialize empty FPGA register objects
    simulation.Init_FPGA_Registers(regmap, [])

    # (This is where register map should be parsed and register lengths should be filled in)

    # Compute FPGA register values based on configuration parameters
    error_cnt = simulation.Compute_FPGA_Registers()

    return error_cnt
Example #4
0
    def registers(self, regmap_json, cavity):

        # Read register map from JSON file
        from read_regmap import get_map, get_reg_info
        regmap = get_map(regmap_json)

        # Extract the registers of interest
        setmp = get_reg_info(regmap, [self.cavity], 'setmp')  # Set-points
        coeff = get_reg_info(regmap, [self.cavity],
                             'coeff')  # Feedback loop gains
        lim = get_reg_info(regmap, [self.cavity],
                           'lim')  # Controller upper and lower limits

        setmp_val, coeff_val, lim_val = self.integers()

        return {
            setmp['name']: setmp_val,
            coeff['name']: coeff_val,
            lim['name']: lim_val
        }
Example #5
0
    def json_map_handle(self, regmappath, refresh=False):
        if refresh or not isfile(regmappath):
            a = read_live_array(self)
            r = decode_array(a)
            print(("Bitfile lists git commit " + r[1]))
            print(("Attempting write of live json to " + regmappath))
            with open(regmappath, 'wb') as f:
                f.write(r[3])
        self.regmap = get_map(regmappath)

        # Look for addresses in hex (encoded in JSON as string values) and convert to int
        for key in self.regmap:
            try:
                if isinstance(self.regmap[key]['base_addr'], str):
                    self.regmap[key]['base_addr'] = int(
                        self.regmap[key]['base_addr'], 0)
            except Exception:
                pass

        # Setting the old regmaps to null; Forcing an error on access
        # TODO: Clean up the deprecated codepath that reads from prc_regmap.json
        self.write_regmap = {}
        self.read_regmap = {}
Example #6
0
from pspeps_io.utilities import decode_2s_comp
from read_regmap import get_map, get_reg_info

visual = 0
if visual:
    import matplotlib.pyplot as plt
    plt.ion()
    fig = plt.figure()

cic_base_period = 33  # default parameter in llrf_dsp.v
wave_samp_per = 1  # set by paramhg.py
Tstep = 10e-9  # as set in paramhg.py
dt = cic_base_period * 2 * wave_samp_per * Tstep  # seconds

base_dir = os.path.dirname(os.path.abspath(__file__)) or '.'
reg_map = get_map(os.path.join(base_dir, "../_autogen/regmap_cryomodule.json"))


def get_write_address(name):
    if type(name) is int:
        return name
    else:
        offset = 0
        if name.endswith(']'):
            x = re.search('^(\w+)\s*\[(\d+)\]', name)
            if x:
                name, offset = x.group(1), int(x.group(2))
        r = get_reg_info(reg_map, [0], name)
        return r['base_addr'] + offset

Example #7
0
import os, sys
from math import sin, cos, pi, sqrt, log, ceil
from cmath import exp
from hashlib import sha1

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +
                "/submodules/build")
from read_regmap import get_map, get_reg_info

regmap_cryomodule = get_map("./_autogen/regmap_cryomodule.json")
ctl_regmap = get_map("./_autogen/regmap_llrf_shell.json")


# Note that Tstep is the ADC time step, also clocks the LLRF controller.
# Divide by two for the cavity simulator (rtsim) clock time step.
Tstep = 10e-9 # s
f0 = 1300e6   # Hz
nyquist_sign = -1    # -1 represents frequency inversion,
# as with high-side LO or even-numbered Nyquist zones.

# DDS setup for simulator should be static
# this construction is for 20 MHz / 94.286 MHz = 7/33
dds_num=7
dds_den=33

dds_phstep_h = int(dds_num*2**20/dds_den)
dds_mult = int(4096/dds_den)
dds_phstep_l = (dds_num*2**20)%dds_den * dds_mult
dds_modulo = 4096 - dds_mult*dds_den
dds_phstep = dds_phstep_h << 12 | dds_phstep_l
#print "# dds",dds_mult,dds_phstep_h, dds_phstep_l, dds_modulo
Example #8
0
def printFPGADict():
    """printFPGADict: Replication of the old param.py program for illustration purposes.
    Run this program in order to call JSON parser, user-defined physics settings to FPGA register space conversion,
    and prints used by Verilog test-bench for configuration parsing.
    """

    from readjson.readjson_accelerator import push_seed

    # Get the simulation and accelerator objects from the JSON parser
    file_list = [
        "readjson/configfiles/LCLS-II/default_accelerator.json",
        "readjson/configfiles/LCLS-II/LCLS-II_accelerator.json",
        "readjson/configfiles/LCLS-II/LCLS-II_append.json"
    ]

    simulation = parseSim.ParseSimulation(file_list)

    # ==== the following dictionaries should get pulled in from Verilog somehow
    sim_base = 16384  # base address for vmod1, see larger.v line 33

    # regmap_global and regmap_emode dictionaries will be automatically created from a JSON file
    # regmap_mode: base address for cavity n (zero-based) is 16+8*n
    regmap_file = "readjson/configfiles/LCLS-II/register_map.json"
    regmap_global, regmap_emode = parseRegMap.ParseRegisterMap(regmap_file)

    from read_regmap import get_map, get_reg_info
    regmap = get_map("./_autogen/regmap_cryomodule.json")

    print "# Globals"
    # Convert user input into FPGA registers
    error_cnt = getFPGADict(simulation)

    # Grab the variables of interest from the dictionary
    ## First go down the hierarchy and get handles to dictionaries
    linac_obj = simulation.linac_list[0]
    cryomodule_obj = linac_obj.cryomodule_list[0]
    station_obj = cryomodule_obj.station_list[0]

    linac_reg_dict = linac_obj.reg_dict
    station0_reg_dict = station_obj.reg_dict
    cm_reg_dict = cryomodule_obj.reg_dict
    mechMode0_reg_dict = cryomodule_obj.mechanical_mode_list[0].reg_dict
    mechMode1_reg_dict = cryomodule_obj.mechanical_mode_list[1].reg_dict
    mechMode2_reg_dict = cryomodule_obj.mechanical_mode_list[2].reg_dict
    elecMode0_reg_dict = station_obj.cavity.elec_modes[0].reg_dict
    elecMode1_reg_dict = station_obj.cavity.elec_modes[1].reg_dict
    # Quick hack to add name field
    elecMode0_reg_dict['name'] = station_obj.cavity.elec_modes[0].name
    elecMode1_reg_dict['name'] = station_obj.cavity.elec_modes[1].name

    piezo0_reg_dict = station_obj.piezo_list[0].reg_dict

    reg_dict = {}
    ## Linac variables
    reg_dict['dds_phstep'] = linac_reg_dict['dds_phstep']
    reg_dict['dds_modulo'] = linac_reg_dict['dds_modulo']
    ## Station variables
    reg_dict['amp_bw'] = station0_reg_dict['amp_bw']

    # Manually construct prompt for now
    reg_dict['prompt'] = station0_reg_dict['prompt']

    for e in [elecMode0_reg_dict, elecMode1_reg_dict]:
        reg_dict['prompt'].value.append(e["prompt_rfl"].value)
        reg_dict['prompt'].value.append(e["prompt_fwd"].value)

    reg_dict['cav_adc_off'] = station0_reg_dict['cav_adc_off']
    reg_dict['rev_adc_off'] = station0_reg_dict['rev_adc_off']
    reg_dict['fwd_adc_off'] = station0_reg_dict['fwd_adc_off']

    reg_dict['res_prop'] = cm_reg_dict['res_prop']
    reg_dict['res_prop'].set_value([
        mechMode0_reg_dict['a2'].value, mechMode0_reg_dict['b2'].value,
        mechMode1_reg_dict['a2'].value, mechMode1_reg_dict['b2'].value,
        mechMode2_reg_dict['a2'].value, mechMode2_reg_dict['b2'].value
    ])

    reg_dict['dot_0_k'] = elecMode0_reg_dict['dot_list']
    reg_dict['outer_0_k'] = elecMode0_reg_dict['outer_list']
    reg_dict['dot_1_k'] = elecMode1_reg_dict['dot_list']
    reg_dict['outer_1_k'] = elecMode1_reg_dict['outer_list']
    reg_dict['dot_2_k'] = [
        piezo0_reg_dict['piezo_couple'].value[0],
        piezo0_reg_dict['piezo_couple'].value[1],
        piezo0_reg_dict['piezo_couple'].value[3],
        piezo0_reg_dict['piezo_couple'].value[2]
    ]
    reg_dict['outer_2_k'] = []
    reg_dict['piezo_couple'] = piezo0_reg_dict['piezo_couple']

    # Added to generate the vibration_hack values
    reg_dict['noise_couple'] = cm_reg_dict['noise_couple']
    reg_dict['noise_couple'].set_value([
        mechMode0_reg_dict['vibration_hack'].value[0],
        mechMode0_reg_dict['vibration_hack'].value[1],
        mechMode1_reg_dict['vibration_hack'].value[0],
        mechMode1_reg_dict['vibration_hack'].value[1],
        mechMode2_reg_dict['vibration_hack'].value[0],
        mechMode2_reg_dict['vibration_hack'].value[1]
    ])

    # Pop some elements to match paramhg.py
    del reg_dict['prompt'].value[4:]
    del reg_dict['dot_2_k'][0:]

    for n in regmap_global.keys():
        set_reg(0, "", n, regmap_global, reg_dict, sim_base)

    for i, emode in enumerate([elecMode0_reg_dict, elecMode1_reg_dict]):
        reg_dict['coarse_freq'] = emode['coarse_freq']
        reg_dict['drive_coupling'] = emode['drive_coupling']
        reg_dict['bw'] = emode['bw']
        reg_dict['out_coupling'] = emode['out_coupling']
        reg_dict['out_phase_offset'] = emode['out_phase_offset']
        regmap_emode.pop('out_couple', None)
        regmap_emode['out_coupling'] = None
        regmap_emode['out_phase_offset'] = None
        print "# Cavity electrical mode %d: %s" % (i, emode['name'])
        for n in regmap_emode:
            set_reg(16 + 8 * i, emode['name'] + ".", n, regmap_emode, reg_dict,
                    sim_base)

    # Pseudo-random generator initialization, see tt800v.v and prng.v
    prng_seed = "pushmi-pullyu"
    prng_iva = get_reg_info(regmap, [], "prng_iva")
    prng_ivb = get_reg_info(regmap, [], "prng_ivb")
    prng_random_run = get_reg_info(regmap, [], "prng_random_run")
    if (prng_seed is not None):
        from hashlib import sha1
        print "# PRNG subsystem seed is '%s'" % prng_seed
        hf = sha1()
        hf.update(prng_seed)
        push_seed(prng_iva['base_addr'] + sim_base, hf)
        push_seed(prng_ivb['base_addr'] + sim_base, hf)
        print "%d 1  # turn on PRNG" % (prng_random_run['base_addr'] +
                                        sim_base)

    # Just hack in a few quick values for the controller
    # This should really be another construction as above, maybe in a separate Python module?
    # static DDS config, 7/33 as above
    wave_samp_per = 1
    wave_shift = 3
    # The LO amplitude in the FPGA is scaled by (32/33)^2, so that yscale
    # fits nicely within the 32768 limit for small values of wave_samp_per
    lo_cheat = (32 / 33.0)**2
    yscale = lo_cheat * (33 * wave_samp_per)**2 * 4**(8 - wave_shift) / 32

    reg_list = []

    # Variables defined to print out the registers value
    piezo_dc = 0
    ph_offset = -35800
    sel_en = 0
    set_X = 0.0
    set_P = 0.0
    k_PA = 0
    k_PP = 0

    from read_regmap import get_map, get_reg_info
    ctl_regmap = get_map("./_autogen/regmap_llrf_shell.json")
    # Maybe the following lines should be removed in the future
    #reg_list.append(c_regs('phase_step', 17+18, reg_dict['dds_phstep'].value))
    #reg_list.append(c_regs('modulo', 18+18, reg_dict['dds_modulo'].value))
    addr = get_reg_info(ctl_regmap, [], 'wave_samp_per')['base_addr']
    reg_list.append(c_regs('wave_samp_per', addr, wave_samp_per))
    addr = get_reg_info(ctl_regmap, [], 'wave_shift')['base_addr']
    reg_list.append(c_regs('wave_shift', addr, wave_shift))
    addr = get_reg_info(ctl_regmap, [], 'piezo_dc')['base_addr']
    reg_list.append(c_regs('piezo_dc', addr, piezo_dc))
    addr = get_reg_info(ctl_regmap, [], 'sel_thresh')['base_addr']
    reg_list.append(c_regs('sel_thresh', addr, 5000))
    addr = get_reg_info(ctl_regmap, [], 'ph_offset')['base_addr']
    reg_list.append(c_regs('ph_offset', addr, ph_offset))
    addr = get_reg_info(ctl_regmap, [], 'sel_en')['base_addr']
    reg_list.append(c_regs('sel_en', addr, sel_en))
    addr = get_reg_info(ctl_regmap, [], 'lp1a_kx')['base_addr']
    reg_list.append(c_regs('lp1a', addr, 20486))
    addr = get_reg_info(ctl_regmap, [], 'lp1a_ky')['base_addr']
    reg_list.append(c_regs('lp1a', addr, -20486))
    reg_list.append(c_regs('wait', 555, 150 - 12))
    addr = get_reg_info(ctl_regmap, [], 'chan_keep')['base_addr']
    reg_list.append(c_regs('ch_keep', addr, 4080))
    addr = get_reg_info(ctl_regmap, [], 'setmp')['base_addr']
    reg_list.append(c_regs('set_X', addr, int(set_X)))
    reg_list.append(c_regs('set_P', addr + 1, int(set_P)))
    addr = get_reg_info(ctl_regmap, [], 'coeff')['base_addr']
    reg_list.append(c_regs('coeff_X_I', addr + 0, -100))
    reg_list.append(c_regs('coeff_X_P', addr + 2, k_PA))
    reg_list.append(c_regs('coeff_Y_I', addr + 1, -100))
    reg_list.append(c_regs('coeff_Y_P', addr + 3, k_PP))
    addr = get_reg_info(ctl_regmap, [], 'lim')['base_addr']
    reg_list.append(c_regs('lim_X_hi', addr + 0, 0))
    reg_list.append(c_regs('lim_Y_hi', addr + 1, 0))
    reg_list.append(c_regs('lim_X_lo', addr + 2, 0))
    reg_list.append(c_regs('lim_Y_lo', addr + 3, 0))

    # Variables needed
    amp_max = 22640

    reg_list.extend(delay_set(0, addr,
                              amp_max))  # 52 is the address of lim_X_hi
    reg_list.extend(delay_set(duration * 8, addr + 2,
                              amp_max))  # 54 is the address of lim_X_lo
    reg_list.extend(delay_set(0, addr, 0))  # 52 is the address of lim_X_hi
    reg_list.extend(delay_set(0, addr + 2, 0))  # 54 is the address of lim_X_lo

    for jx in range(6):
        reg_list.extend(delay_set(0, 0, 0))

    for reg in reg_list:
        print str(reg.addr) + " " + str(reg.value)

    if (error_cnt > 0):
        print "# %d scaling errors found" % error_cnt
        exit(1)
Example #9
0
def gen_reg_list(mode1_foffset=5.0,
                 mode1_Q1=8.1e4,
                 mmode1_freq=30e3,
                 mmode1_Q=5.0,
                 net1_coupling=100,
                 net2_coupling=200,
                 net3_coupling=150,
                 sel_en=1,
                 set_X=0.0,
                 set_P=0.0,
                 k_PA=0,
                 k_PP=0,
                 maxq=0,
                 ph_offset=-35500,
                 amp_max=22640,
                 fwd_phase_shift=0,
                 rfl_phase_shift=0,
                 cav_phase_shift=0,
                 duration=300,
                 PRNG_en=1,
                 piezo_dc=0):
    regs = []
    error_cnt = 0

    #print 'mode1_foffset=%f,mode1_Q1=%f,mmode1_freq=%f,mmode1_Q=%f,net_coupling=%f'%(mode1_foffset,mode1_Q1,mmode1_freq,mmode1_Q,net_coupling)

    # Gang humbly requests that Q_1 be renamed Q_drive, and Q_2 as Q_probe.
    # Should apply here, physics.tex, elsewhere?

    # Note that Tstep is the ADC time step, also clocks the LLRF controller.
    # Divide by two for the cavity simulator (rtsim) clock time step.
    Tstep = 10e-9  # s
    f0 = 1300e6  # Hz
    nyquist_sign = -1  # -1 represents frequency inversion,
    # as with high-side LO or even-numbered Nyquist zones.

    VPmax = 48.0  # V piezo drive max

    # as we scale up, the following 10 parameters replicate per cavity:
    PAmax = 6e3  # W RF amplifier max
    PAbw = 1.5e6  # Hz bandwidth of power amplifier
    cav_adc_max = 1.2  # sqrt(W)
    rfl_adc_max = 180.0  # sqrt(W)
    fwd_adc_max = 160.0  # sqrt(W)
    phase_1 = fwd_phase_shift  # forward monitor phase shift
    phase_2 = rfl_phase_shift  # reflected monitor prompt phase shift
    cav_adc_off = 10
    rfl_adc_off = 20
    fwd_adc_off = 30

    mode1 = Emode(name="pi",
                  RoverQ=1036.0,
                  foffset=mode1_foffset,
                  peakV=1.5e6,
                  Q_0=1e10,
                  Q_1=mode1_Q1,
                  Q_2=2e9,
                  phase_1=rfl_phase_shift,
                  phase_2=cav_phase_shift,
                  mech_couplings=[net1_coupling, net2_coupling, net3_coupling])
    mode2 = Emode(name="8pi/9",
                  RoverQ=10.0,
                  foffset=-8e5,
                  peakV=0.15e6,
                  Q_0=1e10,
                  Q_1=8.1e4,
                  Q_2=2e9,
                  phase_1=10,
                  phase_2=-180,
                  mech_couplings=[0, 0, 0])

    mmode1 = Mmode('silly', mmode1_freq, mmode1_Q, 1.13, 40000, 1, 80000)
    mmode2 = Mmode('lowQ', 100000, 5.0, 1.5, 80000, 1, 20000)
    mmode3 = Mmode('other', 24500, 25.0, 1.5, 20000, 1, 10000)

    # DDS setup for simulator should be static
    # this construction is for 20 MHz / 94.286 MHz = 7/33
    dds_num = 7
    dds_den = 33

    # The following three parameters are set in the Verilog at compile-time,
    # not run-time.  Top-level setting in larger.v needs to be mirrored here.
    lp_shift = 9  # see lp_pair.v, a.k.a. mode_shift
    n_mech_modes = 7  # number of mechanical modes handled
    df_scale = 9  # see cav4_freq.v

    # ==== end of system configuration

    # ==== the following dictionaries should get pulled in from Verilog somehow
    sim_base = 16384  # base address for vmod1, see larger.v line 33

    regmap_global = {
        'dds_phstep': 1,
        'dds_modulo': 2,
        'amp_bw': 5,
        'prompt': 8,  # base address of 4 registers
        'cav_adc_off': 49,
        'rfl_adc_off': 50,
        'fwd_adc_off': 51,
        'sat_ctl': 55,
        'res_prop': 1 * 1024,  # base address of 1024 registers
        'dot_0_k': 2 * 1024,  # base address of 1024 registers
        'outer_0_k': 3 * 1024,  # base address of 1024 registers
        'dot_1_k': 4 * 1024,  # base address of 1024 registers
        'outer_1_k': 5 * 1024,  # base address of 1024 registers
        'dot_2_k': 6 * 1024,  # base address of 1024 registers
        'outer_2_k': 7 * 1024,  # base address of 1024 registers
        'piezo_couple': 8 * 1024,  # base address of 1024 registers
        'noise_couple': 9 * 1024
    }  # base address of 1024 registers

    # base address for cavity n (zero-based) is 16+8*n
    regmap_emode = {
        'coarse_freq': 1,
        'drive_coupling': 2,
        'bw': 3,
        'out_couple': 4
    }  # base address of 4 registers
    from read_regmap import get_map
    regmap = get_map("../sel4v/_autogen/regmap_cryomodule.json")

    # ==== end of hardware register dictionaries

    # send a register value "out"
    # looks address up in regmap[name]
    # finds value via name in python global namespace
    # value can be a scalar or a list
    # prefix and name are used to give a helpful comment
    # ==== now start the application-specific computations

    # Still may have bugs:
    #   Mechanical mode coupling
    # Needs a lot of work:
    #   LLRF controller

    omega0 = f0 * 2 * pi
    mech_tstep = Tstep * n_mech_modes
    interp_gain = n_mech_modes / 2**ceil(
        log(n_mech_modes) / log(2))  # interp0.v

    #print "# Globals"
    amp_bw = fix(Tstep * PAbw * 32, 18, "amp_bw")

    dds_phstep_h = int(dds_num * 2**20 / dds_den)
    dds_mult = int(4096 / dds_den)
    dds_phstep_l = (dds_num * 2**20) % dds_den * dds_mult
    dds_modulo = 4096 - dds_mult * dds_den
    dds_phstep = dds_phstep_h << 12 | dds_phstep_l
    sat_ctl = 65535
    #print "# dds",dds_mult,dds_phstep_h, dds_phstep_l, dds_modulo

    # four registers of pair_couple.v
    # neglect losses between directional coupler and cavity
    prompt = [
        fix(-sqrt(PAmax) / fwd_adc_max, 18, "out1", "cordic"),
        fix(-sqrt(PAmax) / rfl_adc_max, 18, "out2", "cordic"),
        fix(phase_1 / 180.0, 19, "out3"),
        fix(phase_2 / 180.0, 19, "out4")
    ]

    # Mechanical modes
    res_prop = []
    piezo_couple = []
    noise_couple = []
    dot_0_k = []
    outer_0_k = []
    dot_1_k = []
    outer_1_k = []
    dot_2_k = []
    outer_2_k = []
    mech_mode_list = [mmode1, mmode2, mmode3]
    for i, m in enumerate(mech_mode_list):
        #print "# Cavity mechanical mode %d: %s"%(i,m.name)
        w1 = mech_tstep * 2 * pi * m.freq
        # a1 + b1 * i represents the pole in the normalized s-plane
        a1 = w1 * (-1 / (2.0 * m.Q))
        b1 = w1 * sqrt(1 - 1 / (4.0 * m.Q**2))
        z_pole = cexp(a1 + b1 * 1j)
        #print "# z_pole = %7f + %7fi"%(z_pole.real,z_pole.imag)
        a1 = z_pole.real - 1.0
        b1 = z_pole.imag
        scale = int(-log(max(a1, b1)) / log(4))
        scale = max(min(scale, 9), 2)
        a2 = a1 * 4**scale
        b2 = b1 * 4**scale
        #print "# debug",w1,a1,b1,scale,a2,b2
        #c1 = -w1**2 / (k*b1)
        res_prop.append((fix(a2, 18, "a2") & (2**18 - 1)) +
                        ((9 - scale) << 18))
        res_prop.append((fix(b2, 18, "b2") & (2**18 - 1)) +
                        ((9 - scale) << 18))
        # the above is tested.  Onwards to the work-in-progress
        dc_gain = b2 / (a2**2 + b2**2)  # resonator.v
        m.dc_gain = dc_gain  # per-electical mode coupling computation will need this
        piezo_couple.append(m.piezo_hack)
        piezo_couple.append(0)
        noise_couple.append(m.vibration_hack)
        noise_couple.append(0)
        #dot_2_k.append(0)
        #dot_2_k.append(m.piezo_hack)

    for i, m in enumerate([mode1, mode2]):
        #print "# Cavity electrical mode %d: %s"%(i,m.name)
        Q_L = 1 / (1 / m.Q_0 + 1 / m.Q_1 + 1 / m.Q_2)
        # x is defined as sqrt(U)
        xmax = m.peakV / sqrt(m.RoverQ * omega0)
        # four registers of pair_couple.v
        out_couple = [
            fix(
                sqrt(omega0 / m.Q_1) * xmax / rfl_adc_max, 18,
                m.name + ".out1", "cordic"),
            fix(
                sqrt(omega0 / m.Q_2) * xmax / cav_adc_max, 18,
                m.name + ".out2", "cordic"),
            fix(m.phase_1 / 180.0, 19, m.name + "out3"),
            fix(m.phase_2 / 180.0, 19, m.name + "out4")
        ]
        # see Pro tip in eav4_elec.v for better limit on foffset
        # XXX document using 33 for what's really a 28-bit register
        coarse_freq = fix(Tstep * nyquist_sign * m.foffset, 33,
                          m.name + "coarse_freq")
        V_achievable = 2 * sqrt(PAmax * m.Q_1 * m.RoverQ)
        drive_coupling = fix(V_achievable / m.peakV, 18,
                             m.name + "drive_coupling", "cordic")
        # bandwidth in Hz = f_clk/2/2^shift/(2*pi) * bw_register/2^17 = omega_0/(2*pi*2*Q_L)
        # XXX document origin of *2.0 better, compensates for shift right in lp_pair.v
        bw = fix(Tstep * omega0 / (2 * Q_L) * (2**lp_shift) * 2.0, 18,
                 m.name + ".bw")
        for n in regmap_emode.keys():
            regs.extend(
                set_reg(16 + 8 * i, m.name + ".", n, regmap_emode, locals(),
                        sim_base))
        for j, mech_couple in enumerate(m.mech_couplings):
            #print "# elec mode %d coupling index %d value %f"%(i,j,mech_couple)
            # Number of electrical modes implemented in the hardware is set by the
            # parameter mode_count in cav4_elec.v, frozen at the time of synthesis.
            # The address decode generator (newad.py) will embed mode index into a
            # text name, which is then given an address by addr_map.vh.  This explains
            # the funny-looking exec at the end of this stanze.
            mech_mode = mech_mode_list[j]
            Amn = sqrt(mech_couple / m.RoverQ) / omega0  # sqrt(J)/V^2
            Cmn = -sqrt(mech_couple * m.RoverQ) * omega0  # 1/s/sqrt(J)
            lorentz_en = 1
            outer = lorentz_en * Amn / mech_mode.mx * m.peakV**2 / mech_mode.dc_gain  # dimensionless
            inner = lorentz_en * Cmn * mech_mode.mx * Tstep / 2**df_scale / interp_gain  # dimensionless
            # note that inner*outer = net_coupling * mode1.peakV**2 * Tstep
            #print "# outer =",outer,"inner =",inner
            # additional scaling below comes from the 32-bit mech_phase_fine
            # accumulator, but only 18-bit d_result
            exec '''outer_%d_k.append(fix(outer/128,18,"outer")); outer_%d_k.append(0); dot_%d_k.append(0); dot_%d_k.append(fix(inner/128,18,"inner"))''' % (
                i, i, i, i)

    # Must be after electrical mode processing, to pick up outer_0_k etc.
    for n in regmap_global.keys():
        r_hg_0 = set_reg(0, "", n, regmap_global, locals(), sim_base)
        regs.extend(r_hg_0)

    # Pseudo-random generator initialization, see tt800v.v and prng.v
    prng_seed = "pushmi-pullyu"
    if prng_seed:
        #print "# PRNG subsystem seed is '%s'"%prng_seed
        hf = sha1()
        hf.update(prng_seed)
        r53 = push_seed(53 + sim_base, hf)
        r54 = push_seed(54 + sim_base, hf)
        #print "%d 1  # turn on PRNG"%(52+sim_base)
    regs.extend(r53)
    regs.extend(r54)
    regs.append(c_regs('turn on PRNG', 52 + sim_base, PRNG_en))

    # Just hack in a few quick values for the controller
    # This should really be another construction as above,
    # maybe in a separate Python module?
    # static DDS config, 7/33 as above
    # #print "17 %d  # phase_step"%dds_phstep
    # #print "18 %d  # modulo"%dds_modulo
    #print "phase_step %d  # phase_step"%dds_phstep
    #print "modulo %d  # modulo"%dds_modulo
    wave_samp_per = 1
    wave_shift = 3
    # The LO amplitude in the FPGA is scaled by (32/33)^2, so that yscale
    # fits nicely within the 32768 limit for small values of wave_samp_per
    lo_cheat = (32 / 33.0)**2
    yscale = lo_cheat * (33 * wave_samp_per)**2 * 4**(8 - wave_shift) / 32

    regs.append(set_ctl('phase_step', dds_phstep))
    regs.append(set_ctl('modulo', 4))
    regs.append(set_ctl('wave_samp_per', wave_samp_per))
    regs.append(set_ctl('wave_shift', wave_shift))
    regs.append(set_ctl('piezo_dc', piezo_dc))
    regs.append(set_ctl('sel_thresh', 5000))
    regs.append(set_ctl('ph_offset', ph_offset))
    regs.append(set_ctl('sel_en', sel_en))
    regs.append(set_ctl('lp1a_kx_re', 20486))
    regs.append(set_ctl('lp1a_ky_re', -20486))

    #regs.append(c_regs('wait',555,150-12))
    regs.append(set_ctl('chan_keep', 4080))
    #regs.append(set_ctl('lim',22640))
    #regs.append(set_ctl('lim',22640))
    regs.append(set_ctl('set_X', int(set_X)))
    regs.append(set_ctl('set_Y', int(set_P)))
    regs.append(set_ctl('coeff_X_I', -100))
    regs.append(set_ctl('coeff_X_P', k_PA))
    regs.append(set_ctl('coeff_Y_I', -100))
    regs.append(set_ctl('coeff_Y_P', k_PP))
    regs.append(set_ctl('lim_X_hi', 0))
    regs.append(set_ctl('lim_Y_hi', 0))
    regs.append(set_ctl('lim_X_lo', 0))
    regs.append(set_ctl('lim_Y_lo', 0))

    global delay_pc
    if 0:  # FGEN
        regs.append(c_regs('duration', 3, duration))
        regs.append(c_regs('amp_slope', 4, 5000))
        regs.append(c_regs('amp_max', 7, amp_max))
        regs.append(c_regs('amp_dest_addr', 10, 36))
        regs.append(c_regs('amp_dest_addr', 12, 38))
    elif 0:  # TGEN
        delay_pc = 4096
        # start the pulse in open loop (fixed drive amplitude) mode
        regs.extend(delay_set(0, 'lim_Y_hi', 0))
        regs.extend(delay_set(0, 'lim_Y_lo', 0))
        regs.extend(delay_set(0, 'lim_X_hi', 22640))
        regs.extend(delay_set(500 * 8, 'lim_X_lo', 22640))
        # allow the amplitude loop to run
        #regs.extend(delay_set(0, 52, 26000))
        regs.extend(delay_set(duration * 8, 'lim_X_lo', 16000))
        # allow the phase loop to run
        regs.extend(delay_set(0, 'lim_Y_hi', maxq))
        regs.extend(delay_set(5000 * 8, 'lim_Y_lo', -maxq))
        regs.extend(delay_set(0, 'lim_X_hi', 0))
        regs.extend(delay_set(0, 'lim_X_lo', 0))
    else:
        delay_pc = 4096
        regs.extend(delay_set(0, 'lim_X_hi', amp_max))
        regs.extend(delay_set(duration * 8, 'lim_X_lo', amp_max))
        regs.extend(delay_set(0, 'lim_X_hi', 0))
        regs.extend(delay_set(0, 'lim_X_lo', 0))
        for jx in range(6):
            regs.extend(delay_set(0, 'null', 0))

    if error_cnt > 0:
        print "# %d scaling errors found" % error_cnt
        #exit(1)

    return [regs, error_cnt]
Example #10
0
def run_test_bench(setmp_val,
                   coeff_val,
                   lim_val,
                   test_type,
                   in_file,
                   out_file,
                   setmp_step_time=0,
                   setmp_step_val=0,
                   lim_step_time=0,
                   lim_step_val=0,
                   in_i=0,
                   in_q=0):
    """
    Generates an input file for fdbk_core_tb with the appropriate register settings,
    and runs test-bench using Icarus Verilog.
    """

    # Get register map from JSON
    from read_regmap import get_map, get_reg_info
    regmap_fdbk_core = get_map("./_autogen/regmap_fdbk_core_tb.json")

    # Extract the registers of interest
    setmp = get_reg_info(regmap_fdbk_core, [], 'setmp')  # Set-points
    coeff = get_reg_info(regmap_fdbk_core, [], 'coeff')  # Feedback loop gains
    lim = get_reg_info(regmap_fdbk_core, [],
                       'lim')  # Controller upper and lower limits

    setmp['value'] = setmp_val  # set X, set Y
    coeff['value'] = coeff_val  # coeff X I, coeff Y I, coeff X P, coeff Y P
    lim['value'] = lim_val  # lim X hi, lim Y hi, lim X lo, lim Y lo

    # Write the configuration file (register writes) for the test-bench
    write_reg_file([setmp, coeff, lim], regmap_fdbk_core, in_file)

    # Start with empty command to handle exception
    command = ''

    if ((test_type == 2) or (test_type == 3) or (test_type == 4)):
        # Write configuration file for set-point step
        setmp_file = 'setmp_step_file_in.dat'
        # index selects either amplitude or phase step on the set-point
        if (test_type == 2 or test_type == 4):  # Amplitude modulation
            index = 0
        elif (test_type == 3):  # Phase modulation
            index = 1

        # Apply step to set-point to amplitude or phase depending on the test
        setmp['value'][
            index] = setmp['value'][index] + setmp_step_val  # set X, set Y
        write_reg_file([setmp], regmap_fdbk_core, setmp_file)

        # Write configuration file for limits step
        lim_file = 'lim_step_file_in.dat'
        lim['value'] = lim_step_val
        write_reg_file([lim], regmap_fdbk_core, lim_file)

        # Command line to run Verilog simulation
        # Arguments depend on the type of test-bench being run (test_type)
        command = 'vvp -n fdbk_core_tb +vcd +test=' + \
            str(test_type) + ' +in_file=' + in_file + ' +out_file=' + out_file + \
            ' +sp_step_time=' + str(setmp_step_time) + ' +sp_step_file=' + setmp_file +\
            ' +lim_step_time=' + str(lim_step_time) + ' +lim_step_file=' + lim_file

        if test_type == 3:
            command = command + ' +in_i=' + str(in_i) + ' +in_q=' + str(in_q)

    elif (test_type == 0 or test_type == 4):
        command = 'vvp -n fdbk_core_tb +vcd +test=' + str(
            test_type) + ' +in_file=' + in_file + ' +out_file=' + out_file
    elif (test_type == 1):
        command = 'vvp -n fdbk_core_tb +vcd +test=' + str(
            test_type
        ) + ' +in_file=' + in_file + ' +out_file=' + out_file + ' +in_i=' + str(
            in_i) + ' +in_q=' + str(in_q)

    # Run the Verilog test-bench
    print 'Running Verilog test-bench from Python...\n\n' + command + '\n'

    if command == '':
        print 'test_type not defined with a valid code'
        print 'test_type value supplied is ' + str(test_type)
    else:
        return_code = call(command, shell=True)
Example #11
0
def gen_reg_list(verbose=False):
    """
    gen_reg_list: Replication of the old param.py program for illustration
    purposes.  Run this program in order to call JSON parser, user-defined
    physics settings to FPGA register space conversion, and prints used by
    Verilog test-bench for configuration parsing.
    """
    # Get the simulation and accelerator objects from the JSON parser
    file_list = [
        base_dir + "/configfiles/LCLS-II/default_accelerator.json",
        base_dir + "/configfiles/LCLS-II/LCLS-II_accelerator.json",
        base_dir + "/configfiles/LCLS-II/LCLS-II_append.json"
    ]

    simulation = parseSim.ParseSimulation(file_list, verbose)

    sim_base = 0  # base address for vmod1, see larger.v line 33

    # Convert user input into FPGA registers
    regmap, error_cnt, c_reg_base = getFPGADict(simulation)

    # Pseudo-random generator initialization, see tt800v.v and prng.v
    prng_seed = "pushmi-pullyu"

    prng_iva = regmap["cavity_0_prng_iva"]
    prng_ivb = regmap["cavity_0_prng_ivb"]
    prng_random_run = regmap["cavity_0_prng_random_run"]

    if (prng_seed is not None):
        from readjson_accelerator import push_seed
        from hashlib import sha1
        # print "# PRNG subsystem seed is '%s'"%prng_seed
        hf = sha1()
        hf.update(prng_seed)
        push_seed(prng_iva.address + sim_base, hf)
        push_seed(prng_ivb.address + sim_base, hf)
        # print "%d 1  # turn on PRNG"%(prng_random_run.address+sim_base)

    # Just hack in a few quick values for the controller
    # This should really be another construction as above, maybe in a separate Python module?
    # static DDS config, 7/33 as above
    wave_samp_per = 1
    wave_shift = 3

    reg_list = []

    # Variables defined by hand, should really come from JSON controller configuration
    piezo_dc = 0
    ph_offset = -150800
    sel_en = 1
    sel_thresh = 5000
    lp1a_kx = 20486
    lp1a_ky = -20486
    chan_keep = 4080

    ctl_regmap = get_map(base_dir + "/../_autogen/regmap_llrf_shell.json")

    reg = Register(**get_reg_info(ctl_regmap, [], 'wave_samp_per'))
    reg.value = wave_samp_per
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'wave_shift'))
    reg.value = wave_shift
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'piezo_dc'))
    reg.value = piezo_dc
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'sel_thresh'))
    reg.value = sel_thresh
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'ph_offset'))
    reg.value = ph_offset
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'sel_en'))
    reg.value = sel_en
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'lp1a_kx'))
    reg.value = lp1a_kx
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'lp1a_ky'))
    reg.value = lp1a_ky
    reg_list.append(reg)

    reg = Register(**get_reg_info(ctl_regmap, [], 'chan_keep'))
    reg.value = chan_keep
    reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'setmp'))
    # reg.name = 'set_X'
    # reg.address = reg.address + 0
    # reg.value = int(set_X)
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'setmp'))
    # reg.name = 'set_P'
    # reg.address = reg.address + 1
    # reg.value = int(set_P)
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'coeff'))
    # reg.name = 'coeff_X_I'
    # reg.address = reg.address + 0
    # reg.value = coeff_X_I
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'coeff'))
    # reg.name = 'coeff_X_P'
    # reg.address = reg.address + 1
    # reg.value = coeff_X_P
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'coeff'))
    # reg.name = 'coeff_Y_I'
    # reg.address = reg.address + 2
    # reg.value = coeff_Y_I
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'coeff'))
    # reg.name = 'coeff_Y_P'
    # reg.address = reg.address + 3
    # reg.value = coeff_Y_P
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'lim'))
    # reg.name = 'lim_X_hi'
    # reg.address = reg.address + 0
    # reg.value = lim_X_hi
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'lim'))
    # reg.name = 'lim_Y_hi'
    # reg.address = reg.address + 1
    # reg.value = lim_Y_hi
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'lim'))
    # reg.name = 'lim_X_lo'
    # reg.address = reg.address + 2
    # reg.value = lim_X_lo
    # reg_list.append(reg)

    # reg = Register(**get_reg_info(ctl_regmap,[],'lim'))
    # reg.name = 'lim_Y_lo'
    # reg.address = reg.address + 3
    # reg.value = lim_Y_lo
    # reg_list.append(reg)

    addr = get_reg_info(ctl_regmap, [], 'lim')['base_addr']
    # Variables needed

    # reg_list.extend(delay_set(0, addr, amp_max))            # 52 is the address of lim_X_hi
    # reg_list.extend(delay_set(duration*8, addr+2, amp_max))   # 54 is the address of lim_X_lo
    # reg_list.extend(delay_set(0, addr, 0))                  # 52 is the address of lim_X_hi
    # reg_list.extend(delay_set(0, addr+2, 0))                  # 54 is the address of lim_X_lo

    # for jx in range(6):
    #    reg_list.extend(delay_set(0,0,0))

    for item in reg_list:
        if item.name != '':
            regmap[item.name] = item

    if (error_cnt > 0):
        print "# %d scaling errors found" % error_cnt
        exit(1)

    return regmap
Example #12
0
# this construction is for 20 MHz / 94.286 MHz = 7/33
dds_num = 7
dds_den = 33

# The following three parameters are set in the Verilog at compile-time,
# not run-time.  Top-level setting in vmod1_tb.v needs to be mirrored here.
lp_shift = 9  # see lp_pair.v, a.k.a. mode_shift
n_mech_modes = 7  # number of mechanical modes handled
df_scale = 9  # see cav4_freq.v

# ==== end of system configuration

# Read registers from regmap_gen_vmod1
sim_base = 0  # base address for vmod1
from read_regmap import get_map
regmap = get_map(regmap_file)
# ==== end of hardware register dictionaries

# scale a floating point number in range [-1,1) to fit in b-bit register
error_cnt = 0


def fix(x, b, msg, opt=None):
    global error_cnt
    ss = 2**(b - 1)
    # cordic_g = 1.646760258
    if (opt is "cordic"): ss = int(ss / 1.646760258)
    xx = int(x * ss + 0.5)
    #print x,b,ss,xx
    if (xx > ss - 1):
        xx = ss - 1
Example #13
0
from math import sin, cos, pi, sqrt, log
from numpy import log as clog
from numpy import exp as cexp
from numpy import ceil
# http://stackoverflow.com/questions/14132789/python-relative-imports-for-the-billionth-time
# Leaves me with only one choice ... :(
# Since I don't want to modify shell variables
import os, sys
sys.path.append(
    os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +
    "/submodules/build")
from read_regmap import get_map, get_reg_info

cav_num = 0

regmap_cryomodule = get_map("./_autogen/regmap_cryomodule.json")
#ctl_regmap = get_map("./_autogen/regmap_llrf_shell.json")
#c_reg_base = get_reg_info(regmap_cryomodule,[],'llrf_'+str(cav_num)+'_xxxx')['base_addr']

# Gang humbly requests that Q_1 be renamed Q_drive, and Q_2 as Q_probe.
# Should apply here, physics.tex, elsewhere?

# Note that Tstep is the ADC time step, also clocks the LLRF controller.
# Divide by two for the cavity simulator (rtsim) clock time step.
Tstep = 10e-9  # s
f0 = 1300e6  # Hz
nyquist_sign = -1  # -1 represents frequency inversion,
# as with high-side LO or even-numbered Nyquist zones.

VPmax = 48.0  # V piezo drive max