def cross_connect(gpio, chains): state_names = ["force"] + ["di%i" % i for i in range(len(gpio.i))] states = [1, gpio.i] signal_names = ["zero"] signals = Array([0]) for n, c in chains: for s in c.state_out: states.append(s) state_names.append("%s_%s" % (n, s.backtrace[-1][0])) for s in c.signal_out: signals.append(s) name = s.backtrace[-1][0] signal_names.append("%s_%s" % (n, name)) sig = CSRStatus(len(s), name=name) clr = CSR(name="%s_clr" % name) max = CSRStatus(len(s), name="%s_max" % name) min = CSRStatus(len(s), name="%s_min" % name) # setattr(c, sig.name, sig) setattr(c, clr.name, clr) setattr(c, max.name, max) setattr(c, min.name, min) c.comb += sig.status.eq(s) c.sync += If(clr.re | (max.status < s), max.status.eq(s)) c.sync += If(clr.re | (min.status > s), min.status.eq(s)) states = Cat(states) state = Signal(len(states)) gpio.comb += state.eq(states) gpio.state = CSRStatus(len(state)) gpio.state_clr = CSR() gpio.sync += [ If( gpio.state_clr.re, gpio.state.status.eq(0), ).Else(gpio.state.status.eq(gpio.state.status | state), ) ] # connect gpio output to "doi%i_en" for i, s in enumerate(gpio.o): csr = CSRStorage(len(state), name="do%i_en" % i) setattr(gpio, csr.name, csr) gpio.sync += s.eq((state & csr.storage) != 0) # connect state ins to "%s_en" and signal ins to "%s_sel" for n, c in chains: for s in c.state_in: csr = CSRStorage(len(state), name="%s_en" % s.backtrace[-1][0]) setattr(c, csr.name, csr) c.sync += s.eq((state & csr.storage) != 0) for s in c.signal_in: csr = CSRStorage(bits_for(len(signals) - 1), name="%s_sel" % s.backtrace[-1][0]) setattr(c, csr.name, csr) c.sync += s.eq(signals[csr.storage]) return state_names, signal_names
def connect_everything(self, width, signal_width): s = signal_width - width combined_error_signal = Signal((signal_width, True)) self.control_signal = Signal((signal_width, True)) self.sync += [ self.chain_a_offset_signed.eq(self.chain_a_offset.storage), self.chain_b_offset_signed.eq(self.chain_b_offset.storage), self.combined_offset_signed.eq(self.combined_offset.storage), self.out_offset_signed.eq(self.out_offset.storage), ] self.state_in = [] self.signal_in = [] self.state_out = [] self.signal_out = [self.control_signal, combined_error_signal] self.comb += [ combined_error_signal.eq(self.limit_error_signal.y), self.control_signal.eq( Array([self.limit_fast1.y, self.limit_fast2.y])[ self.control_channel.storage ] << s ), ]
def __init__(self, hit_channels, time, reset, clock): # parameters # inputs self.hit_channels = hit_channels self.reset = reset self.clock = clock # outputs self.time = time # internal signals self.meta_reg1 = Signal(self.NB_INPUTS) self.meta_reg2 = Signal(self.NB_INPUTS) self.edge_reg = Signal(self.NB_INPUTS) self.edge_detect = Signal(self.NB_INPUTS) self.hit_time_regs = Array( Signal(TIME_RES) for a in range(self.NB_INPUTS)) self.time_reg = Signal(TIME_RES) #### # edge detector with meta-stability removal register chain self.sync += [ self.meta_reg1.eq(self.hit_channels), self.meta_reg2.eq(self.meta_reg1), self.edge_reg.eq(self.meta_reg2), ] for i in range(self.NB_INPUTS): self.sync += [ If( self.edge_detect[i], # pulse detected self.hit_time_regs[i].eq( self.clock) # update hit register ).Elif( self.reset.data == 1, self.hit_time_regs[i].eq(0), ).Elif( self.hit_time_regs[i] != 0, # reset hit register self.hit_time_regs[i].eq(0)) ] self.comb += [ self.time_reg.eq(self.hit_time_regs[0] | self.hit_time_regs[1]) ] self.comb += [ self.reset.ready.eq(1), self.time.data.eq(self.time_reg), self.edge_detect.eq(~self.edge_reg & self.meta_reg2), # edge detection # output logic If(self.time_reg != 0, self.time.valid.eq(1)).Else(self.time.valid.eq(0)) ]
def __init__(self, max_decimation): self.decimation = Signal(max_decimation) self.decimation_counter = Signal(max_decimation) self.sync += [self.decimation_counter.eq(self.decimation_counter + 1)] self.output = Signal(1) self.sync += [ self.output.eq(Array(self.decimation_counter)[self.decimation]) ]
def migen_body(self, template): # generics N_BITS = template.generics["N_BITS"] # 1-64 N_INPUTS = template.generics["N_INPUTS"] TREE_DEPTH = int(ceil(log2(N_INPUTS))) # inputs self.d_in = template.add_pa_in_port( 'd_in', dl.DOptional(dl.DInt(dl.DSize(N_BITS * N_INPUTS)))) self.cmd = template.add_pa_in_port('cmd', dl.DOptional(dl.DInt())) # outputs self.d_out = template.add_pa_out_port('d_out', dl.DInt()) self.err = template.add_pa_out_port('error', dl.DInt()) # input length correction [need a power of 2 sized tree] N_INPUTS_CORR = pow(2, TREE_DEPTH) # internals # correct the size of the input tree to be a power of 2 # and register the inputs self.d_in_full_reg = Signal(N_INPUTS_CORR * N_BITS) self.d_in_valid_reg = Signal(1) self.cmd_data_reg = Signal(8) self.cmd_valid_reg = Signal(1) # register outputs self.d_out_data_reg = Signal(N_BITS + TREE_DEPTH) self.d_out_valid_reg = Signal(1) self.err_data_reg = Signal(1) self.err_valid_reg = Signal(1) # create the 2D array of data [INPUTS x TREE_DEPTH] to route # all the core units in an iterative way. The number of bits is incremented # at each stage to account for the carry in additions. self.d_pipe = Array( Array(Signal(N_BITS + b) for a in range(N_INPUTS_CORR)) for b in range(TREE_DEPTH + 1)) # create the 2D array of error signals. self.e_pipe = Array( Array(Signal(N_BITS) for a in range(N_INPUTS_CORR)) for b in range(TREE_DEPTH)) ### # correct input vector length to match a power of 2. # fill non-provided inputs with 0's (affects mean and minimum) self.sync += [ self.d_in_full_reg.eq(self.d_in.data), self.d_in_valid_reg.eq(self.d_in.valid), self.cmd_data_reg.eq(self.cmd.data), self.cmd_valid_reg.eq(self.cmd.valid) ] # wiring inputs to the first stage of the tree for i in range(N_INPUTS_CORR): self.comb += [ self.d_pipe[0][i].eq(self.d_in_full_reg[N_BITS * i:N_BITS * (i + 1)]) ] # instantiation of the core units. for j in range(TREE_DEPTH): for i in range(int(N_INPUTS_CORR / (pow(2, j + 1)))): self.submodules += CoreUnit(self.d_pipe[j][2 * i], self.d_pipe[j][2 * i + 1], self.d_pipe[j + 1][i], self.cmd_data_reg, self.e_pipe[j][i], N_BITS) # error signal propagation. If any of the single units have # a high error signal, the error is propagated to the node's output. self.comb += [ If(self.e_pipe[j][i] == 1, self.err_data_reg.eq(1)) ] self.comb += [ self.d_in.ready.eq(1), self.cmd.ready.eq(1), self.d_out_data_reg.eq(self.d_pipe[TREE_DEPTH][0]), If(self.d_in_valid_reg, self.err_valid_reg.eq(1), self.d_out_valid_reg.eq(1)).Else(self.err_valid_reg.eq(0)) ] self.sync += [ self.d_out.data.eq(self.d_out_data_reg), self.d_out.valid.eq(self.d_out_valid_reg), self.err.data.eq(self.err_data_reg), self.err.valid.eq(self.err_valid_reg) ]
def __init__(self, width=14, N_points=16383, max_delay=16383): self.init_submodules(width, N_points, max_delay) peak_height_bit, x_data_length_bit = self.init_csr(N_points) self.init_inout_signals(width) # is the autolock actively trying to detect peaks? This is set to true # if lock is requested and once the ramp is at start watching = Signal() # the following signals are property of the peak that the autolock is # trying to detet right now self.current_instruction_idx = Signal( bits_for(AUTOLOCK_MAX_N_INSTRUCTIONS - 1)) current_peak_height = Signal((peak_height_bit, True)) abs_current_peak_height = Signal.like(current_peak_height) current_wait_for = Signal(x_data_length_bit) self.comb += [ current_peak_height.eq( Array([ peak_height.storage for peak_height in self.peak_heights ])[self.current_instruction_idx]), current_wait_for.eq( Array([wait_for.storage for wait_for in self.wait_for ])[self.current_instruction_idx]), ] # after detecting the last peak, how many cycles have passed? waited_for = Signal(bits_for(N_points)) # after all peaks have been detected, how many cycles have passed? final_waited_for = Signal(bits_for(N_points)) # this is the signal that's used for detecting peaks sum_diff = Signal((len(self.sum_diff_calculator.output), True)) abs_sum_diff = Signal.like(sum_diff) self.comb += [ self.sum_diff_calculator.writing_data_now.eq( self.writing_data_now), self.sum_diff_calculator.restart.eq(self.at_start), self.sum_diff_calculator.input.eq(self.input), self.sum_diff_calculator.delay_value.eq(self.time_scale.storage), sum_diff.eq(self.sum_diff_calculator.output), ] # has this signal at the moment the same sign as the peak we are looking # for? sign_equal = Signal() # is this signal higher than the peak we are looking for? over_threshold = Signal() # since detecting the previous peak, has enough time passed? waited_long_enough = Signal() # have we detected all peaks (and can turn on the lock)? all_instructions_triggered = Signal() self.comb += [ sign_equal.eq((sum_diff > 0) == (current_peak_height > 0)), If(sum_diff >= 0, abs_sum_diff.eq(sum_diff)).Else(abs_sum_diff.eq(-1 * sum_diff)), If( current_peak_height >= 0, abs_current_peak_height.eq(current_peak_height), ).Else(abs_current_peak_height.eq(-1 * current_peak_height)), over_threshold.eq(abs_sum_diff >= abs_current_peak_height), waited_long_enough.eq(waited_for > current_wait_for), all_instructions_triggered.eq( self.current_instruction_idx >= self.N_instructions.storage), self.turn_on_lock.eq( all_instructions_triggered & (final_waited_for >= self.final_wait_time.storage)), ] self.sync += [ If( self.at_start, waited_for.eq(0), # fpga robust autolock algorithm registeres trigger events delayed. # Therefore, we give it a head start for `final_waited_for` final_waited_for.eq(ROBUST_AUTOLOCK_FPGA_DELAY), self.current_instruction_idx.eq(0), If(self.request_lock, watching.eq(1)).Else(watching.eq(0)), ).Else( # not at start If( ~self.request_lock, # disable `watching` if `request_lock` was disabled while # the ramp is running. This is important for slow scan # speeds when disabling the autolock and enabling it again # with different parameters. In this case we want to take # care that we start watching at start. watching.eq(0), ), If( self.writing_data_now & ~all_instructions_triggered & self.sweep_up, If( watching & sign_equal & over_threshold & waited_long_enough, self.current_instruction_idx.eq( self.current_instruction_idx + 1), waited_for.eq(0), ).Else(waited_for.eq(waited_for + 1)), ), If( self.writing_data_now & all_instructions_triggered & self.sweep_up, final_waited_for.eq(final_waited_for + 1), ), ), ] self.signal_out = [] self.signal_in = [] self.state_out = [ watching, self.turn_on_lock, sign_equal, over_threshold, waited_long_enough, ] self.state_in = []
def __init__(self, width=25): self.gpio_trigger = Signal() self.sweep_trigger = Signal() # when lock is disabled and sweep enabled, acquisition process arms the # scope, waits until scope has triggered and reads out the data. Once # data is read out, it rearms the acquisition. When robust autolock is # looking for a lock point, acquisition process doesn't send any triggers # though because it doesn't transmit any data until lock is confirmed. # Therefore, autolock turns on "always_arm" mode which automatically # rearms scope when it has finished. self.automatically_rearm = Signal() # this mode is used when the laser is locked. In this case we don't have # to sync acquisition with a ramp. Synchronisation with readout takes # place by manually rearming after reading out the data. self.automatically_trigger = Signal() automatic_trigger_signal = Signal() self.sync += [ If(self.automatically_trigger, automatic_trigger_signal.eq(~automatic_trigger_signal) ).Else( automatic_trigger_signal.eq(0) ) ] self.external_trigger = CSRStorage(1) ext_scope_trigger = Array([self.gpio_trigger, self.sweep_trigger])[ self.external_trigger.storage ] self.scope_sys = Record(sys_layout) self.asg_sys = Record(sys_layout) adc_a = Signal((width, True)) adc_a_q = Signal((width, True)) adc_b = Signal((width, True)) adc_b_q = Signal((width, True)) dac_a = Signal((width, True)) dac_b = Signal((width, True)) self.signal_in = adc_a, adc_b, adc_a_q, adc_b_q self.signal_out = dac_a, dac_b self.state_in = () self.state_out = () asg_a = Signal((14, True)) asg_b = Signal((14, True)) asg_trig = Signal() s = width - len(asg_a) self.comb += dac_a.eq(asg_a << s), dac_b.eq(asg_b << s) # these signals will be connected to autolock which inspects written data self.writing_data_now = Signal() self.scope_written_data = Signal((14, True)) self.scope_position = Signal(14) self.specials.scope = Instance( "red_pitaya_scope", i_automatically_rearm_i=self.automatically_rearm, i_adc_a_i=adc_a >> s, i_adc_b_i=adc_b >> s, i_adc_a_q_i=adc_a_q >> s, i_adc_b_q_i=adc_b_q >> s, # i_adc_a_q_i=0b11111111111111, # i_adc_b_q_i=0b11111111111111, i_adc_clk_i=ClockSignal(), i_adc_rstn_i=~ResetSignal(), i_trig_ext_i=ext_scope_trigger | automatic_trigger_signal, i_trig_asg_i=asg_trig, i_sys_clk_i=self.scope_sys.clk, i_sys_rstn_i=self.scope_sys.rstn, i_sys_addr_i=self.scope_sys.addr, i_sys_wdata_i=self.scope_sys.wdata, i_sys_sel_i=self.scope_sys.sel, i_sys_wen_i=self.scope_sys.wen, i_sys_ren_i=self.scope_sys.ren, o_sys_rdata_o=self.scope_sys.rdata, o_sys_err_o=self.scope_sys.err, o_sys_ack_o=self.scope_sys.ack, o_written_data=self.scope_written_data, o_scope_position=self.scope_position, o_scope_writing_now=self.writing_data_now, )
def __init__(self, width=14, signal_width=25, coeff_width=18, mod=None, offset_signal=None): self.adc = Signal((width, True)) # output of in-phase demodulated signal self.out_i = Signal((signal_width, True)) # output of quadrature demodulated signal self.out_q = Signal((signal_width, True)) self.y_tap = CSRStorage(2) self.invert = CSRStorage(1) self.state_in = [] self.state_out = [] x = Signal((signal_width, True)) dx = Signal((signal_width, True)) dy = Signal((signal_width, True)) self.signal_in = dx, dy self.signal_out = x, self.out_i, self.out_q ### self.submodules.demod = Demodulate(width=width) ### s = signal_width - width self.comb += [ x.eq(self.adc << s), self.demod.x.eq(self.adc), self.demod.phase.eq(mod.phase), ] ya = Signal((width + 3, True)) self.sync += (ya.eq(((dy >> s))), ) ### def init_submodule(name, submodule): setattr(self.submodules, name, submodule) # iterate over in-phase and quadrature signal # both have filters and limits for sub_channel_idx in (0, 1): x_limit = LimitCSR(width=signal_width, guard=1) init_submodule("x_limit_%d" % (sub_channel_idx + 1), x_limit) iir_c = Iir( width=signal_width, coeff_width=coeff_width, shift=coeff_width - 2, order=1, ) init_submodule("iir_c_%d" % (sub_channel_idx + 1), iir_c) iir_d = Iir( width=signal_width, coeff_width=coeff_width, shift=coeff_width - 2, order=2, ) init_submodule("iir_d_%d" % (sub_channel_idx + 1), iir_d) y_limit = LimitCSR(width=signal_width, guard=3) init_submodule("y_limit_%d" % (sub_channel_idx + 1), y_limit) self.comb += [ x_limit.x.eq( ([self.demod.i, self.demod.q][sub_channel_idx] << s) + dx), iir_c.x.eq(x_limit.y), iir_c.hold.eq(0), iir_c.clear.eq(0), iir_d.x.eq(iir_c.y), iir_d.hold.eq(0), iir_d.clear.eq(0), ] ys = Array([iir_c.x, iir_c.y, iir_d.y]) self.comb += [ y_limit.x.eq( Mux(self.invert.storage, -1, 1) * (ys[self.y_tap.storage] + (ya << s) + (offset_signal << s))), (self.out_i, self.out_q)[sub_channel_idx].eq(y_limit.y), ]