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)
def RRRRR(name, regmap, value, station_index=None, mode_index=None, addr_offset=0): if station_index is not None: if mode_index is not None: addr = get_reg_info(regmap_cryomodule, [station_index, mode_index], name)["base_addr"] else: addr = get_reg_info(regmap_cryomodule, [station_index], name)["base_addr"] else: addr = get_reg_info(regmap_cryomodule, [], name)["base_addr"] if type(value) is list: for i, v in enumerate(value): print addr_offset + addr + i, v, "#", name + "["+str(i)+"]" else: print addr_offset + addr, value, '#', name
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
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
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 }
def reg_read(self, name_list, hierarchy=[]): alist = [] for name in name_list: x = get_reg_info(self.regmap, hierarchy, name) if x is not None: addr = x['base_addr'] elif name in self.read_regmap: addr = self.read_regmap[name] elif name in list(self.read_regmap.values()): addr = name else: print(('unknown register:' + name + 'skipped')) addr = None if addr: alist.append(addr) return self.reg_read_alist(alist)
def gen_controller(controller_index, dds_phstep, dds_modulo): #set_ctl(addr, "ph_offset", -35800) # A change to offset the DDS phase, and match the signals between # cryomodule_tb and larger_tb 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 RRRRR('wave_samp_per', ctl_regmap, wave_samp_per, addr_offset=controller_base) RRRRR('wave_shift', ctl_regmap, wave_shift, addr_offset=controller_base) RRRRR('sel_thresh', ctl_regmap, 5000, addr_offset=controller_base) RRRRR('ph_offset', ctl_regmap, -150800, addr_offset=controller_base) RRRRR('sel_en', ctl_regmap, 1, addr_offset=controller_base) RRRRR('lp1a_kx', ctl_regmap, 20486, addr_offset=controller_base) RRRRR('lp1a_ky', ctl_regmap, -20486, addr_offset=controller_base) RRRRR('chan_keep', ctl_regmap, 4080, addr_offset=controller_base) addr = get_reg_info(ctl_regmap,[],'lim')['base_addr'] delay_pc=4096 def delay_set_new(ticks,addr,data): delay_pc += 4 print "%d %d # duration" %(delay_pc-4, ticks) print "%d %d # dest addr (%s)" %(delay_pc-3, addr, addr) print "%d %d # value_msb" %(delay_pc-2, int(data)/65536) print "%d %d # value_lsb" %(delay_pc-1, int(data)%65536) if 0: # FGEN print "3 300 # duration" print "4 5000 # amp_slope" print "7 22640 # amp_max" print "555 7600 # wait" print "10 36 # amp dest address (lim X hi)" print "12 38 # amp dest address (lim X lo)" else: # TGEN # delay_set(0, 'lim_X_hi', 22640) # delay_set(6000, 'lim_X_lo', 22640) # delay_set(0, 'lim_X_hi', 0) # delay_set(0, 'lim_X_lo', 0) delay_set_new(0, addr, 22640) delay_set_new(6000, addr+2, 22640) delay_set_new(0, addr, 0) delay_set_new(0, addr+2, 0) if (error_cnt > 0): print "# %d scaling errors found"%error_cnt exit(1)
def get_ctl_reg(name): r = get_reg_info(regmap_cryomodule, [0], name) return r
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 = 0 regmap_global = { 'dds_phstep': get_reg_info(regmap_cryomodule, [cav_num], "cav4_elec_phase_step")["base_addr"], 'dds_modulo': get_reg_info(regmap_cryomodule, [cav_num], "cav4_elec_modulo")["base_addr"], 'amp_bw': get_reg_info(regmap_cryomodule, [cav_num], "amp_lp_bw")["base_addr"], 'prompt': get_reg_info(regmap_cryomodule, [cav_num], "drive_couple_out_coupling") ["base_addr"], # base address of 4 registers 'cav_adc_off': get_reg_info(regmap_cryomodule, [cav_num], "a_cav_offset")["base_addr"], 'rfl_adc_off': get_reg_info(regmap_cryomodule, [cav_num], "a_rfl_offset")["base_addr"], 'fwd_adc_off': get_reg_info(regmap_cryomodule, [cav_num], "a_for_offset")["base_addr"], 'res_prop': get_reg_info(regmap_cryomodule, [cav_num], "resonator_prop_const")["base_addr"], 'dot_0_k': get_reg_info(regmap_cryomodule, [cav_num], ["dot_0_k_out"])["base_addr"], 'outer_0_k': get_reg_info(regmap_cryomodule, [cav_num], ["outer_prod_0_k_out"])["base_addr"], 'dot_1_k': get_reg_info(regmap_cryomodule, [cav_num], ["dot_1_k_out"])["base_addr"], 'outer_1_k': get_reg_info(regmap_cryomodule, [cav_num], ["outer_prod_1_k_out"])["base_addr"], 'dot_2_k': get_reg_info(regmap_cryomodule, [cav_num], ["dot_2_k_out"])["base_addr"], 'outer_2_k': get_reg_info(regmap_cryomodule, [cav_num], ["outer_prod_2_k_out"])["base_addr"], 'piezo_couple': get_reg_info(regmap_cryomodule, [cav_num], "piezo_couple")["base_addr"], 'noise_couple': get_reg_info(regmap_cryomodule, [cav_num], "noise_couple")["base_addr"] } # 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 # ==== 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 #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_coupling = [ 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") ] print out_coupling # 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") regmap_emode = { 'coarse_freq': get_reg_info(regmap_cryomodule, [cav_num, i], "coarse_freq")["base_addr"], 'drive_coupling': get_reg_info(regmap_cryomodule, [cav_num, i], "drive_coupling")["base_addr"], 'bw': get_reg_info(regmap_cryomodule, [cav_num, i], "bw")["base_addr"], 'out_coupling': get_reg_info(regmap_cryomodule, [cav_num, i], "out_coupling")["base_addr"] } # base address of 4 registers for n in regmap_emode: r = get_reg_info(regmap_cryomodule, [cav_num, i], n) regs.extend( set_reg(0, m.name + ".", n, regmap_emode, locals(), sim_base, r['name'])) 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, n) 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) r = get_reg_info(regmap_cryomodule, [cav_num], "prng_iva") r53 = push_seed(r["base_addr"], hf, r['name']) r = get_reg_info(regmap_cryomodule, [cav_num], "prng_ivb") r54 = push_seed(r["base_addr"], hf, r['name']) #print "%d 1 # turn on PRNG"%(52 + sim_base) regs.extend(r53) regs.extend(r54) regs.append( c_regs( 'turn on PRNG', get_reg_info(regmap_cryomodule, [cav_num], "prng_random_run")["base_addr"], 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)) r = get_ctl_reg('phase_step') regs.append(c_regs('phase_step', r['base_addr'], dds_phstep, r['name'])) r = get_ctl_reg('modulo') regs.append(c_regs('modulo', r['base_addr'], 4, r['name'])) r = get_ctl_reg('wave_samp_per') regs.append( c_regs('wave_samp_per', r['base_addr'], wave_samp_per, r['name'])) r = get_ctl_reg('wave_shift') regs.append(c_regs('wave_shift', r['base_addr'], wave_shift, r['name'])) r = get_ctl_reg('piezo_dc') regs.append(c_regs('piezo_dc', r['base_addr'], piezo_dc, r['name'])) r = get_ctl_reg('sel_thresh') regs.append(c_regs('sel_thresh', r['base_addr'], 5000, r['name'])) r = get_ctl_reg('ph_offset') regs.append(c_regs('ph_offset', r['base_addr'], ph_offset, r['name'])) r = get_ctl_reg('sel_en') regs.append(c_regs('sel_en', r['base_addr'], sel_en, r['name'])) r = get_ctl_reg('lp1a_kx') regs.append(c_regs('lp1a_kx', r['base_addr'], 20486, r['name'])) r = get_ctl_reg('lp1a_ky') regs.append(c_regs('lp1a_ky', r['base_addr'], -20486, r['name'])) #regs.append(c_regs('wait',555,150-12)) #regs.append(set_ctl('chan_keep',4080)) r = get_ctl_reg('chan_keep') regs.append(c_regs('chan_keep', r['base_addr'], 4080, r['name'])) #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))) r = get_ctl_reg('setmp') regs.append(c_regs('set_X', r['base_addr'], int(set_X), r['name'])) regs.append(c_regs('set_P', r['base_addr'] + 1, int(set_P), r['name'])) # 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)) r = get_ctl_reg('coeff') addr = r['base_addr'] regs.append(c_regs('coeff_X_I', addr + 0, -100, r['name'])) regs.append(c_regs('coeff_X_P', addr + 2, k_PA, r['name'])) regs.append(c_regs('coeff_Y_I', addr + 1, -100, r['name'])) regs.append(c_regs('coeff_Y_P', addr + 3, k_PP, r['name'])) # 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)) r = get_ctl_reg('lim') addr = r['base_addr'] regs.append(c_regs('lim_X_hi', addr + 0, 0, r['name'])) regs.append(c_regs('lim_Y_hi', addr + 1, 0, r['name'])) regs.append(c_regs('lim_X_lo', addr + 2, 0, r['name'])) regs.append(c_regs('lim_Y_lo', addr + 3, 0, r['name'])) 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 = get_reg_info(regmap_cryomodule, [0], 'XXX')['base_addr'] # 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)) regs.extend(delay_set(0, addr, amp_max)) # 52 is the address of lim_X_hi regs.extend(delay_set(duration * 8, addr + 2, amp_max)) # 54 is the address of lim_X_lo regs.extend(delay_set(0, addr, 0)) # 52 is the address of lim_X_hi regs.extend(delay_set(0, addr + 2, 0)) # 54 is the address of lim_X_lo for jx in range(6): regs.extend(delay_set(0, 0, 0)) regs.append(c_regs('Mode Select', 65536 + 554, 0)) if error_cnt > 0: print "# %d scaling errors found" % error_cnt #exit(1) global print_once if print_once == True: for r in regs: print r.print_regs() print_once = False return [regs, error_cnt]
def gen_cryomodule(station_count=2): emode_count = 2 mmode_count = 2 c_reg_base = [] VPmax = 48.0 # V piezo drive max emode1 = Emode("pi", RoverQ = 1036.0, foffset = 5.0, peakV = 1.5e6, Q_0 = 1e10, Q_1 = 8.1e4, Q_2 = 2e9, phase_1 = 0, phase_2 = 0) emode2 = Emode("8pi/9", RoverQ = 10.0, foffset = -8e5, peakV = 0.15e6, Q_0 = 1e10, Q_1 = 8.1e4, Q_2 = 2e9, phase_1 = 10.0, phase_2 = -180.0) # This mode is silly, but lets the frequency change on the time scale of # software simulation = 40 us mmode1 = Mmode("silly", freq = 30000, Q = 5.0, mx = 1.13, piezo_hack = 0, lorentz_en = 1) mmode2 = Mmode("piezo", freq = 100000, Q = 5.0, mx = 0, piezo_hack = 80000, lorentz_en = 0) for si in range(station_count): c_reg_base.append(get_reg_info(regmap_cryomodule,[],'llrf_'+str(si)+'_xxxx')['base_addr']) # Mechanical modes # Still may have bugs: # Mechanical mode coupling resonator_prop_const=[] piezo_couple=[] dot_0_k=[]; outer_prod_0_k=[] dot_1_k=[]; outer_prod_1_k=[] dot_2_k=[]; outer_prod_2_k=[] for i,m in enumerate([mmode1,mmode2]): 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 = exp(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) resonator_prop_const.append( (fix(a2,18,"a2")&(2**18-1)) + ((9-scale) << 18) ) resonator_prop_const.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 net_coupling = 130.0 # Hz / V^2, negative is implicit Amn = sqrt(net_coupling/emode1.RoverQ) / omega0 # sqrt(J)/V^2 Cmn = - sqrt(net_coupling*emode1.RoverQ) * omega0 # 1/s/sqrt(J) outer = m.lorentz_en * Amn / mmode1.mx * emode1.peakV**2 / dc_gain # dimensionless inner = m.lorentz_en * Cmn * mmode1.mx * Tstep / 2**df_scale / interp_gain # dimensionless # note that inner*outer = net_coupling * emode1.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 outer_prod_0_k.append(fix(outer/128,18,"outer")) outer_prod_0_k.append(0) dot_0_k.append(0) dot_0_k.append(fix(inner/128,18,"inner")) # Use second resonance to test piezo subsystem # The scaling is still non-quantitative piezo_couple.append(m.piezo_hack) piezo_couple.append(0) dot_2_k.append(0) dot_2_k.append(m.piezo_hack) for si in range(station_count): gen_station(si, dds_modulo, dds_phstep, [emode1, emode2]) RRRRR('dot_0_k', regmap_cryomodule, dot_0_k, si) RRRRR('dot_1_k', regmap_cryomodule, dot_1_k, si) RRRRR('dot_2_k', regmap_cryomodule, dot_2_k, si) RRRRR('outer_prod_0_k', regmap_cryomodule, outer_prod_0_k, si) RRRRR('outer_prod_1_k', regmap_cryomodule, outer_prod_1_k, si) RRRRR('outer_prod_2_k', regmap_cryomodule, outer_prod_2_k, si) RRRRR('piezo_couple', regmap_cryomodule, piezo_couple, si) #gen_controller(si, dds_modulo, dds_phstep) RRRRR('resonator_prop_const', regmap_cryomodule, resonator_prop_const) # TODO HACK: # Since the sole purpose of this file is to feed cryomodule_tb print "555 600 # Add delay of 600 cycles" print "14336 1 # Flip the circle buffer" print "14337 1 # Flip the circle buffer"
def gen_station(station_index, cav4_elec_phase_step, cav4_elec_modulo, emodes): # 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 = 0 # forward monitor phase shift phase_2 = 0 # reflected monitor prompt phase shift a_cav_offset = 10 a_rfl_offset = 30 a_for_offset = 20 amp_lp_bw = fix(Tstep*PAbw*32, 18, "amp_lp_bw") cav4_elec_phase_step = cav4_elec_phase_step cav4_elec_modulo = cav4_elec_modulo drive_couple_out_coupling = [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")] for i, m in enumerate(emodes): 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_out_coupling = [ 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") RRRRR('coarse_freq', regmap_cryomodule, coarse_freq, station_index, i) RRRRR('drive_coupling', regmap_cryomodule, drive_coupling, station_index, i) RRRRR('bw', regmap_cryomodule, bw, station_index, i) RRRRR('out_couple_out_coupling', regmap_cryomodule, out_couple_out_coupling, station_index, i) RRRRR('cav4_elec_phase_step', regmap_cryomodule, cav4_elec_phase_step, station_index) RRRRR('cav4_elec_modulo', regmap_cryomodule, cav4_elec_modulo, station_index) RRRRR('amp_lp_bw', regmap_cryomodule, amp_lp_bw, station_index) RRRRR('drive_couple_out_coupling', regmap_cryomodule, drive_couple_out_coupling, station_index) RRRRR('a_cav_offset', regmap_cryomodule, a_cav_offset, station_index) RRRRR('a_rfl_offset', regmap_cryomodule, a_rfl_offset, station_index) RRRRR('a_for_offset', regmap_cryomodule, a_for_offset, station_index) if prng_seed is not None: print "# PRNG subsystem seed is '%s'"%prng_seed hf = sha1() hf.update(prng_seed) push_seed(get_reg_info(regmap_cryomodule,[station_index],"prng_iva")["base_addr"],hf) push_seed(get_reg_info(regmap_cryomodule,[station_index],"prng_ivb")["base_addr"],hf) print "%d 1 # turn on PRNG"%(get_reg_info(regmap_cryomodule,[station_index],"prng_random_run")["base_addr"])
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)
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)
def get_cryo_reg(h, name): r = get_reg_info(regmap_cryomodule, h, name) return r
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
return else: # print "# Key not found: %s"%(name) return addr = regmap[name]['base_addr'] if type(val) is list: for i, v in enumerate(val): print('{} {} # {}'.format(addr + i, v, prefix + name + "[" + str(i) + "]")) else: print('{} {} # {}'.format(addr, val, prefix + name)) regmap_global = { 'beam_phase_step': get_reg_info(regmap, [], "beam_phase_step")["base_addr"], 'beam_modulo': get_reg_info(regmap, [], "beam_modulo")["base_addr"], 'drive_couple_out_coupling': get_reg_info(regmap, [], "drive_couple_out_coupling") ["base_addr"], # base address of 4 registers 'amp_lp_bw': get_reg_info(regmap, [], "amp_lp_bw")["base_addr"], 'a_cav_offset': get_reg_info(regmap, [], "a_cav_offset")["base_addr"], 'a_rfl_offset': get_reg_info(regmap, [], "a_rfl_offset")["base_addr"], 'a_for_offset': get_reg_info(regmap, [], "a_for_offset")["base_addr"], 'resonator_prop_const': get_reg_info(regmap, [], "resonator_prop_const")["base_addr"],
def get_ctl_reg_and_set(name, value): addr = get_reg_info(regmap_cryomodule, [0], name)['base_addr'] set_ctl(addr, name, value)
# 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 regmap_global = { 'dds_phstep': get_reg_info(regmap_cryomodule, [cav_num], "cav4_elec_phase_step")["base_addr"], 'dds_modulo': get_reg_info(regmap_cryomodule, [cav_num], "cav4_elec_modulo")["base_addr"], 'amp_bw': get_reg_info(regmap_cryomodule, [cav_num], "amp_lp_bw")["base_addr"], 'prompt': get_reg_info(regmap_cryomodule, [cav_num], "drive_couple_out_coupling") ["base_addr"], # base address of 4 registers 'cav_adc_off': get_reg_info(regmap_cryomodule, [cav_num], "a_cav_offset")["base_addr"], 'rfl_adc_off': get_reg_info(regmap_cryomodule, [cav_num], "a_rfl_offset")["base_addr"], 'fwd_adc_off': get_reg_info(regmap_cryomodule, [cav_num], "a_for_offset")["base_addr"], 'res_prop':