Exemplo n.º 1
0
 def __init__(self, sim_core, index, app_settings):
     rfnocsim.SimComp.__init__(self,
                               sim_core,
                               name='USRP_%03d' % (index),
                               ctype=rfnocsim.comptype.hardware)
     # USRP i carries data for radio 2i and 2i+1 interleaved into one stream
     self.index = index
     items = [
         rfnocsim.DataStream.submatrix_gen('rx', [2 * index]),
         rfnocsim.DataStream.submatrix_gen('rx', [2 * index + 1])
     ]
     # Samples are 4 bytes I and Q
     latency = (self.RADIO_LATENCY +
                self.IO_LATENCY / 2) * self.get_tick_rate()
     if app_settings['domain'] == 'frequency':
         # Max latency per direction depends on the FFT size and sample rate
         latency += self.__get_fft_latency(app_settings['fft_size'],
                                           app_settings['samp_rate'],
                                           self.get_tick_rate())
     # An X310 Radio has two producers (RX data) and consumers (TX data) (i.e. two ethernet ports)
     # Both ports can carry data from both radio frontends
     self.sources = ([
         rfnocsim.Producer(sim_core, self.name + '/TX0', self.BPI, items,
                           self.MAX_SAMP_RATE, latency),
         rfnocsim.Producer(sim_core, self.name + '/TX1', self.BPI, items,
                           self.MAX_SAMP_RATE, latency)
     ])
     self.sinks = ([
         rfnocsim.Consumer(sim_core, self.name + '/RX0',
                           self.BPI * self.MAX_SAMP_RATE, latency),
         rfnocsim.Consumer(sim_core, self.name + '/RX1',
                           self.BPI * self.MAX_SAMP_RATE, latency)
     ])
     # The actual sample rate depends over the wire depends on the radio sample rate,
     # the FFT size and FFT overlap
     for src in self.sources:
         if app_settings['domain'] == 'frequency':
             src.set_rate(app_settings['samp_rate'] *
                          (1.0 + (float(app_settings['fft_overlap']) /
                                  app_settings['fft_size'])))
         else:
             src.set_rate(app_settings['samp_rate'])
Exemplo n.º 2
0
    def __init__(self, sim_core, index, num_coeffs, switch_ports,
                 app_settings):
        rfnocsim.SimComp.__init__(self,
                                  sim_core,
                                  name='MGMT_HOST_%03d' % (index),
                                  ctype=rfnocsim.comptype.other)
        if app_settings['domain'] == 'frequency':
            k = app_settings['fft_size']
        else:
            k = app_settings['fir_taps']

        self.sources = dict()
        self.sinks = dict()
        for l in range(switch_ports):
            self.sources[l] = rfnocsim.Producer(
                sim_core, '%s/COEFF_%d' % (self.name, l), 4,
                ['coeff_%03d[%d]' % (index, l)], (10e9 / 8) / switch_ports, 0)
            self.sinks[l] = rfnocsim.Consumer(
                sim_core, self.name + '%s/ACK%d' % (self.name, l))
            self.sources[l].set_rate(k * num_coeffs *
                                     app_settings['coherence_rate'])
Exemplo n.º 3
0
    def config_bitstream(cls, bee7fpga, app_settings, fpga_addr):
        """
        Defines the FPGA behavior for the current FPGA. This function will make
        create the necessary simulation functions, connect them to IO lanes and
        define the various utilization metrics for the image.

        config_bitstream(bee7fpga, app_settings, fpga_addr):
        - bee7fpga: The FPGA simulation object being configured
        - fpga_addr: Address of the FPGA in 3-D space
        - app_settings: Application information
        """
        if len(fpga_addr) != 3:
            raise bee7fpga.SimCompError('fpga_addr must be 3-dimensional. Got ' + str(len(fpga_addr)))

        # Map that stores lane indices for all neighbors of this node
        (router_map, terminal_map) = cls.get_portmap(fpga_addr)
        # USRPs are connected in the X dimension (RTM) because it has SFP+ ports
        base_usrp_lane = terminal_map['X']

        DIM_WIDTH = 4       # Dimension size for the 3-D network
        MAX_USRPS = 4       # Max USRPs that can possibly be connected to each FPGA
        NUM_USRPS = 2       # Number of USRPs actually connected to each FPGA
        CHANS_PER_USRP = 2  # How many radio channels does each USRP have
        ALL_CHANS = list(range(pow(DIM_WIDTH, 3) * NUM_USRPS * CHANS_PER_USRP))

        # Each FPGA will forward the sample stream from each USRP to all of its
        # X-axis neighbors
        for ri in router_map['X']:
            for li in range(MAX_USRPS):  # li = GT Lane index
                bee7fpga.sim_core.connect(bee7fpga.serdes_i[base_usrp_lane + li], 0, bee7fpga.serdes_o[router_map['X'][ri] + li], 0)

        # Consequently, this FPGA will receive the USRP sample streams from each of
        # its X-axis neighbors. Define an internal bus to aggregate all the neighbor
        # streams with the native ones. Order the streams such that each FPGA sees the
        # same data streams.
        bee7fpga.int_samp_bus = dict()
        for i in range(DIM_WIDTH):
            for li in range(MAX_USRPS):  # li = GT Lane index
                bee7fpga.int_samp_bus[(MAX_USRPS*i) + li] = rfnocsim.Channel(
                    bee7fpga.sim_core, '%s/_INT_SAMP_%02d' % (bee7fpga.name,(MAX_USRPS*i) + li))
                ln_base = base_usrp_lane if i == fpga_addr['X'] else router_map['X'][i]
                bee7fpga.sim_core.connect(bee7fpga.serdes_i[ln_base + li], 0, bee7fpga.int_samp_bus[(MAX_USRPS*i) + li], 0)

        # Forward the X-axis aggregated sample streams to all Y-axis neighbors
        for ri in router_map['Y']:
            for li in range(DIM_WIDTH*DIM_WIDTH):  # li = GT Lane index
                bee7fpga.sim_core.connect(bee7fpga.int_samp_bus[li], 0, bee7fpga.serdes_o[router_map['Y'][ri] + li], 0)

        # What partial products will this FPGA compute?
        # Generate channel list to compute partial products
        pp_chans = list()
        for cg in range(DIM_WIDTH):     # cg = Channel group
            for r in range(NUM_USRPS):
                radio_num = cls.get_radio_num({'X':fpga_addr['X'], 'Y':fpga_addr['Y'], 'Z':cg}, r, NUM_USRPS)
                for ch in range(CHANS_PER_USRP):
                    pp_chans.append(radio_num*CHANS_PER_USRP + ch)

        # Instantiate partial product computer
        bee7fpga.func_pp_comp = PartialContribComputer(
            sim_core=bee7fpga.sim_core, name=bee7fpga.name+'/pp_computer/', size=DIM_WIDTH*DIM_WIDTH*NUM_USRPS,
            dst_chans=pp_chans,
            items_per_stream=CHANS_PER_USRP, app_settings=app_settings)
        bee7fpga.add_function(bee7fpga.func_pp_comp)

        # Partial product computer takes inputs from all Y-axis links
        for sg in range(DIM_WIDTH):     # sg = Group of sexdectects
            for qi in range(DIM_WIDTH):  # qi = GT Quad index
                for li in range(NUM_USRPS):
                    func_inln = (sg * DIM_WIDTH * NUM_USRPS) + (qi * NUM_USRPS) + li
                    if sg == fpga_addr['Y']:
                        bee7fpga.sim_core.connect(bee7fpga.int_samp_bus[(qi * DIM_WIDTH) + li], 0,
                            bee7fpga.func_pp_comp, func_inln)
                    else:
                        bee7fpga.sim_core.connect(bee7fpga.serdes_i[router_map['Y'][sg] + (qi * DIM_WIDTH) + li], 0,
                            bee7fpga.func_pp_comp, func_inln)

        # Internal bus to hold aggregated partial products
        bee7fpga.pp_bus = dict()
        for i in range(DIM_WIDTH*NUM_USRPS):
            bee7fpga.pp_bus[i] = rfnocsim.Channel(bee7fpga.sim_core, '%s/_INT_PP_%02d' % (bee7fpga.name,i))
            bee7fpga.sim_core.connect(bee7fpga.func_pp_comp, i, bee7fpga.pp_bus[i], 0)

        # Forward partial products to Z-axis neighbors
        for ri in router_map['Z']:
            for li in range(NUM_USRPS):  # li = GT Lane index
                bee7fpga.sim_core.connect(bee7fpga.pp_bus[ri*NUM_USRPS + li], 0, bee7fpga.serdes_o[router_map['Z'][ri] + li], 0)

        # Instantiate partial product adder
        bee7fpga.func_pp_comb = dict()
        for i in range(NUM_USRPS):
            bee7fpga.func_pp_comb[i] = PartialContribCombiner(
                sim_core=bee7fpga.sim_core, name=bee7fpga.name + '/pp_combiner_%d/'%(i),
                radix=DIM_WIDTH, app_settings=app_settings, reducer_filter=(ALL_CHANS, 'tx'),
                items_per_stream=CHANS_PER_USRP)
            bee7fpga.add_function(bee7fpga.func_pp_comb[i])

        # Aggregate partial products from Z-axis neighbors
        for u in range(NUM_USRPS):
            for ri in range(DIM_WIDTH):
                if ri in router_map['Z']:
                    bee7fpga.sim_core.connect(bee7fpga.serdes_i[router_map['Z'][ri] + u], 0, bee7fpga.func_pp_comb[u], ri)
                else:
                    bee7fpga.sim_core.connect(bee7fpga.pp_bus[ri*NUM_USRPS + u], 0, bee7fpga.func_pp_comb[u], ri)

        # Instantiate partial product adder
        for u in range(NUM_USRPS):
            bee7fpga.sim_core.connect(bee7fpga.func_pp_comb[u], 0, bee7fpga.serdes_o[base_usrp_lane + u], 0)

        # Coefficient consumer
        bee7fpga.coeff_sink = rfnocsim.Consumer(bee7fpga.sim_core, bee7fpga.name + '/coeff_sink', 10e9/8, 0.0)
        bee7fpga.sim_core.connect(bee7fpga.serdes_i[terminal_map['X'] + NUM_USRPS], 0, bee7fpga.coeff_sink, 0)