Source code for yellow_blocks.adc5g

from .yellow_block import YellowBlock
from verilog import VerilogModule
from constraints import PortConstraint, ClockConstraint, RawConstraint

from math import ceil, floor

[docs]class adc5g(YellowBlock):
[docs] def initialize(self): self.add_source('adc5g') self.add_source('adc5g/fifo_generator_0.xci') self.add_source('wb_adc5g_controller') self.zdok_num = int(self.adc_brd[-1]) # The block has an zdok_num variable of the form "ZDOK 0" self.provides = ['adc0_clk','adc0_clk90', 'adc0_clk180', 'adc0_clk270'] self.requires = ['zdok%d'%self.zdok_num] if self.demux != '1:1': raise ValueError("Only ADC5g demux 1:1 is supported") self.bitclk_rate = self.adc_clk_rate / 4. # 1/2 for demux (per input) by 2, 1/2 for DDR self.userclk_rate = self.adc_clk_rate / 8. # demux by 8 (per input) into simulink self.bitclk_period = 1./self.bitclk_rate * 1e3 #ns self.userclk_period = 1./self.userclk_rate * 1e3 #ns # get mode configuration stuff # assume only demux 1:1 if self.input_mode == 'One-channel -- A': self.mode = 'MODE_ACHAN_DMUX1' self.ctrl_mode = 0 self.chan_mode = 0 elif self.input_mode == 'One-channel -- C': self.ctrl_mode = 2 self.chan_mode = 0 self.mode = 'MODE_CCHAN_DMUX1' elif self.input_mode == 'Two-channel -- A&C': self.ctrl_mode = 4 self.chan_mode = 1 self.mode = 'MODE_2CHAN_DMUX1' else: raise ValueError("Unsupported ADC5g input mode %s" % self.input_mode) if self.test_ramp == 'on': self.mode = 'MODE_TEST_RAMP' self.clock_params = self._get_mmcm_params()
def _get_mmcm_params(self): # based on kintex 7 speed grade -1 (snap is -2) f_pfdmax = 450.0 f_pfdmin = 10.0 f_vcomax = 1200.0 f_vcomin = 600.0 allowed_d = list(range(1, 107)) allowed_m = list(range(2, 65)) # floatify #allowed_o0 = [1.0*i for i in range(1,128)] #allowed_o1 = [1.0*i for i in range(1,128)] allowed_o0 = list(range(1,128)) allowed_o1 = list(range(1,128)) # input clock to MMCM f_in = float(self.bitclk_rate) d_min = int(ceil(f_in / f_pfdmax)) d_max = int(floor(f_in / f_pfdmin)) m_min = int(ceil(d_min * f_vcomin / f_in)) m_max = int(floor(d_max * f_vcomax / f_in)) # Scan through d and m options. For each, figure out # what output dividers would be needed to get the correct # output frequencies. # if d, m, o0 and o1 meet the allowed criteria we're done for d in range(d_min, d_max+1): f_pfd = f_in / d for m in range(m_min, m_max+1): f_vco = f_pfd * m # target clock for o0 is bitclk_rate # target clock for o1 is userclk_rate = bitclk_rate / 8 o0 = f_vco / self.bitclk_rate o1 = f_vco / self.userclk_rate if d not in allowed_d: continue if m not in allowed_m: continue if o0 not in allowed_o0: continue if o1 not in allowed_o1: continue # force o0 and o1 to be ints. This is fine since we have already tested that they # are in the allowed list -- which are ints. rv = {'f_vco':f_vco, 'f_pfd':f_pfd, 'd':d, 'm':m, 'o0':int(o0), 'o1':int(o1)} print(rv) return rv # if we've got to here, there's no valid MMCM options raise RuntimeError("adc5g: No valid MMCM parameters found!")
[docs] def modify_top(self,top): module = 'adc5g_dmux1_interface' inst = top.get_instance(entity=module, name=self.fullname) inst.add_parameter('adc_bit_width', '8') inst.add_parameter('clkin_period ', '%.3f' % self.bitclk_period) inst.add_parameter('mode ', self.chan_mode) inst.add_parameter('mmcm_m ', '%.1f' % self.clock_params['m']) inst.add_parameter('mmcm_d ', '%d' % self.clock_params['d']) inst.add_parameter('mmcm_o0 ', '%.1f' % self.clock_params['o0']) inst.add_parameter('mmcm_o1 ', '%d' % self.clock_params['o1']) inst.add_parameter('bufr_div ', '1') inst.add_parameter('bufr_div_str ', '"1"') # physical ports inst.add_port('adc_clk_p_i ', self.fullname+'_adc_clk_p_i ', parent_port=True, dir='in') inst.add_port('adc_clk_n_i ', self.fullname+'_adc_clk_n_i ', parent_port=True, dir='in') inst.add_port('adc_sync_p ', self.fullname+'_adc_sync_p ', parent_port=True, dir='in') inst.add_port('adc_sync_n ', self.fullname+'_adc_sync_n ', parent_port=True, dir='in') inst.add_port('adc_data0_p_i ', self.fullname+'_adc_data0_p_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data0_n_i ', self.fullname+'_adc_data0_n_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data1_p_i ', self.fullname+'_adc_data1_p_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data1_n_i ', self.fullname+'_adc_data1_n_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data2_p_i ', self.fullname+'_adc_data2_p_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data2_n_i ', self.fullname+'_adc_data2_n_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data3_p_i ', self.fullname+'_adc_data3_p_i ', parent_port=True, dir='in', width=8) inst.add_port('adc_data3_n_i ', self.fullname+'_adc_data3_n_i ', parent_port=True, dir='in', width=8) # infrastructure outputs inst.add_port('ctrl_clk_in ', 'adc0_clk ') inst.add_port('ctrl_clk_out ', 'adc0_clk ') inst.add_port('ctrl_clk90_out ', 'adc0_clk90 ') inst.add_port('ctrl_clk180_out', 'adc0_clk180') inst.add_port('ctrl_clk270_out', 'adc0_clk270') # user ports inst.add_port('user_data_i0', self.fullname+'_user_data_i0', width=8) inst.add_port('user_data_i1', self.fullname+'_user_data_i1', width=8) inst.add_port('user_data_i2', self.fullname+'_user_data_i2', width=8) inst.add_port('user_data_i3', self.fullname+'_user_data_i3', width=8) inst.add_port('user_data_i4', self.fullname+'_user_data_i4', width=8) inst.add_port('user_data_i5', self.fullname+'_user_data_i5', width=8) inst.add_port('user_data_i6', self.fullname+'_user_data_i6', width=8) inst.add_port('user_data_i7', self.fullname+'_user_data_i7', width=8) inst.add_port('user_data_q0', self.fullname+'_user_data_q0', width=8) inst.add_port('user_data_q1', self.fullname+'_user_data_q1', width=8) inst.add_port('user_data_q2', self.fullname+'_user_data_q2', width=8) inst.add_port('user_data_q3', self.fullname+'_user_data_q3', width=8) inst.add_port('user_data_q4', self.fullname+'_user_data_q4', width=8) inst.add_port('user_data_q5', self.fullname+'_user_data_q5', width=8) inst.add_port('user_data_q6', self.fullname+'_user_data_q6', width=8) inst.add_port('user_data_q7', self.fullname+'_user_data_q7', width=8) inst.add_port('sync ', self.fullname+'_sync') # ports from software controller inst.add_port('dcm_reset ', self.fullname+'_dcm_reset ') inst.add_port('dcm_psclk ', self.fullname+'_dcm_psclk ') inst.add_port('dcm_psen ', self.fullname+'_dcm_psen ') inst.add_port('dcm_psincdec ', self.fullname+'_dcm_psincdec ') inst.add_port('ctrl_reset ', self.fullname+'_dcm_reset ') inst.add_port('adc_reset_o ', self.fullname+'_adc_reset_o ') inst.add_port('datain_pin ', self.fullname+'_datain_pin ', width=5) inst.add_port('datain_tap ', self.fullname+'_datain_tap ', width=5) inst.add_port('tap_rst ', self.fullname+'_tap_rst ') inst.add_port('fifo_full_cnt ', self.fullname+'_fifo_full_cnt ', width=16) inst.add_port('fifo_empty_cnt ', self.fullname+'_fifo_empty_cnt ', width=16) inst.add_port('ctrl_dcm_locked', self.fullname+'_dcm_locked ') inst.add_port('dcm_psdone ', self.fullname+'_dcm_psdone ') # ADC software controller # static name -- multiple ADCs on different ZDOK ports should pick up the same instance inst = top.get_instance(entity='wb_adc5g_controller', name='wb_adc5g_controller') inst.add_wb_interface(nbytes=512, regname='adc5g_controller', mode='rw') inst.add_parameter('INITIAL_CONFIG_MODE_%d' % self.zdok_num, '%d' % self.ctrl_mode) inst.add_port('adc%d_adc3wire_clk ' % self.zdok_num, self.fullname+'_adc3wire_clk ', parent_port=True, dir='out') inst.add_port('adc%d_adc3wire_data ' % self.zdok_num, self.fullname+'_adc3wire_data ', parent_port=True, dir='out') inst.add_port('adc%d_adc3wire_data_o ' % self.zdok_num, self.fullname+'_adc3wire_data_o ', parent_port=True, dir='in' ) inst.add_port('adc%d_adc3wire_spi_rst' % self.zdok_num, self.fullname+'_adc3wire_spi_rst', parent_port=True, dir='out') inst.add_port('adc%d_modepin ' % self.zdok_num, self.fullname+'_modepin ', parent_port=True, dir='out') inst.add_port('adc%d_reset ' % self.zdok_num, self.fullname+'_reset ', parent_port=True, dir='out') inst.add_port('adc%d_dcm_reset ' % self.zdok_num, self.fullname+'_dcm_reset ') inst.add_port('adc%d_dcm_locked ' % self.zdok_num, self.fullname+'_dcm_locked ') inst.add_port('adc%d_fifo_full_cnt ' % self.zdok_num, self.fullname+'_fifo_full_cnt ', width=16) inst.add_port('adc%d_fifo_empty_cnt ' % self.zdok_num, self.fullname+'_fifo_empty_cnt ', width=16) inst.add_port('adc%d_psclk ' % self.zdok_num, self.fullname+'_dcm_psclk ') inst.add_port('adc%d_psen ' % self.zdok_num, self.fullname+'_dcm_psen ') inst.add_port('adc%d_psincdec ' % self.zdok_num, self.fullname+'_dcm_psincdec ') inst.add_port('adc%d_psdone ' % self.zdok_num, self.fullname+'_dcm_psdone ') inst.add_port('adc%d_clk ' % self.zdok_num, 'adc0_clk ') inst.add_port('adc%d_tap_rst ' % self.zdok_num, self.fullname+'_tap_rst ') inst.add_port('adc%d_datain_pin ' % self.zdok_num, self.fullname+'_datain_pin ', width=5) inst.add_port('adc%d_datain_tap ' % self.zdok_num, self.fullname+'_datain_tap ', width=5)
[docs] def gen_constraints(self): cons = [] cons.append(PortConstraint(self.fullname+'_adc_clk_p_i ', 'zdok%d_p' % self.zdok_num, iogroup_index=39)) cons.append(PortConstraint(self.fullname+'_adc_clk_n_i ', 'zdok%d_n' % self.zdok_num, iogroup_index=39)) cons.append(PortConstraint(self.fullname+'_adc_sync_p ', 'zdok%d_p' % self.zdok_num, iogroup_index=38)) cons.append(PortConstraint(self.fullname+'_adc_sync_n ', 'zdok%d_n' % self.zdok_num, iogroup_index=38)) cons.append(PortConstraint(self.fullname+'_adc_data0_p_i ', 'zdok%d_p' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(8)))) cons.append(PortConstraint(self.fullname+'_adc_data0_n_i ', 'zdok%d_n' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(8)))) cons.append(PortConstraint(self.fullname+'_adc_data1_p_i ', 'zdok%d_p' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(10,18)))) cons.append(PortConstraint(self.fullname+'_adc_data1_n_i ', 'zdok%d_n' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(10,18)))) cons.append(PortConstraint(self.fullname+'_adc_data2_p_i ', 'zdok%d_p' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(20,28)))) cons.append(PortConstraint(self.fullname+'_adc_data2_n_i ', 'zdok%d_n' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(20,28)))) cons.append(PortConstraint(self.fullname+'_adc_data3_p_i ', 'zdok%d_p' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(30,38)))) cons.append(PortConstraint(self.fullname+'_adc_data3_n_i ', 'zdok%d_n' % self.zdok_num, port_index=list(range(8)), iogroup_index=list(range(30,38)))) cons.append(PortConstraint(self.fullname+'_adc3wire_clk ', 'zdok%d' % self.zdok_num, iogroup_index=17)) cons.append(PortConstraint(self.fullname+'_adc3wire_data ', 'zdok%d' % self.zdok_num, iogroup_index=18)) cons.append(PortConstraint(self.fullname+'_adc3wire_data_o ', 'zdok%d' % self.zdok_num, iogroup_index=19)) cons.append(PortConstraint(self.fullname+'_adc3wire_spi_rst', 'zdok%d' % self.zdok_num, iogroup_index=36)) cons.append(PortConstraint(self.fullname+'_modepin ', 'zdok%d' % self.zdok_num, iogroup_index=16)) cons.append(PortConstraint(self.fullname+'_reset ', 'zdok%d' % self.zdok_num, iogroup_index=37)) # clock constraint with variable period clkconst = ClockConstraint(self.fullname+'_adc_clk_p_i', name=self.fullname+'_adc5g_clk', freq=self.bitclk_rate) cons.append(clkconst) cons.append(RawConstraint('set_clock_groups -name async_sysclk_adcclk -asynchronous -group [get_clocks -include_generated_clocks %s] -group [get_clocks -include_generated_clocks sys_clk0_dcm]' % clkconst.name)) return cons