Beispiel #1
0
 def load_ip_data(cls, ip_name, data):
     """This method writes data to the addressable IP.
     
     Note
     ----
     The data is assumed to be in binary format (.bin). The data 
     name will be stored as a state information in the IP dictionary.
     
     Parameters
     ----------
     ip_name : str
         The name of the addressable IP.
     data : str
         The absolute path of the data to be loaded.
     
     Returns
     -------
     None
     
     """
     cls._client_request()
     with open(data, 'rb') as bin:
         size = (math.ceil(os.fstat(bin.fileno()).st_size/ \
                 mmap.PAGESIZE))*mmap.PAGESIZE
         mmio = MMIO(int(cls._ip_dict[ip_name][0], 16), size)
         buf = bin.read(size)
         mmio.write(0, buf)
         
     cls._ip_dict[ip_name][2] = data
     cls._server_update()
Beispiel #2
0
def test_mmio():
    """Test whether MMIO class is working properly.
    
    Generate random tests to swipe through the entire range:
    
    >>> mmio.write(all offsets, random data)
    
    Steps:
    
    1. Initialize an instance with length in bytes
    
    2. Write an integer to a given offset.
    
    3. Write a number within the range [0, 2^32-1] into a 4-byte location.
    
    4. Change to the next offset and repeat.
    
    """
    ol = Overlay('base.bit')
    
    ol.download()
    sleep(0.2)
    mmio_base = int(ol.get_ip_addr_base('SEG_mb_bram_ctrl_1_Mem0'),16)
    mmio_range = int(ol.get_ip_addr_range('SEG_mb_bram_ctrl_1_Mem0'),16)
    mmio = MMIO(mmio_base, mmio_range)
    for offset in range(0, 100, general_const.MMIO_WORD_LENGTH):
        data1 = randint(0, pow(2,32)-1)
        mmio.write(offset, data1)
        sleep(0.02)
        data2 = mmio.read(offset)
        assert data1==data2, \
            'MMIO read back a wrong random value at offset {}.'.format(offset)
        mmio.write(offset, 0)
        sleep(0.02)
        assert mmio.read(offset)==0, \
            'MMIO read back a wrong fixed value at offset {}.'.format(offset)
            
    del ol
    
Beispiel #3
0
class LR_Accel:
    """
    Python class for the LR Accelerator.
    """
    
    def __init__(self, chunkSize, numClasses, numFeatures):
        self.numClasses = numClasses
        self.numFeatures = numFeatures
           
        # -------------------------
        #   Download Overlay.
        # -------------------------    

        ol = Overlay("LogisticRegression.bit")
        ol.download()  
        
        # -------------------------
        #   Physical address of the Accelerator Adapter IP.
        # -------------------------

        ADDR_Accelerator_Adapter_BASE = int(PL.ip_dict["SEG_LR_gradients_kernel_accel_0_if_Reg"][0], 16)
        ADDR_Accelerator_Adapter_RANGE = int(PL.ip_dict["SEG_LR_gradients_kernel_accel_0_if_Reg"][1], 16)

        # -------------------------
        #    Initialize new MMIO object. 
        # -------------------------

        self.bus = MMIO(ADDR_Accelerator_Adapter_BASE, ADDR_Accelerator_Adapter_RANGE)

        # -------------------------
        #   Physical addresses of the DMA IPs.
        # -------------------------

        ADDR_DMA0_BASE = int(PL.ip_dict["SEG_dm_0_Reg"][0], 16)
        ADDR_DMA1_BASE = int(PL.ip_dict["SEG_dm_1_Reg"][0], 16)
        ADDR_DMA2_BASE = int(PL.ip_dict["SEG_dm_2_Reg"][0], 16)
        ADDR_DMA3_BASE = int(PL.ip_dict["SEG_dm_3_Reg"][0], 16)

        # -------------------------
        #    Initialize new DMA objects. 
        # -------------------------

        self.dma0 = DMA(ADDR_DMA0_BASE, direction = DMA_TO_DEV)    # data1 DMA.
        self.dma1 = DMA(ADDR_DMA1_BASE, direction = DMA_TO_DEV)    # data2 DMA.
        self.dma2 = DMA(ADDR_DMA2_BASE, direction = DMA_TO_DEV)    # weights DMA.
        self.dma3 = DMA(ADDR_DMA3_BASE, direction = DMA_FROM_DEV)  # gradients DMA.
        
        # -------------------------
        #    Allocate physically contiguous memory buffers.
        # -------------------------

        self.dma0.create_buf(int(chunkSize / 2) * (self.numClasses + (1 + self.numFeatures)) * 4, 1)
        self.dma1.create_buf(int(chunkSize / 2) * (self.numClasses + (1 + self.numFeatures)) * 4, 1)
        self.dma2.create_buf((self.numClasses * (1 + self.numFeatures)) * 4, 1)
        self.dma3.create_buf((self.numClasses * (1 + self.numFeatures)) * 4, 1)

        # -------------------------
        #    Get CFFI pointers to objects' internal buffers.
        # -------------------------

        self.data1_buf = self.dma0.get_buf(32, data_type = "float")
        self.data2_buf = self.dma1.get_buf(32, data_type = "float")
        self.weights_buf = self.dma2.get_buf(32, data_type = "float")
        self.gradients_buf = self.dma3.get_buf(32, data_type = "float")

    def gradients_kernel(self, data, weights):
        chunkSize = int(len(data) / (self.numClasses + (1 + self.numFeatures)))
        
        for i in range (0, int(len(data) / 2)):
            self.data1_buf[i] = float(data[i])
            self.data2_buf[i] = float(data[int(len(data) / 2) + i])
        for kj in range (0, self.numClasses * (1 + self.numFeatures)):
            self.weights_buf[kj] = float(weights[kj])

        # -------------------------
        #   Write data to MMIO.
        # -------------------------

        CMD = 0x0028            # Command.
        ISCALAR0_DATA = 0x0080  # Input Scalar-0 Write Data FIFO.

        self.bus.write(ISCALAR0_DATA, int(chunkSize))
        self.bus.write(CMD, 0x00010001)
        self.bus.write(CMD, 0x00020000)
        self.bus.write(CMD, 0x00000107)

        # -------------------------
        #   Transfer data using DMAs (Non-blocking).
        #   Block while DMAs are busy.
        # -------------------------

        self.dma0.transfer(int(len(data) / 2) * 4, direction = DMA_TO_DEV)
        self.dma1.transfer(int(len(data) / 2) * 4, direction = DMA_TO_DEV)
        self.dma2.transfer((self.numClasses * (1 + self.numFeatures)) * 4, direction = DMA_TO_DEV)

        self.dma0.wait()
        self.dma1.wait()
        self.dma2.wait()

        self.dma3.transfer((self.numClasses * (1 + self.numFeatures)) * 4, direction = DMA_FROM_DEV)

        self.dma3.wait()

        gradients = []
        for kj in range (0, self.numClasses * (1 + self.numFeatures)):
            gradients.append(float(self.gradients_buf[kj]))

        return gradients
    
    def __del__(self):

        # -------------------------
        #   Destructors for DMA objects.
        # -------------------------

        self.dma0.__del__()
        self.dma1.__del__()
        self.dma2.__del__()
        self.dma3.__del__()
Beispiel #4
0
class LightCube(object):
    def __init__(self):
        LightCubeOverlay("lightcube.bit")
        self.ip = MMIO(0X43C00000, 0X10000)
        self.bram = MMIO(0X40000000, 0X2000)
        self.socketio = SocketIO(app)
        self.clear()
        self.func_group = {
            'Scan Left and Right': self.lr_scan,
            'Scan Front and Back': self.fb_scan,
            'Scan Top and Bottom': self.tb_scan,
            'Roll X': self.roll_x, 'Roll Y': self.roll_y, 'Roll Z': self.roll_z,
            'Hollow Cubes': self.cube_h, 'Solid Cubes': self.cube_s,
            'Falling Rain': self.rain_down, 'Rising Rain': self.rain_up,
            'Hollow Spinner': self.spinner_0, 'Solid Spinner': self.spinner_1,
            'Curved Spinner': self.spinner_c,
            'Sandglass': self.sandglass_b,
            'Blink': self.blink_b, 'All On': self.on,
            'Show On-board Demo': self.show_board_demo,
            'Control from Web': self.read_py_ctrl
        }

    def start(self):
        self.ip.write(ADDR, 0X00)
        self.ip.write(MODE, 0X01)

    def change_mode(self, mode):
        self.ip.write(MODE, mode)
        self.non()

    def run(self, timeout=0.2):
        self.socketio.emit('run', self.get_xyz())
        start = time.time()
        while True:
            while not self.ip.read(DONE):
                pass
            for i in range(64):
                self.bram.write(0X4 * i, self.arr[63 - i])
            self.ip.write(RUN, 0X01)
            self.ip.write(RUN, 0X00)
            if timeout + start - time.time() <= 0:
                break

    def clear(self):
        self.arr = [0X00] * 64

    def get_xyz(self):
        x1, y1, z1 = [], [], []
        x2, y2, z2 = [], [], []
        for z in range(8):
            for x in range(8):
                for y in range(8):
                    if self.arr[8 * z + x] & (0X01 << y):
                        x1.append(x)
                        y1.append(y)
                        z1.append(7 - z)
                    else:
                        x2.append(x)
                        y2.append(y)
                        z2.append(7 - z)
        return {
            'x1': x1, 'y1': y1, 'z1': z1,
            'x2': x2, 'y2': y2, 'z2': z2
        }

    def toggle_xyz(self, x, y, z):
        val = self.arr[8 * z + x] & (0X01 << y)
        if val:
            self.arr[8 * z + x] &= ~(0x01 << y)
        else:
            self.arr[8 * z + x] |= 0x01 << y

    def display_ctrls(self):
        words = [
            'Scan Left and Right',
            'Scan Front and Back',
            'Scan Top and Bottom',
            'Roll X', 'Roll Y', 'Roll Z',
            'Hollow Cubes', 'Solid Cubes',
            'Falling Rain', 'Rising Rain',
            'Hollow Spinner', 'Solid Spinner', 'Curved Spinner',
            'Sandglass', 'Blink', 'All On',
            'Control from Web', 'Show On-board Demo'
        ]
        show = [False] * len(words)
        items = [Button(description=words[i], disabled=show[i],
                        button_style='', tooltip=words[i])
                 for i in range(len(words))]
        for i in range(len(words)):
            items[i].on_click(self.func_group[words[i]])
        scan_box_0 = HBox([items[0], items[1], items[2]])
        scan_box_1 = HBox([items[3], items[4], items[5]])
        scan_box_2 = HBox([items[6], items[7]])
        scan_box_3 = HBox([items[8], items[9]])
        scan_box_4 = HBox([items[10], items[11], items[12]])
        scan_box_5 = HBox([items[13], items[14], items[15]])
        scan_box_6 = VBox([items[16], items[17]])
        return HBox([
            VBox([scan_box_0, scan_box_1, scan_box_2,
                  scan_box_3, scan_box_4, scan_box_5]),
            VBox([scan_box_6])])

    def read_py_ctrl(self, b):
        self.change_mode(1)

    def show_board_demo(self, b):
        self.change_mode(0)

    def lr_scan(self, b):
        for i in range(5):
            self.l2r_scan()
            self.r2l_scan()
        self.non()

    def lr_scan_web(self):
        for i in range(5):
            self.l2r_scan()
            self.r2l_scan()
        self.non()

    def fb_scan(self, b):
        for i in range(5):
            self.f2b_scan()
            self.b2f_scan()
        self.non()

    def tb_scan(self, b):
        for i in range(5):
            self.u2d_scan()
            self.d2u_scan()
        self.non()

    def roll_x(self, b):
        self.xcw(2)
        self.xacw(2)
        self.xcw(2)
        self.xacw(2)
        self.xcw(2)
        self.non()

    def roll_y(self, b):
        self.ycw(2)
        self.yacw(2)
        self.ycw(2)
        self.yacw(2)
        self.ycw(2)
        self.non()

    def roll_z(self, b):
        self.zcw(2)
        self.zacw(2)
        self.zcw(2)
        self.zacw(2)
        self.zcw(2)
        self.non()

    def cube_h(self, b):
        for i in range(2):
            self.cube(0, 0)
            self.cube(0, 1)
            self.cube(0, 3)
            self.cube(0, 2)
        self.non()

    def cube_s(self, b):
        for i in range(2):
            self.cube(1, 0)
            self.cube(1, 1)
            self.cube(1, 3)
            self.cube(1, 2)
        self.non()

    def rain_down(self, b):
        self.rain(0, 10)
        self.non()

    def rain_up(self, b):
        self.rain(1, 10)
        self.non()

    def spinner_0(self, b):
        self.spinner(0, 0)
        self.spinner(0, 1)
        self.non()

    def spinner_1(self, b):
        self.spinner(1, 0)
        self.spinner(1, 1)
        self.non()

    def spinner_c(self, b):
        self.curved_spinner(0)
        self.curved_spinner(1)
        self.non()

    def sandglass_b(self, b):
        self.sandglass()
        self.non()

    def blink_b(self, b):
        self.blink(20)
        self.non()

    def on(self, b):
        self.all(10)
        self.non()

    def test(self, mode):
        self.clear()
        if mode:
            for i in range(64):
                self.arr[i] = TEST_1[i]
        else:
            for i in range(64):
                self.arr[i] = TEST_0[i]
        self.run()

    def all(self, nums=10):
        self.arr = [0XFF] * 64
        for num in range(nums - 1, -1, -1):
            self.run()

    def non(self, nums=10):
        self.clear()
        for num in range(nums - 1, -1, -1):
            self.run()

    def blink(self, nums=10):
        for num in range(nums - 1, -1, -1):
            self.arr = [0XFF] * 64
            self.run(0.2)
            self.arr = [0X00] * 64
            self.run(0.2)

    def floor_fill(self):
        self.clear()
        self.run()
        for z in range(8):
            for x in range(8):
                self.arr[z * 8 + x] = 0XFF
                self.run()
        for z in range(8):
            for x in range(8):
                self.arr[z * 8 + x] = 0X00
                self.run()

    def l2r_scan(self):
        self.clear()
        for z in range(8):
            self.arr[z * 8] = 0XFF
        self.run()
        for x in range(1, 8):
            for z in range(8):
                self.arr[z * 8 + x] = 0XFF
                self.arr[z * 8 + x - 1] = 0X00
            self.run()

    def r2l_scan(self):
        self.clear()
        for z in range(8):
            self.arr[z * 8 + 7] = 0XFF
        self.run()
        for x in range(6, -1, -1):
            for z in range(8):
                self.arr[z * 8 + x] = 0XFF
                self.arr[z * 8 + x + 1] = 0X00
            self.run()

    def f2b_scan(self):
        self.clear()
        for i in range(64):
            self.arr[i] = 0X01
        self.run()
        for y in range(7):
            for i in range(64):
                self.arr[i] <<= 1
            self.run()

    def b2f_scan(self):
        self.clear()
        for i in range(64):
            self.arr[i] = 0X80
        self.run()
        for y in range(7):
            for i in range(0, 64):
                self.arr[i] >>= 1
            self.run()

    def u2d_scan(self):
        self.clear()
        for x in range(8):
            self.arr[x] = 0XFF
        self.run()
        for z in range(1, 8):
            for x in range(8):
                self.arr[z * 8 + x] = 0XFF
                self.arr[(z - 1) * 8 + x] = 0X00
            self.run()

    def d2u_scan(self):
        self.clear()
        for x in range(8):
            self.arr[7 * 8 + x] = 0XFF
        self.run()
        for z in range(6, -1, -1):
            for x in range(8):
                self.arr[z * 8 + x] = 0XFF
                self.arr[(z + 1) * 8 + x] = 0X00
            self.run()

    def xcw(self, nums=10):
        self.clear()
        for i in range(8):
            self.arr[7 * 8 + i] = 0XFF
        self.run()
        for num in range(nums - 1, -1, -1):
            for i in range(28):
                if i < 7:
                    for k in range(8):
                        self.arr[(6 - i) * 8 + k] |= 0X01
                        self.arr[7 * 8 + k] >>= 0X01
                elif i < 14:
                    for k in range(8):
                        self.arr[k] |= 0X01 << (i - 6)
                        self.arr[(14 - i) * 8 + k] = 0X00
                elif i < 21:
                    for k in range(8):
                        self.arr[(i - 13) * 8 + k] = 0X80
                        self.arr[k] <<= 0X01
                elif i < 28:
                    for k in range(8):
                        self.arr[7 * 8 + k] |= 0X80 >> (i - 20)
                        self.arr[(i - 21) * 8 + k] = 0X00
                self.run()

    def xacw(self, nums=10):
        self.clear()
        for i in range(0, 8):
            self.arr[7 * 8 + i] = 0XFF
        self.run()
        for num in range(nums - 1, -1, -1):
            for i in range(28):
                if i < 7:
                    for k in range(0, 8):
                        self.arr[(6 - i) * 8 + k] |= 0X80
                        self.arr[7 * 8 + k] <<= 0X01
                elif i < 14:
                    for k in range(8):
                        self.arr[k] |= 0X80 >> (i - 6)
                        self.arr[(14 - i) * 8 + k] = 0X00
                elif i < 21:
                    for k in range(8):
                        self.arr[(i - 13) * 8 + k] = 0X01
                        self.arr[k] >>= 0X01
                elif i < 28:
                    for k in range(8):
                        self.arr[7 * 8 + k] |= 0X01 << (i - 20)
                        self.arr[(i - 21) * 8 + k] = 0X00
                self.run()

    def ycw(self, nums=10):
        self.clear()
        for i in range(0, 8):
            self.arr[i * 8] = 0XFF
        self.run()
        for num in range(nums - 1, -1, -1):
            for i in range(0, 28):
                if i < 7:
                    for k in range(8):
                        self.arr[(7 - i) * 8] = 0X00
                        self.arr[i + 1] = 0XFF
                elif i < 14:
                    for k in range(8):
                        self.arr[i - 7] = 0X00
                        self.arr[(i - 6) * 8 + 7] = 0XFF
                elif i < 21:
                    for k in range(8):
                        self.arr[(i - 14) * 8 + 7] = 0X00
                        self.arr[7 * 8 + (20 - i)] = 0XFF
                elif i < 28:
                    for k in range(8):
                        self.arr[7 * 8 + (28 - i)] = 0X00
                        self.arr[(27 - i) * 8] = 0XFF
                self.run()

    def yacw(self, nums=10):
        self.clear()
        for i in range(8):
            self.arr[i * 8] = 0XFF
        self.run()
        for num in range(nums - 1, -1, -1):
            for i in range(28):
                if i < 7:
                    for k in range(8):
                        self.arr[i * 8] = 0X00
                        self.arr[7 * 8 + (i + 1)] = 0XFF
                elif i < 14:
                    for k in range(8):
                        self.arr[7 * 8 + (i - 7)] = 0X00
                        self.arr[(13 - i) * 8 + 7] = 0XFF
                elif i < 21:
                    for k in range(8):
                        self.arr[(21 - i) * 8 + 7] = 0X00
                        self.arr[20 - i] = 0XFF
                elif i < 28:
                    for k in range(8):
                        self.arr[28 - i] = 0X00
                        self.arr[(i - 20) * 8] = 0XFF
                self.run()

    def zcw(self, nums=10):
        self.clear()
        for i in range(0, 64):
            self.arr[i] = 0X80
        self.run()
        for num in range(nums - 1, -1, -1):
            for i in range(28):
                if i < 7:
                    for k in range(8):
                        self.arr[k * 8 + 7] |= (0X80 >> (i + 1))
                        self.arr[k * 8 + i] = 0X00
                elif i < 14:
                    for k in range(8):
                        self.arr[k * 8 + 13 - i] = 0X01
                        self.arr[k * 8 + 7] >>= 0X01
                elif i < 21:
                    for k in range(8):
                        self.arr[k * 8 + 21 - i] = 0X00
                        self.arr[k * 8] |= (0x01 << (i - 13))
                elif i < 28:
                    for k in range(8):
                        self.arr[k * 8 + i - 20] = 0X80
                        self.arr[k * 8] <<= 0X01
                self.run()

    def zacw(self, nums=10):
        self.clear()
        for i in range(64):
            self.arr[i] = 0x80
        self.run()
        for num in range(nums - 1, -1, -1):
            for i in range(28):
                if i < 7:
                    for k in range(8):
                        self.arr[k * 8] |= (0X80 >> (i + 1))
                        self.arr[k * 8 + 7 - i] = 0X00
                elif i < 14:
                    for k in range(8):
                        self.arr[k * 8 + i - 6] = 0X01
                        self.arr[k * 8] >>= 0X01
                elif i < 21:
                    for k in range(8):
                        self.arr[k * 8 + i - 14] = 0X00
                        self.arr[k * 8 + 7] |= (0x01 << (i - 13))
                elif i < 28:
                    for k in range(8):
                        self.arr[k * 8 + 27 - i] = 0X80
                        self.arr[k * 8 + 7] <<= 0X01
                self.run()

    def move(self, kind, direction, length):
        if kind == 0:
            if direction == 1:
                for z in range(8):
                    for x in range(7, length - 1, -1):
                        self.arr[z * 8 + x] = self.arr[z * 8 + (x - length)]
                    for x in range(0, length):
                        self.arr[z * 8 + x] = 0
            else:
                for z in range(8):
                    for x in range(length, 8):
                        self.arr[z * 8 + (x - length)] = self.arr[z * 8 + x]
                    for x in range(8 - length, 8):
                        self.arr[z * 8 + x] = 0
        elif kind == 1:
            if direction == 1:
                for i in range(64):
                    self.arr[i] <<= length
            else:
                for i in range(64):
                    self.arr[i] >>= length
        else:
            if direction == 1:
                for x in range(8):
                    for z in range(7, length - 1, -1):
                        self.arr[z * 8 + x] = self.arr[(z - length) * 8 + x]
                    for z in range(0, length):
                        self.arr[z * 8 + x] = 0
            else:
                for x in range(8):
                    for z in range(length, 8):
                        self.arr[(z - length) * 8 + x] = self.arr[z * 8 + x]
                    for z in range(8 - length, 8):
                        self.arr[z * 8 + x] = 0

    def cube_0(self, n):
        self.clear()
        j = 0XFF >> (8 - n)
        self.arr[0] = j
        self.arr[n - 1] = j
        self.arr[(n - 1) * 8] = j
        self.arr[(n - 1) * 8 + n - 1] = j
        for i in range(n):
            j = 0X01 | (0x01 << (n - 1))
            self.arr[i * 8] |= j
            self.arr[i * 8 + n - 1] |= j
            self.arr[i] |= j
            self.arr[(n - 1) * 8 + i] |= j

    def cube_1(self, n):
        for z in range(8):
            for x in range(8):
                if z < n and x < n:
                    self.arr[z * 8 + x] = 0XFF >> (8 - n)
                else:
                    self.arr[z * 8 + x] = 0X00

    def cube(self, empty, kind):
        self.clear()
        for i in range(1, 9):
            if empty == 0:
                self.cube_0(i)
            else:
                self.cube_1(i)
            if kind == 0:
                pass
            elif kind == 1:
                self.move(0, 1, 8 - i)
            elif kind == 2:
                self.move(2, 1, 8 - i)
            else:
                self.move(0, 1, 8 - i)
                self.move(2, 1, 8 - i)
            self.run()
        for i in range(7, -1, -1):
            if empty == 0:
                self.cube_0(i)
            else:
                self.cube_1(i)
            if kind == 0:
                self.move(0, 1, 8 - i)
            elif kind == 1:
                self.move(0, 1, 8 - i)
                self.move(2, 1, 8 - i)
            elif kind == 2:
                pass
            else:
                self.move(2, 1, 8 - i)
            self.run()

    def rain(self, menu, nums=10):
        self.clear()
        if (menu == 1):
            for x in range(0, 8):
                self.arr[56 + x] = TAB_RAIN[x]
            self.run()
            for z in range(1, 8):
                self.move(2, 0, 1)
                for x in range(0, 8):
                    self.arr[56 + x] = TAB_RAIN[z * 8 + x]
                self.run()
            for num in range(nums - 1, -1, -1):
                for z in range(0, 8):
                    self.move(2, 0, 1)
                    for x in range(0, 8):
                        self.arr[56 + x] = TAB_RAIN[z * 8 + x]
                    self.run()
        else:
            for x in range(0, 8):
                self.arr[x] = TAB_RAIN[x]
            self.run()
            for z in range(1, 8):
                self.move(2, 1, 1)
                for x in range(0, 8):
                    self.arr[x] = TAB_RAIN[z * 8 + x]
                self.run()
            for num in range(nums - 1, -1, -1):
                for z in range(0, 8):
                    self.move(2, 1, 1)
                    for x in range(0, 8):
                        self.arr[x] = TAB_RAIN[z * 8 + x]
                    self.run()

    def up(self, nums=10):
        self.clear()
        for num in range(nums - 1, -1, -1):
            for x in range(0, 8):
                self.arr[56 + x] = 0XFF
            self.run()
            for z in range(1, 8):
                self.move(2, 0, 1)
                for x in range(0, 8):
                    self.arr[56 + x] = 0XFF
                self.run()
            for z in range(0, 8):
                if num == 0 & z == 7:
                    continue
                self.move(2, 0, 1)
                self.run()
        for z in range(0, 7):
            self.move(2, 1, 1)
            self.run()

    def spinner(self, kind, cw, nums=10):
        self.clear()
        for num in range(nums - 1, -1, -1):
            if cw == 1:
                for i in range(13, -1, -1):
                    for z in range(8):
                        for x in range(8):
                            if x > 1 and x < 6 and z > 1 and z < 6 and kind != 1:
                                self.arr[z * 8 + x] = \
                                    TAB_SPINNER_0[i * 8 + x] & 0XC3
                            else:
                                self.arr[z * 8 + x] = \
                                    TAB_SPINNER_0[i * 8 + x]
                    self.run()
            else:
                for i in range(14):
                    for z in range(8):
                        for x in range(8):
                            if x > 1 and x < 6 and z > 1 and z < 6 and kind != 1:
                                self.arr[z * 8 + x] = \
                                    TAB_SPINNER_0[i * 8 + x] & 0XC3
                            else:
                                self.arr[z * 8 + x] = \
                                    TAB_SPINNER_0[i * 8 + x]
                    self.run()

    def curved_spinner(self, cw, nums=10):
        self.clear()
        for z in range(8):
            for x in range(8):
                self.arr[z * 8 + x] = TAB_SPINNER_0[x]
        self.run()
        for num in range(nums - 1, -1, -1):
            if cw == 1:
                for i in range(13, -1, -1):
                    self.move(2, 1, 1)
                    for x in range(8):
                        self.arr[x] = TAB_SPINNER_0[i * 8 + x]
                    self.run()
            else:
                for i in range(13):
                    self.move(2, 1, 1)
                    for x in range(8):
                        self.arr[x] = TAB_SPINNER_0[i * 8 + x]
                    self.run()
        for i in range(7):
            self.move(2, 1, 1)
            for x in range(8):
                self.arr[x] = TAB_SPINNER_0[x]
            self.run()

    def sandglass(self):
        self.clear()
        for i in range(128):
            self.arr[TAB_0_0[i]] = 0X01 << TAB_0_1[i]
            self.run()
            self.arr[TAB_0_0[i]] = 0
        for i in range(128):
            self.arr[TAB_1_0[i]] |= 0X01 << TAB_0_1[i]
            if i >= 8:
                self.arr[TAB_1_0[i - 8]] ^= 0X01 << TAB_0_1[i - 8]
        self.arr[7] |= 0X01
        self.arr[0] = 0X01
        self.run()
        for i in range(128):
            if i < 8:
                self.arr[8 - i] = 0X00
            self.arr[TAB_0_0[i]] |= 0X01 << TAB_0_1[i]
            self.run()
        self.run()
        for i in range(128):
            self.arr[TAB_1_0[i]] ^= 0X01 << TAB_0_1[i]
Beispiel #5
0
class TT:
    def __init__(self):
        ol = Overlay("SCS_TT_TEST_wrapper.bit", 0)
        ol.download()
        self.UTIL = MMIO(0x41200000, 0x10000)
        self.UTIL.write(0x8, int(REF_CLK))
        self.DATA0 = MMIO(0x41210000, 0x10000)
        self.DATA1 = MMIO(0x41220000, 0x10000)
        self.DATA_UTIL = MMIO(0x41230000, 0x10000)
        self.DEBUG0 = MMIO(0x41240000, 0x10000)
        self.DEBUG1 = MMIO(0x41250000, 0x10000)

    def uencode(self, val, length):
        cnt = 0
        for i in range(length):
            if ((val >> i) & 0b1 == 1):
                cnt += 1
        return cnt

    def set_timeout(self, seconds):
        self.UTIL.write(0x8, int(REF_CLK * seconds))

    def start(self):
        self.UTIL.write(0x0, 0x1)

    def stop(self):
        self.UTIL.write(0x0, 0x0)

    def wait_for_rdy(self):
        if ((self.read_drdy()) == 1):
            while ((self.read_drdy()) == 1):
                pass
        else:
            while (self.read_drdy() == 0):
                pass

    def read_debug(self):
        deb0 = self.DEBUG0.read(0x0)
        deb1 = self.DEBUG0.read(0x8)
        deb2 = self.DEBUG1.read(0x0)
        rawdel0 = deb2
        rawdel1 = (deb0 & 0xFFFF)
        rawdel2 = (deb0 & 0xFFFF0000) >> 16
        rawdel3 = (deb1 & 0xFFFF)
        rawdel4 = (deb1 & 0xFFFF0000) >> 16
        log.debug("T0D: " + bin(rawdel0))
        log.debug("T1D: " + bin(rawdel1))
        log.debug("T2D: " + bin(rawdel2))
        log.debug("T3D: " + bin(rawdel3))
        log.debug("T4D: " + bin(rawdel4))

    def read_drdy(self):
        return (self.DATA_UTIL.read(0x8) & 0B0000100000000) >> 8

    def read_times(self):
        rawtime0 = self.DATA0.read(0x0)
        rawtime1 = self.DATA0.read(0x8)
        rawtime2 = self.DATA1.read(0x0)
        rawtime3 = self.DATA1.read(0x8)
        log.debug("T0: " + str(rawtime0))
        log.debug("T1: " + str(rawtime1))
        log.debug("T2: " + str(rawtime2))
        log.debug("T3: " + str(rawtime3))
        self.read_debug()
        ctime0 = rawtime0 / REF_CLK
        ctime1 = rawtime1 / REF_CLK
        ctime2 = rawtime2 / REF_CLK
        ctime3 = rawtime3 / REF_CLK
        #print("CTIME0: "+str(ctime0))
        #print("CTIME1: " + str(ctime1))
        #print("CTIME2: " + str(ctime2))
        #print("CTIME3: " + str(ctime3))
        del0 = self.DATA_UTIL.read(0x0)
        del1 = self.DATA_UTIL.read(0x8) & 0B11111111
        #print("DELAYS: "+bin(del0))
        rawdel0 = (del1 & 0xFF)
        rawdel1 = (del0 & 0xFF)
        rawdel2 = ((del0 & 0xFF00) >> 8)
        rawdel3 = ((del0 & 0xFF0000) >> 16)
        rawdel4 = ((del0 & 0xFF000000) >> 24)
        log.debug("RT: " + str(rawdel0))
        log.debug("R1: " + str(rawdel1))
        log.debug("R2: " + str(rawdel2))
        log.debug("R3: " + str(rawdel3))
        log.debug("R4: " + str(rawdel4))
        t0del = rawdel0 * FTIME
        t2del = rawdel2 * FTIME
        t3del = rawdel3 * FTIME
        t4del = rawdel4 * FTIME
        t1del = rawdel1 * FTIME
        ctime0 = ctime0 + t0del - t1del
        ctime1 = ctime1 + t0del - t2del
        ctime2 = ctime2 + t0del - t3del
        ctime3 = ctime3 + t0del - t4del
        return [ctime0, ctime1, ctime2, ctime3]

    def read_timeouts(self):
        return (self.DATA_UTIL.read(0x8) & 0B1111000000000) >> 9

    def proc(self):
        self.wait_for_rdy()
        times = self.read_times()
        timeouts = self.read_timeouts()
        print("T1 (ns): " + str(times[0] * 1e9))
        print("T2 (ns): " + str(times[1] * 1e9))
        print("T3 (ns): " + str(times[2] * 1e9))
        print("T4 (ns): " + str(times[3] * 1e9))
        print("TIMEOUTS: " + bin(timeouts))
        return times
Beispiel #6
0
class SP_TOOLS:
    def __init__(self):
        self.OV = Overlay("Single_Photons/SP_OVERLAY.bit", 0)
        self.OV.download()
        ##Initialize pulse counter
        axi_offset = 0
        #Initialize data channels
        self.PC_DAT = []
        global axi_range
        for i in range(4):
            self.PC_DAT.append(MMIO(axi_base_addr + (i * axi_range),
                                    axi_range))
            self.PC_DAT[i].write(ch1_dir, agpi)  #ch1 is counts
            self.PC_DAT[i].write(ch2_dir, agpo)  #Ch2 is window
            self.PC_DAT[i].write(ch2_data, 0xFFFFFFFF)
        #Initialize utility channels
        axi_offset = 4
        self.PC_UTIL = []
        for i in range(4):
            self.PC_UTIL.append(
                MMIO(axi_base_addr + ((i + axi_offset) * axi_range),
                     axi_range))
            self.PC_UTIL[i].write(ch1_dir, agpo)  #Reset
            self.PC_UTIL[i].write(ch1_data, 0x0)  #Hold in reset
            self.PC_UTIL[i].write(ch2_dir, agpi)  #Ready
        #Initialize trigger controller
        self.T_UTIL = MMIO(0x41200000, 0x10000)
        self.T_UTIL.write(ch2_dir, 0x0)
        self.T_UTIL.write(ch2_data, 0x0)
        self.T_RDY_UTIL = MMIO(0x41210000, 0x10000)
        self.T_RDY_UTIL.write(ch1_dir, 0x1)
        ##Initialize single channel inter-rising_edge detection
        axi_offset = 8
        self.ST_DAT = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
        self.ST_DAT.write(ch1_dir, agpi)
        self.ST_DAT.write(ch2_dir, agpo)
        self.ST_DAT.write(ch2_data, 0x0)  #Hold in reset
        self.ST_RDY = MMIO(axi_base_addr + (axi_offset + 1) * axi_range,
                           axi_range)
        self.ST_RDY.write(ch1_dir, agpi)
        ##Initialize interchannel coincidence timer
        axi_offset = 10
        self.CT_DAT = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
        self.CT_DAT.write(ch1_dir, agpi)
        self.CT_DAT.write(ch2_dir, agpo)
        self.CT_DAT.write(ch2_data, 0x0)  #Hold in reset
        self.CT_RDY = MMIO(axi_base_addr + (axi_offset + 1) * axi_range,
                           axi_range)
        self.CT_RDY.write(ch1_dir, agpi)
        ##Initialize Pulse generator
        axi_offset = 12
        iDC = 0.5
        iFREQ = 440.0
        ph0, ph1 = self.encode_phase_inc(iFREQ)
        iDCenc = self.calc_dc_lim(iFREQ, iDC)
        self.PG_PH = []
        self.PG_AUX = []
        self.chfreqs = [440.0, 440.0, 440.0, 440.0]
        self.chdcs = [0.5, 0.5, 0.5, 0.5]
        self.chdelays = [0, 0, 0, 0]
        for i in range(4):  #Phase increments
            tap = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tap.write(ch1_dir, agpo)
            tap.write(ch2_dir, agpo)
            tap.write(ch1_data, ph0)
            tap.write(ch2_data, ph1)
            self.PG_PH.append(tap)
            axi_offset += 1
            self.chfreqs[i] = 440.0
        for i in range(4):  #Duty length and delay
            tdc = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tdc.write(ch1_dir, agpo)
            tdc.write(ch1_data, iDCenc)
            tdc.write(ch2_dir, agpo)
            tdc.write(ch2_data, 0x0)
            self.PG_AUX.append(tdc)
            axi_offset += 1
            self.chdcs[i] = 0.5
        self.PG_UTIL = MMIO(0x43D40000,
                            0x10000)  #increment load and master reset
        self.PG_UTIL.write(ch1_dir, agpo)
        self.PG_UTIL.write(ch2_dir, agpo)
        self.PG_UTIL.write(ch1_data, 0x0)  #SEt loader to 0
        self.PG_UTIL.write(ch2_data, 0x0)  #Hold in reset
        #Routine to write initial phase increments
        self.PG_UTIL.write(ch2_data, 0x1)
        self.PG_UTIL.write(ch1_data, 0xF)
        sleep(slt)
        self.PG_UTIL.write(ch1_data, 0x0)
        #Channel enable controller
        self.T_UTIL.write(ch1_dir, 0x0)
        self.T_UTIL.write(ch1_data, 0xF)  #SEt all channels to high impedance
        axi_offset += 1
        self.pg_ch_stat = 0xF
        #self.PG_UTIL.write(ch2_data,0x0)
        ##Initialize Time Tagger
        #initialize detector MMIOs
        self.TT_DET = []
        for i in range(4):
            temp = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            temp.write(ch1_dir, 0xFFFFFFFF)
            temp.write(ch2_dir, 0xFFFFFFFF)
            self.TT_DET.append(temp)
            axi_offset += 1
        #Initialize timeout MMIO
        self.TT_TIME_OUT = MMIO(axi_base_addr + (axi_offset * axi_range),
                                axi_range)
        self.TT_TIME_OUT.write(ch1_dir, 0x0)
        self.TT_TIME_OUT.write(ch2_dir, 0x0)
        self.TT_TIME_OUT.write(ch1_data, 0xFFFFFFFF)
        self.TT_TIME_OUT.write(ch2_data, 0xFFFF)
        axi_offset += 1
        #Initialize utility
        print(hex(axi_base_addr + (axi_offset * axi_range)))
        print(hex(axi_range))
        self.TT_UTIL = MMIO(axi_base_addr + (axi_offset * axi_range),
                            axi_range)
        self.TT_UTIL.write(ch1_dir, 0x0)
        self.TT_UTIL.write(ch2_dir, 0xFFFFFFFF)
        self.TT_UTIL.write(ch1_data, 0x0)  #Hold system in reset
        axi_offset += 1
        ##Initialize IDELAY
        self.iDD_DATA = []
        self.iDD_UTIL = []
        for i in range(6):
            tempdel = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tempdel.write(ch1_data, 0x0)
            tempdel.write(ch2_data, 0x0)
            self.iDD_DATA.append(tempdel)
            axi_offset += 1
        for i in range(6):
            temputil = MMIO(axi_base_addr + (axi_offset * axi_range),
                            axi_range)
            temputil.write(ch1_data, 0x1)
            temputil.write(ch2_data, 0x1)
            self.iDD_UTIL.append((temputil))
            axi_offset += 1

    ####------------------PHOTON COUNTER---------------------------------------------------####
    def pc_set_window(
            self, window,
            channels):  #Channels is 4 bit integer, window is in seconds
        m = 0B0001
        wval = int(window * TIMER_CLK)
        if (wval > 0xFFFFFFFF or wval <= 0):
            print(
                "Window must be between 34.35973836s and 0, cannot be 0 seconds"
            )
            return
        for i in range(4):
            if ((0B0001 << i) & channels) != 0:
                self.PC_DAT[i].write(ch2_data, wval)

    def pc_wait_for_rdy(self, channel, mode):
        if mode == 0:
            if (self.PC_UTIL[channel].read(ch2_data) == 0):
                while (self.PC_UTIL[channel].read(ch2_data) == 0):
                    pass
            else:
                while (self.PC_UTIL[channel].read(ch2_data) == 1):
                    pass
        else:
            if (self.T_RDY_UTIL.read(ch1_data) == 0):
                while (self.T_RDY_UTIL.read(ch1_data) == 0):
                    pass

    def pc_ex_triggered(self, window):
        self.pc_set_window(window, 0xF)
        self.T_UTIL.write(ch2_data, 0x1)
        self.pc_wait_for_rdy(0, 0)
        retval = []
        for i in range(4):
            retval.append(self.pc_read_counts(i))
        self.T_UTIL.write(ch2_data, 0x0)
        return retval

    def pc_ex_trig_stop(self):
        self.T_UTIL.write(ch2_data, 0x3)
        for i in range(4):
            self.PC_DAT[i].write(ch2_data, 0xFFFFFFFF)
        self.pc_wait_for_rdy(0, 1)
        retval = []
        for i in range(4):
            retval.append(self.pc_read_counts(i))
        self.T_UTIL.write(ch2_data, 0x0)
        return retval

    def pc_enable_channels(self, channels):  #channels a 4 bit integer
        for i in range(4):
            if ((0B0001 << i) & channels) != 0:
                self.PC_UTIL[i].write(ch1_data, 0x1)

    def pc_disable_channels(self, channels):  #Channels a 4 bit integer
        for i in range(4):
            if ((0B0001 << i) & channels) != 0:
                self.PC_UTIL[i].write(ch1_data, 0x0)

    def pc_read_counts(self, channel):
        return self.PC_DAT[channel].read(ch1_data)

    ####----------------------------------------------------------------------------------####
    ####------------------Single line inter-rising_edge timer-----------------------------####
    def st_arm_and_wait(self):
        self.ST_DAT.write(ch2_data, 0x1)  #Enable
        op = 0
        while (self.ST_RDY.read(ch1_data) == 0x0):  #Wait for ready
            pass
        if (self.ST_RDY.read(ch1_data) == 0x1):
            op = self.ST_DAT.read(ch1_data)  #Read time
            self.ST_DAT.write(ch2_data, 0x0)
        return op * (1 / REF_CLK)

    ####----------------------------------------------------------------------------------####
    ####------------------Two channel photon coincidence timer----------------------------####
    def ct_arm_and_wait(self):
        self.CT_DAT.write(ch2_data, 0x1)  # Enable
        op = 0
        #print("Armed")
        while (self.CT_RDY.read(ch1_data) == 0x0):  # Wait for ready
            pass
        #print("Triggered")
        if (self.CT_RDY.read(ch1_data) == 0x1):
            #print("Reading")
            op = self.CT_DAT.read(ch1_data)  # Read time
            self.CT_DAT.write(ch2_data, 0x0)
        return op * (1 / REF_CLK)

    ####---------------------Signal generator---------------------------------------------####

    def pg_disable(self):
        self.PG_UTIL.write(ch2_data, 0x0)

    def pg_enable(self):
        self.PG_UTIL.write(ch2_data, 0x1)

    def pg_enable_channel(self, channel):
        self.pg_ch_stat = ~(~self.pg_ch_stat | (0B0001 << channel))
        self.T_UTIL.write(ch1_data, self.pg_ch_stat)

    def pg_disable_channel(self, channel):
        self.pg_ch_stat = self.pg_ch_stat | (0b0001 << channel)
        self.T_UTIL.write(ch1_data, self.pg_ch_stat)

    def pg_set_channel_freq(self, channel, freq):
        nenc = self.encode_phase_inc(2 * freq)
        self.PG_PH[channel].write(ch1_data, nenc[0])
        self.PG_PH[channel].write(ch2_data, nenc[1])
        self.PG_UTIL.write(ch1_data, 0xF)
        sleep(slt)
        self.PG_UTIL.write(ch1_data, 0x0)
        newdc = self.calc_dc_lim(freq, self.chdcs[channel])
        self.PG_UTIL.write(ch2_data, 0x0)
        self.PG_AUX[channel].write(ch1_data, newdc)
        self.PG_AUX[channel].write(ch2_data,
                                   self.calc_delay(self.chdelays[channel]))
        self.PG_UTIL.write(ch2_data, 0x1)
        self.chfreqs[channel] = freq

    def pg_set_dc(self, channel, dc):  #Dc from 0 to 1
        dcenc = self.calc_dc_lim(self.chfreqs[channel], dc)
        self.PG_UTIL.write(ch2_data, 0x0)
        self.PG_AUX[channel].write(ch1_data, dcenc)
        self.PG_UTIL.write(ch2_data, 0x1)
        self.chdcs[channel] = dc

    def pg_set_pw(self, channel, pw):
        pwv = self.calc_delay(pw / 1000)
        self.PG_UTIL.write(ch2_data, 0x0)
        self.PG_AUX[channel].write(ch1_data, pwv)
        self.PG_UTIL.write(ch2_data, 0x1)
        tlim = REF_CLK / self.chfreqs[channel]
        self.chdcs[channel] = pwv / tlim

    def pg_set_delay(self, channel, delay):  #Delay in seconds
        delv = self.calc_delay(delay)
        self.PG_UTIL.write(ch2_data, 0x0)
        self.PG_AUX[channel].write(ch2_data, delv)
        self.chdelays[channel] = delay
        self.PG_UTIL.write(ch2_data, 0x1)

    def encode_phase_inc(self, freq):
        enc = int((freq * 2**PHASE_BIT_DEPTH) / REF_CLK)
        lsb = enc & 0xFFFFFFFF
        msb = (enc >> 32) & 0xFFFF
        return [lsb, msb]

    def calc_dc_lim(self, freq, dc):  #dc from 0 to 1
        dc_t = int(REF_CLK / freq)
        return int(dc_t * dc)

    def calc_delay(self, delay):
        return int(delay * REF_CLK)

    def TT_concat48(self, lsb, msb):
        retval = (lsb & 0xFFFFFFFF) | ((msb & 0xFFFF) << 32)
        return retval

    def TT_slice48(self, xsl):
        lsb = xsl & 0xFFFFFFFF
        msb = (xsl >> 32) & 0xFFFF
        return [lsb, msb]

    def TT_set_timeout(self, time):
        tval = time * REF_CLK
        lsb, msb = self.TT_slice48(int(tval))
        self.TT_TIME_OUT.write(ch1_data, lsb)
        self.TT_TIME_OUT.write(ch2_data, msb)

    def TT_reset(self):
        self.TT_UTIL.write(ch1_data, 0b0)

    def TT_activate(self, timeout):
        self.TT_set_timeout(timeout)
        self.TT_UTIL.write(ch1_data, 0b1)

    def TT_read_times(self):
        retvals = []
        for i in range(4):
            lsb = self.TT_DET[i].read(ch1_data)
            msb = self.TT_DET[i].read(ch2_data)
            retvals.append(self.TT_concat48(lsb, msb))
        return retvals

    def TT_read_states(self):
        return self.TT_UTIL.read(ch2_data) & 0xF

    def TT_read_rdy(self):
        return (self.TT_UTIL.read(ch2_data) >> 4) & 0x1

    def TT_proc(self):
        print("Waiting for data")
        if (self.TT_read_rdy() == 0):
            print("1")
            while (self.TT_read_rdy() == 0):
                pass
        else:
            print("0")
            while (self.TT_read_rdy() == 1):
                pass
        vals = self.TT_read_times()
        states = self.TT_read_states()
        return {
            'T1': vals[0] * (1 / REF_CLK),
            'T2': vals[1] * (1 / REF_CLK),
            'T3': vals[2] * (1 / REF_CLK),
            'T4': vals[3] * (1 / REF_CLK),
            'T1s': (states & 1),
            'T2s': ((states >> 1) & 0b1),
            'T3s': ((states >> 2) & 0b1),
            'T4s': ((states >> 3) & 0b1)
        }

    def DD_idelay(self, channel, tap, stage):
        print("Setting input delay on channel " + str(channel) +
              " dline tap of " + str(tap) + " with " + str(stage) +
              " stage(s).")
        self.iDD_UTIL[channel].write(ch1_data, 0x0)
        sleep(slt)
        self.iDD_UTIL[channel].write(ch1_data, 0x1)
        self.iDD_DATA[channel].write(ch1_data, tap)
        self.iDD_DATA[channel].write(ch2_data, stage)
Beispiel #7
0
    def __init__(self,
                 bitfile_name=None,
                 init_rf_clks=True,
                 voila=False,
                 **kwargs):
        """Construct a new SpectrumAnalyser
        bitfile_name: Optional. If left None, the 'rfsoc_sam.bit' bundled with this
                      rfsoc-sam package will be used.
        init_rf_clks: If true (default), the reference clocks are configured
                      for all tiles. If the clocks are already configured, set
                      to false for faster execution.
        """

        # Generate default bitfile name
        if bitfile_name is None:
            this_dir = os.path.dirname(__file__)
            bitfile_name = os.path.join(this_dir, 'bitstream', 'rfsoc_sam.bit')

        if voila:
            dark_theme = True
        else:
            dark_theme = False

        if dark_theme:
            from IPython.display import display, HTML
            import plotly.io as pio

            # Apply plotly theming
            dark_template = pio.templates['plotly_dark']
            dark_template.layout.paper_bgcolor = 'rgb(0,0,0,0)'
            dark_template.layout.plot_bgcolor = 'rgb(0,0,0,0)'
            dark_template.layout.legend.bgcolor = 'rgb(0,0,0,0)'
            pio.templates['dark_plot'] = dark_template
            pio.templates.default = 'dark_plot'

        # Set FPD and LPD interface widths
        from pynq import MMIO
        fpd_cfg = MMIO(0xfd615000, 4)
        fpd_cfg.write(0, 0x00000A00)
        lpd_cfg = MMIO(0xff419000, 4)
        lpd_cfg.write(0, 0x00000000)

        # Create Overlay
        super().__init__(bitfile_name, **kwargs)

        # Extact in-use dataconverter objects with friendly names
        self.rf = self.usp_rf_data_converter_0

        # Start up LMX clock
        if init_rf_clks:
            xrfclk.set_all_ref_clks(409.6)

        # Set sane DAC defaults
        # DAC4
        self.dac_tile = self.rf.dac_tiles[1]
        self.dac_block = self.dac_tile.blocks[0]

        self.dac_tile.DynamicPLLConfig(1, 409.6, 2048)
        self.dac_block.NyquistZone = 1
        self.dac_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_IMMEDIATE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 0,
            'MixerMode': xrfdc.MIXER_MODE_C2R,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.dac_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.dac_tile.SetupFIFO(True)

        # DAC5
        self.dac_tile = self.rf.dac_tiles[1]
        self.dac_block = self.dac_tile.blocks[1]

        self.dac_tile.DynamicPLLConfig(1, 409.6, 2048)
        #self.dac_block.NyquistZone = 1
        self.dac_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_IMMEDIATE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 0,
            'MixerMode': xrfdc.MIXER_MODE_C2R,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.dac_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.dac_tile.SetupFIFO(True)

        # DAC6
        self.dac_tile = self.rf.dac_tiles[1]
        self.dac_block = self.dac_tile.blocks[2]

        self.dac_tile.DynamicPLLConfig(1, 409.6, 2048)
        #self.dac_block.NyquistZone = 1
        self.dac_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_IMMEDIATE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 0,
            'MixerMode': xrfdc.MIXER_MODE_C2R,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.dac_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.dac_tile.SetupFIFO(True)

        # DAC7
        self.dac_tile = self.rf.dac_tiles[1]
        self.dac_block = self.dac_tile.blocks[3]

        self.dac_tile.DynamicPLLConfig(1, 409.6, 2048)
        #self.dac_block.NyquistZone = 1
        self.dac_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_IMMEDIATE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 80,
            'MixerMode': xrfdc.MIXER_MODE_C2R,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.dac_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.dac_tile.SetupFIFO(True)

        # Set sane ADC defaults
        # ADC2
        self.adc_tile = self.rf.adc_tiles[1]
        self.adc_block = self.adc_tile.blocks[0]

        self.adc_tile.DynamicPLLConfig(1, 409.6, 2048)
        self.adc_block.NyquistZone = 1
        self.adc_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_TILE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 64,
            'MixerMode': xrfdc.MIXER_MODE_R2C,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.adc_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.adc_tile.SetupFIFO(True)

        # ADC1
        self.adc_tile = self.rf.adc_tiles[0]
        self.adc_block = self.adc_tile.blocks[1]

        self.adc_tile.DynamicPLLConfig(1, 409.6, 2048)
        self.adc_block.NyquistZone = 1
        self.adc_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_TILE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 64,
            'MixerMode': xrfdc.MIXER_MODE_R2C,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.adc_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.adc_tile.SetupFIFO(True)

        # ADC0
        self.adc_tile = self.rf.adc_tiles[0]
        self.adc_block = self.adc_tile.blocks[0]

        self.adc_tile.DynamicPLLConfig(1, 409.6, 2048)
        self.adc_block.NyquistZone = 1
        self.adc_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_TILE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 64,
            'MixerMode': xrfdc.MIXER_MODE_R2C,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.adc_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.adc_tile.SetupFIFO(True)

        self.timers = TimerRegistry()

        # Demo initialisation
        #self.TransmitterTop = self.Transmitter
        self.BandwidthSelector = self.SpectrumAnalyser.BandwidthSelector
        self.SpectrumWindow = self.SpectrumAnalyser.SpectrumWindow
        self.SpectrumFFT = self.SpectrumAnalyser.SpectrumFFT
        self.DataInspector = self.SpectrumAnalyser.DataInspector

        self._fs = 128e6
        self._axi_fs = 256e6
        self._fc = 64

        self.voila = voila
        self.dark_theme = dark_theme
        self.peak_flag = False

        # Hot-fix
        self.SpectrumAnalyser.SpectrumFFT.PSD.output_selection = 0
        self.SpectrumAnalyser.SpectrumFFT.PSD.write(
            0x104,
            int(
                struct.unpack('!i',
                              struct.pack('!f',
                                          float(1 / (128e6 * 2048))))[0]))
        self.SpectrumAnalyser.SpectrumFFT.PSD.write(
            0x108,
            int(
                struct.unpack('!i', struct.pack('!f',
                                                float(128e6 / 2048)))[0]))

        self.frequency_synth.constant_enable = 15

        self.frequency_synth.enable_nco_0 = 1
        self.frequency_synth.enable_nco_1 = 1
        self.frequency_synth.enable_nco_2 = 1
        self.frequency_synth.enable_nco_3 = 1

        self.frequency_synth.gain_nco_0 = int(2**14)
        self.frequency_synth.gain_nco_1 = int(2**14)
        self.frequency_synth.gain_nco_2 = int(2**14)
        self.frequency_synth.gain_nco_3 = int(2**14)

        Ni = 2**16
        self.frequency_synth.step_size_0 = int((1.024e9 / 100) * Ni * 2**16)
        self.frequency_synth.step_size_1 = int((1.024e9 / 100) * Ni * 2**16)
        self.frequency_synth.step_size_2 = int((1.024e9 / 100) * Ni * 2**16)
        self.frequency_synth.step_size_3 = int((1.024e9 / 100) * Ni * 2**16)
                    help='height of the image',
                    required=True)
parser.add_argument('-M', '--mode', type=str, help='mode of the camera')
args = parser.parse_args()
print(args)

if (args.mode):
    set_values(args.mode, args.width, args.height)
width = args.width * 4  #vdma needs data in to bytes not into words,each pixel is 4 bytes so width * 4
in_cma = xlnk.cma_array(shape=(width * args.height, ), dtype=np.uint8)
print('Created cma')
print("size of input arr", in_cma.size)
in_physical_addr = in_cma.physical_address
print("the physical address is = ", in_physical_addr)

vdma.write(status, 0xffffffff)
vdma.write(0x30, 0x8b)
print("cr = ", vdma.read(0x30))

vdma.write(frame_delay, width)
print("frame_delay = ", vdma.read(frame_delay))

vdma.write(vsize, args.height)
print("vsize = ", vdma.read(vsize))

vdma.write(hsize, width)
print("hsize = ", vdma.read(hsize))

vdma.write(s2m_start, in_physical_addr)
print("s2m = ", vdma.read(s2m_start))
Beispiel #9
0
    def __init__(self,
                 bitfile_name=None,
                 init_rf_clks=True,
                 dark_theme=False,
                 presentation_mode=False,
                 **kwargs):
        """Construct a new QpskOverlay

        bitfile_name: Optional. If left None, the 'rfsoc_qpsk.bit' bundled with this
                      rfsoc-qpsk package will be used.

        init_rf_clks: If true (default), the reference clocks are configured
                      for all tiles. If the clocks are already configured, set
                      to false for faster execution.

        dark_theme: Flat to enable a dark theme for plots

        presentation_mode: Flag to enable a dark theme with thick lines and
                           bigger font

        """

        # Generate default bitfile name
        if bitfile_name is None:
            this_dir = os.path.dirname(__file__)
            bitfile_name = os.path.join(this_dir, 'bitstream',
                                        'rfsoc_qpsk.bit')

        # Set optional theming for dark mode
        if dark_theme:
            from IPython.display import display, HTML
            import plotly.io as pio

            # Apply plotly theming
            dark_template = pio.templates['plotly_dark']
            dark_template.layout.paper_bgcolor = 'rgb(0,0,0,0)'
            dark_template.layout.plot_bgcolor = 'rgb(0,0,0,0)'
            dark_template.layout.legend.bgcolor = 'rgb(0,0,0,0)'
            pio.templates['dark_plot'] = dark_template
            pio.templates.default = 'dark_plot'

        # Set optional theming for presentation mode
        if presentation_mode:
            from IPython.display import display, HTML
            import plotly.io as pio

            # Apply plotly theming
            pio.templates.default = 'plotly_dark+presentation'

            # Force dark style for ipywidget tab background
            display(
                HTML("""
            <style>
            .jupyter-widgets.widget-tab > .widget-tab-contents {
              background: inherit !important;
            }
            </style>
            """))

        # Set FPD and LPD interface widths
        from pynq import MMIO
        fpd_cfg = MMIO(0xfd615000, 4)
        fpd_cfg.write(0, 0x00000A00)
        lpd_cfg = MMIO(0xff419000, 4)
        lpd_cfg.write(0, 0x00000000)

        # Create Overlay
        super().__init__(bitfile_name, **kwargs)

        # Extact in-use dataconverter objects with friendly names
        self.rf = self.usp_rf_data_converter_0
        self.dac_tile = self.rf.dac_tiles[1]
        self.dac_block = self.dac_tile.blocks[2]

        self.adc_tile = self.rf.adc_tiles[0]
        self.adc_block = self.adc_tile.blocks[0]

        # Start up LMX clock
        if init_rf_clks:
            xrfclk.set_all_ref_clks(409.6)

        # Set sane DAC defaults
        self.dac_tile.DynamicPLLConfig(1, 409.6, 1228.8)
        self.dac_block.NyquistZone = 2
        self.dac_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_IMMEDIATE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 1000,
            'MixerMode': xrfdc.MIXER_MODE_C2R,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.dac_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.dac_tile.SetupFIFO(True)

        # Set sane ADC defaults
        self.adc_tile.DynamicPLLConfig(1, 409.6, 1228.8)
        self.adc_block.NyquistZone = 2
        self.adc_block.MixerSettings = {
            'CoarseMixFreq': xrfdc.COARSE_MIX_BYPASS,
            'EventSource': xrfdc.EVNT_SRC_TILE,
            'FineMixerScale': xrfdc.MIXER_SCALE_1P0,
            'Freq': 1000,
            'MixerMode': xrfdc.MIXER_MODE_R2C,
            'MixerType': xrfdc.MIXER_TYPE_FINE,
            'PhaseOffset': 0.0
        }
        self.adc_block.UpdateEvent(xrfdc.EVENT_MIXER)
        self.adc_tile.SetupFIFO(True)

        # Touch RX and TX drivers for strict evaluation
        self.qpsk_tx.qpsk_tx.enable = 1
        self.qpsk_rx.qpsk_rx_dec.enable = 1
        self.qpsk_rx.qpsk_rx_csync.enable = 1
        self.qpsk_rx.qpsk_rx_rrc.enable = 1
        self.qpsk_rx.qpsk_rx_tsync.enable = 1

        self.timers = TimerRegistry()
Beispiel #10
0
class cv2pynqDiverImageFilters(DefaultHierarchy):
    def __init__(self, description):
        super().__init__(description)
        self.intc1 = MMIO(0x43C10000, 0x10000)  #get axis_interconnect_1
        self.intc2 = MMIO(0x43C20000, 0x10000)  #get axis_interconnect_2
        self.filter = 1
        self.intc1.write(0x40 + 0 * 4, 0x80000000)  #disable master0
        self.intc1.write(0x40 + 1 * 4, 0x00000000)  #select slave0 for master1
        self.intc1.write(0x40 + 2 * 4, 0x80000000)  #disable master2
        self.intc1.write(0x40 + 3 * 4, 0x80000000)  #disable master3
        self.intc1.write(0x40 + 4 * 4, 0x80000000)  #disable master4
        self.intc1.write(0x40 + 5 * 4, 0x80000000)  #disable master5
        self.intc2.write(0x40, self.filter)  #select slave# for master0
        self.intc1.write(0x00, 0x2)  #reset interconnect 1
        self.intc2.write(0x00, 0x2)  #reset interconnect 2

    @staticmethod
    def checkhierarchy(description):
        if 'axi_dma_0' in description['ip'] \
           and 'axis_interconnect_1' in description['ip'] \
           and 'axis_interconnect_2' in description['ip'] \
           and 'canny_edge_0' in description['ip'] \
           and 'filter2D_hls_0' in description['ip'] \
           and 'filter2D_f_0' in description['ip'] \
           and 'erode_hls_0' in description['ip'] \
           and 'dilate_hls_0' in description['ip'] \
           and 'filter2D_hls_5_0' in description['ip']:
            return True
        return False

    def select_filter(self, filter):
        if not self.filter == filter:
            self.intc1.write(0x40 + self.filter * 4,
                             0x80000000)  #disable old master
            self.intc1.write(0x40 + filter * 4,
                             0x00000000)  #select slave0 for new master
            self.intc2.write(0x40, filter)  #select new slave for master0
            self.intc1.write(0x00, 0x2)  #reset interconnect 1
            self.intc2.write(0x00, 0x2)  #reset interconnect 2
            self.filter = filter
Beispiel #11
0
class DevMode(object):
    """Control an IO processor running the developer mode program. 
    
    This class will wait for Python to send commands to Pmod / Arduino IO, 
    IIC, or SPI.

    Attributes
    ----------
    if_id : int
        The interface ID (1,2,3) corresponding to (PMODA,PMODB,ARDUINO).
    iop : _IOP
        IO processor instance used by DevMode.
    iop_switch_config :list
        IO processor switch configuration (8 or 19 integers).
    mmio : MMIO
        Memory-mapped IO instance to read and write instructions and data.
    
    """
    def __init__(self, if_id, switch_config):
        """Return a new instance of a DevMode object.
        
        Parameters
        ----------
        if_id : int
            The interface ID (1,2,3) corresponding to (PMODA,PMODB,ARDUINO).
        switch_config : list
            IO Processor switch configuration (8 or 19 integers).
            
        """
        if not if_id in [PMODA, PMODB, ARDUINO]:
            raise ValueError("No such IOP for DevMode.")
            
        self.if_id = if_id
        self.iop = request_iop(if_id, iop_const.MAILBOX_PROGRAM)
        self.iop_switch_config = list(switch_config)
        self.mmio = MMIO(self.iop.mmio.base_addr + iop_const.MAILBOX_OFFSET, \
                         iop_const.MAILBOX_SIZE)
                        
    def start(self):
        """Start the IO Processor.
        
        The IOP instance will start automatically after instantiation.
        
        This method will:
        1. zero out mailbox CMD register;
        2. load switch config;
        3. set IOP status as "RUNNING".
        
        """
        self.iop.start()
        self.mmio.write(iop_const.MAILBOX_PY2IOP_CMD_OFFSET, 0)
        self.load_switch_config(self.iop_switch_config)

    def stop(self):
        """Put the IO Processor into Reset.
        
        This method will set IOP status as "STOPPED".
        
        """
        self.iop.stop()

    def load_switch_config(self, config=None):
        """Load the IO processor's switch configuration.
        
        This method will update switch config.
        
        Parameters
        ----------
        config: list
            A switch configuration list of integers.

        Raises
        ----------
        TypeError
            If the config argument is not of the correct type.
            
        """
        if self.if_id in [PMODA, PMODB]:
            if config == None:
                config = iop_const.PMOD_SWCFG_DIOALL
            elif not len(config) == iop_const.PMOD_SWITCHCONFIG_NUMREGS:
                raise TypeError('Invalid switch config {}.'.format(config))
                
            # Build switch config word 
            self.iop_switch_config = config
            sw_config_word = 0
            for ix, cfg in enumerate(self.iop_switch_config): 
                sw_config_word |= (cfg << ix*4)
                
            # Disable, configure, enable switch
            self.write_cmd(iop_const.PMOD_SWITCHCONFIG_BASEADDR + 4, 0)
            self.write_cmd(iop_const.PMOD_SWITCHCONFIG_BASEADDR, \
                           sw_config_word)
            self.write_cmd(iop_const.PMOD_SWITCHCONFIG_BASEADDR + 7, \
                           0x80, dWidth=1)
                           
        elif self.if_id in [ARDUINO]:
            if config == None:
                config = iop_const.ARDUINO_SWCFG_DIOALL
            elif not len(config) == iop_const.ARDUINO_SWITCHCONFIG_NUMREGS:
                raise TypeError('Invalid switch config {}.'.format(config))
                
            # Build switch config word 
            self.iop_switch_config = config
            sw_config_words = [0, 0, 0, 0]
            for ix, cfg in enumerate(self.iop_switch_config): 
                if ix < 6:
                    sw_config_words[0] |= (cfg << ix*2)
                elif ix == 6:
                    sw_config_words[0] |= (cfg << 31)
                elif 7 <= ix < 11:
                    sw_config_words[1] |= (cfg << (ix-7)*4)
                elif 11 <= ix < 15:
                    sw_config_words[2] |= (cfg << (ix-11)*4)
                else:
                    sw_config_words[3] |= (cfg << (ix-15)*4)
                
                # Configure switch
                for i in range(4):
                    self.write_cmd(iop_const.ARDUINO_SWITCHCONFIG_BASEADDR + \
                                   4*i, sw_config_words[i])
                                   
        else:
            raise ValueError("Cannot load switch for unknown IOP.")
            
    def status(self):
        """Returns the status of the IO processor.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        str
            The IOP status ("IDLE", "RUNNING", or "STOPPED").
        
        """
        return self.iop.state
       
    def write_cmd(self, address, data, dWidth=4, dLength=1, timeout=10):
        """Send a write command to the mailbox.
        
        Parameters
        ----------
        address : int
            The address tied to IO processor's memory map.
        data : int
            32-bit value to be written (None for read).
        dWidth : int
            Command data width.
        dLength : int
            Command burst length (currently only supporting dLength 1).
        timeout : int
            Time in milliseconds before function exits with warning.
        
        Returns
        -------
        None
        
        """
        return self._send_cmd(iop_const.WRITE_CMD, address, data, 
                                dWidth=dWidth, timeout=timeout)

    def read_cmd(self, address, dWidth=4, dLength=1, timeout=10):
        """Send a read command to the mailbox.
        
        Parameters
        ----------
        address : int
            The address tied to IO processor's memory map.
        dWidth : int
            Command data width.
        dLength : int
            Command burst length (currently only supporting dLength 1).
        timeout : int
            Time in milliseconds before function exits with warning.
        
        Returns
        -------
        list
            A list of data returned by MMIO read.
        
        """
        return self._send_cmd(iop_const.READ_CMD, address, None, 
                                dWidth=dWidth, timeout=timeout)

    def is_cmd_mailbox_idle(self): 
        """Check whether the IOP command mailbox is idle.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        bool
            True if IOP command mailbox idle.
        
        """
        mb_cmd_word = self.mmio.read(iop_const.MAILBOX_PY2IOP_CMD_OFFSET)
        return (mb_cmd_word & 0x1) == 0

    def get_cmd_word(self, cmd, dWidth, dLength):
        """Build the command word.

        Note
        ----
        The returned command word has the following format:
        Bit [0]     : valid bit.
        Bit [2:1]   : command data width.
        Bit [3]     : command type (read or write).
        Bit [15:8]  : command burst length.
        Bit [31:16] : unused.
        
        Parameters
        ----------        
        cmd : int
            Either 1 (read IOP register) or 0 (write IOP register).
        dWidth : int
            Command data width.
        dLength : int
            Command burst length (currently only supporting dLength 1).
            
        Returns
        -------
        int
            The command word following a specific format.
            
        """
        word = 0x1                    # cmd valid
        word = word | (dWidth-1) << 1 # cmd dataWidth    (3->4B, 1->2B, 0->1B)
        word = word | (cmd) << 3      # cmd type         (1->RD, 0->WR)
        word = word | (dLength) << 8  # cmd burst length (1->1 word)
        word = word | (0) << 16       # unused
              
        return word

    def _send_cmd(self, cmd, address, data, dWidth=4, dLength=1, timeout=10):
        """Send a command to the IO processor via mailbox.

        Note
        ----
        User should avoid to call this method directly. 
        Use the read_cmd() or write_cmd() instead.

        Example:
            >>> _send_cmd(1, 4, None)  # Read address 4.
            
        Parameters
        ----------        
        cmd : int
            Either 1 (read IOP Reg) or 0 (write IOP Reg).
        address : int
            The address tied to IO processor's memory map.
        data : int
            32-bit value to be written (None for read).
        dWidth : int
            Command data width.
        dLength : int
            Command burst length (currently only supporting dLength 1).
        timeout : int
            Time in milliseconds before function exits with warning.
            
        Raises
        ------
        LookupError
            If it takes too long to receive the ACK from the IOP.

        """
        self.mmio.write(iop_const.MAILBOX_PY2IOP_ADDR_OFFSET, address)
        if data != None:
            self.mmio.write(iop_const.MAILBOX_PY2IOP_DATA_OFFSET, data)
        
        # Build the write command
        cmd_word = self.get_cmd_word(cmd, dWidth, dLength)
        self.mmio.write(iop_const.MAILBOX_PY2IOP_CMD_OFFSET, cmd_word)

        # Wait for ACK in steps of 1ms
        cntdown = timeout
        while not self.is_cmd_mailbox_idle() and cntdown > 0:
            time.sleep(0.001)
            cntdown -= 1

        # If ACK is not received, alert users.
        if cntdown == 0:
            raise LookupError("DevMode _send_cmd() not acknowledged.")

        # Return data if expected from read, otherwise return None
        if cmd == iop_const.WRITE_CMD: 
            return None
        else:
            return self.mmio.read(iop_const.MAILBOX_PY2IOP_DATA_OFFSET)
Beispiel #12
0
class PulseAcq():
    def __init__(self, GPIO_ADDRESS, GPIO_RANGE, DMA_ADDRESS, DMA_RANGE):
        self.gpio = MMIO(GPIO_ADDRESS, GPIO_RANGE)
        self.dma = MMIO(DMA_ADDRESS, DMA_RANGE)
        self.gpioDataOut = 0
        return

    def setResetn(self, val):
        mask = 0b1111111111111111111111110
        self.gpioDataOut = (self.gpioDataOut & mask) | (val << 0)
        self.gpio.write(0, self.gpioDataOut)
        return

    def setCounterMax(self, val):
        mask = 0b0000000000000000000000001
        self.gpioDataOut = (self.gpioDataOut & mask) | (val << 1)
        self.gpio.write(0, self.gpioDataOut)
        return

    def getState(self):
        return self.gpio.read(0x0008) & 0b111

    def getStreamUpCounter(self):
        return (self.gpio.read(0x0008) >> 3)

    def dmaS2MMIsIdle(self):
        isIdle = bool(self.dma.read(0x34) & (1 << 1))
        return isIdle

    def dmaS2MMConfig(self, bufferAddress):
        self.dma.write(0x48, bufferAddress)
        return

    def dmaS2MMRun(self, bufferBytesLen):
        self.dma.write(0x58, bufferBytesLen)
        return

    def dmaS2MMReset(self):
        self.dma.write(0x30, (1 << 2))
        return

    def dmaS2MMHalt(self):
        self.dma.write(0x30, 0)
        return

    def dmaS2MMStart(self):
        self.dma.write(0x30, 1)
        return
Beispiel #13
0
class ST:
    def __init__(self):
        self.ov = Overlay("TEST_wrapper.bit", 0)
        self.ov.download()
        self.DATA = MMIO(0x41200000, 0x10000)
        self.UTIL = MMIO(0x41210000, 0x10000)
        self.DELAY0 = MMIO(0x41220000, 0x10000)
        self.DELAY1 = MMIO(0x41230000, 0x10000)
        self.DEBUG = MMIO(0x41240000, 0x10000)
        self.DUTIL = MMIO(0x41250000, 0x10000)
        self.set_delays(DEFAULT_DELAY_CALIBRATIONS)
        log.info("Ready")

    def wait_for_rdy(self):
        while (self.UTIL.read(0x8) == 0):
            pass

    def read_time(self):
        course_time = self.DATA.read(0x0)
        log.debug("CT: " + str(course_time))
        finetimes = self.DATA.read(0x8)
        preftime = finetimes & 0xFF
        postftime = (finetimes & 0xFF00) >> 8
        log.debug("PRE: " + str(preftime))
        log.debug("POST: " + str(postftime))
        timetoconv = preftime - postftime
        timetoconv *= FTIME
        time = course_time / COURSE_CLK + timetoconv
        return time

    def proc(self):
        self.DUTIL.write(0x0, 0x1)
        sleep(0.1)
        self.UTIL.write(0x0, 0x1)
        self.wait_for_rdy()
        self.read_debug()
        time = self.read_time()
        log.info("TIME: " + str(time * 1e9))
        self.UTIL.write(0x0, 0x0)
        self.DUTIL.write(0x0, 0x0)
        return time

    def set_delays(self, dels):
        #self.DUTIL.write(0x0,0x1)
        self.DELAY0.write(0x0, int(dels[0]))
        self.DELAY0.write(0x8, int(dels[1]))
        self.DELAY1.write(0x0, int(dels[2]))
        self.DELAY1.write(0x8, int(dels[3]))
        #self.DUTIL.write(0x0,0x1)
    def read_debug(self):
        log.debug("STATEN: " + bin(self.DEBUG.read(0x0)))
        log.debug("STATEL: " + bin(self.DEBUG.read(0x8)))
Beispiel #14
0
ddr4_array = ddr4.array  # numpy array of uint32
print("size = {} words".format(ddr4_array.size))

# AXI-Lite hls access
regs = ovl.ip_dict["resnet18_0_0"]
base_addr_snd = regs["phys_addr"]
addr_range_snd = regs["addr_range"]
print("snd:base_addr = 0x{:X}".format(base_addr_snd))
print("snd:addr_range = {}".format(addr_range_snd))
mmio_hls = MMIO(base_addr_snd, addr_range_snd)

n = mmio_axi32.read(OFFSET_ID_VERSION)
print("ID_VERSION = 0x{:X}".format(n))
bid = mmio_axi32.read(OFFSET_STATUS)
print("Board ID = 0x{:X}".format(bid))
mmio_axi32.write(OFFSET_LED, 0x80 | bid)

time.sleep(1)

mmio_axi32.write(OFFSET_EXT_ADDR, 0xfff8)
mmio_axi32.write(OFFSET_EXT_DATA, 0x2)
mcubecluster.settbl(mmio_axi32)

# set ddr data
ddr = np.loadtxt('./resnet18_param/ddr0.txt', dtype='uint32')
ddr4_array[0:len(ddr)] = ddr
print('DDRSIZE: ' + str(len(ddr) * 2))

# DMA

dma = ovl.axi_dma_0
Beispiel #15
0
class Motor_Controller(object):  # TODO comments
    """Class for the motor control. 

    This class is used to control the motor as well as read the status motor
    parameters. Motor control modes include: Speed mode and Current mode.
    In speed mode, the speed and direction of the motor are controlled using
    the RPM_Sp register. In current mode, the Torque_Sp register controls the
    current Iq to the motor. Relationship between current and torque is:
    Current = Torque*(0.00039)

    Attributes
    ----------
    mmio_blocks : dict
        A dict of IP blocks used by the motor controller.
    motor_modes : list
        A list of available modes of the motor controller.
    """

    def __init__(self):
        self.mmio_control = MMIO(CONTROL_BLOCK_OFFSET, ADDRESS_RANGE)
        self.mmio_capture = MMIO(CAPTURE_BLOCK_OFFSET, ADDRESS_RANGE)
        self.mmio_blocks = {'control_axi_block': hex(CONTROL_BLOCK_OFFSET),
                            'capture_axi_block': hex(CAPTURE_BLOCK_OFFSET)}
        self.motor_modes = ('reset_mode', 'torque_mode', 'rpm_mode', 'init_mode')
        self.motor_capture_modes = ('ia_ib_rpm_angle_filtered', 'ia_ib_rpm_angle_raw', 'ialpha_ibeta_rpm_angle',  'id_iq_rpm_angle', 'vd_vq_angle', 'valpha_vbeta_angle', 'va_vb_vc', 'va_vb_vc_PWM')

    def set_mode(self, mode='reset_mode'):
        reg_list = [CONTROL, FLUX_SP, FLUX_KP, FLUX_KI, TORQUE_SP, TORQUE_KP,
                    TORQUE_KI, RPM_SP, RPM_KP, RPM_KI, VD, VQ]
                    # SHIFT, DECIMATION, CONTROL_MPC, CONTROL_REG2]
                    # the commented out registers above won't be changed when the mode is set 
        for reg in reg_list:
            if mode == 'torque_mode':
                self.mmio_control.write(reg.offset, reg.torque_mode)
            elif mode == 'rpm_mode':
                self.mmio_control.write(reg.offset, reg.rpm_mode)
            elif mode == 'init_mode':
                self.mmio_control.write(reg.offset, reg.init_mode)
            else:
                self.mmio_control.write(reg.offset, reg.reset_mode)

    def set_rpm(self, value):
        self.mmio_control.write(RPM_SP.offset, value)

    def set_torque(self, value):
        self.mmio_control.write(TORQUE_SP.offset, value)

    def stop(self):
        self.mmio_control.write(CONTROL.offset, CONTROL.reset_mode)

    def _read_controlreg(self, offset):
        result = self.mmio_control.read(offset)
        return result

    def _write_controlreg(self, offset, value):
        self.mmio_control.write(offset, value)

    def write_capturereg(self, offset, value):
        self.mmio_capture.write(offset, value)

    def read_capturereg(self, offset):
        result = self.mmio_capture.read(offset)
        return result

    def stream_capture(self, capture_address):  # TODO constants
        # Offset 0 - Control reg
        self.write_capturereg(0, 2)
        # Offset 4 - Transfer size
        self.write_capturereg(4, 256)
        # Offset 12 - Start address
        self.write_capturereg(12, capture_address)
        # Offset 16 - End address
        self.write_capturereg(16, capture_address + 256)
        # Offset 0 - Control reg
        self.write_capturereg(0, 3)
Beispiel #16
0
class FGPU:
    def __init__(self):
        """Class to use the FGPU architecture in iPython
        
        FGPU is a soft GPU architecture for FPGAs. It can be programmed
        using OpenCL. This class offers:
        * Compilation of OpenCL kernels
        * Binding memory regions to kernel parameters
        * Download tasks along with their binaries and execute them
        """

        self.bitfile = ""  # bit file to program
        self.params = {}
        # array to store the HW physical addresses of kernel parameters

        #initialize MMIO object
        self.base_addr = 0x43C00000  # 1st HW address of FGPU
        self.addr_space = 0x10000  # size of FGPU address space
        self.status_reg_offset = 0x8000  # HW address of a control register
        self.start_reg_offset = 0x8004  # HW address of a control register
        self.clean_cache_reg_offset = 0x8008  # HW address of a control register
        self.initiate_reg_offset = 0x800C  # HW address of a control register
        self.mmio = MMIO(
            self.base_addr,
            self.addr_space)  # map the control regsiter address space

        #initialize kernel descriptor
        self.kdesc = {
            #basic parameters (to be set by the user)
            'size0': 0,  # size of index space in 1st dimension
            'size1': 0,  # size of index space in 2nd dimension
            'size2': 0,  # size of index space in 3rd dimension
            'offset0': 0,  # offset of kernel index space in 1st dimension
            'offset1': 0,  # offset of kernel index space in 2nd dimension
            'offset2': 0,  # offset of kernel index space in 3rd dimension
            'wg_size0': 0,  # work-group size in 1st dimension
            'wg_size1': 0,  # work-group size in 2nd dimension
            'wg_size2': 0,  # work-group size in 3rd dimension
            'nParams': 0,  # number of kernel parameters
            'nDim': 0,  # number of activated dimensions in kernel index space

            #calculated parameters (computed according to user input)
            'size': 0,  # number of work-items to be launched
            'n_wg0': 0,  # number of work-groups to launch in 1st dimension 
            'n_wg1': 0,  # number of work-groups to launch in 2nd dimension 
            'n_wg2': 0,  # number of work-groups to launch in 3rd dimension 
            'wg_size': 0,  # number of work-items in a work-group
            'nWF_WG': 0,  # number of wavefronts in a work-group
            'start_addr':
            0  # address of the first instruction to be executed in CRAM
        }

        # file name that contains kernel code
        self.kernelFileName = ""
        #kernel code
        self.kernel_code = []

    def __set_fclk0(self):
        """This internal method sets the output frequency of FCLK0 to 50MHz. 
        
        This has to be performed for any FGPU v2 overlay or bitstream
        """
        self._SCLR_BASE = 0xf8000000
        self._FCLK0_OFFSET = 0x170
        addr = self._SCLR_BASE + self._FCLK0_OFFSET
        FPGA0_CLK_CTRL = MMIO(addr).read()
        if FPGA0_CLK_CTRL != 0x300a00:
            #divider 0
            shift = 20
            mask = 0xF00000
            value = 0x3
            self.__set_regfield_value(addr, shift, mask, value)
            #divider 1
            shift = 8
            mask = 0xF00
            value = 0xa
            self.__set_regfield_value(addr, shift, mask, value)

    def __set_regfield_value(self, addr, shift, mask, value):

        curval = MMIO(addr).read()
        MMIO(addr).write(0, ((curval & ~mask) | (value << shift)))

    def download_bitstream(self):
        """Set the clock frequency and download the bitstream
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        """
        self.__set_fclk0()
        Bitstream(self.bitfile).download()

    def download_kernel_code(self):
        """Download the binary to the compiled kernel into the CRAM (Code RAM) of FGPU
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        """
        #kernel code memory offset
        kc_offset = 0x4000
        #copy instructions into sequential memory
        for i_offset, instruction in enumerate(self.kernel_code):
            self.mmio.write(kc_offset + i_offset * 4, instruction)

    def prepare_kernel_descriptor(self):
        """Compute the settings for the kernel to be executed according to user input.
        For example, it computes the number of wavefronts within a work-group and
        the number of work-groups to be launched.
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        """
        if self.kdesc['nDim'] == 1:
            self.kdesc['wg_size'] = self.kdesc['wg_size0']
            self.kdesc['size'] = self.kdesc['size0']
            self.kdesc['wg_size1'] = self.kdesc['wg_size2'] = 1
            self.kdesc['size1'] = self.kdesc['size2'] = 1
        elif self.kdesc['nDim'] == 2:
            self.kdesc['size'] = self.kdesc['size0'] * self.kdesc['size1']
            self.kdesc[
                'wg_size'] = self.kdesc['wg_size0'] * self.kdesc['wg_size1']
            self.kdesc['wg_size2'] = 1
            self.kdesc['size2'] = 1

        self.kdesc['size'] = self.kdesc['size0'] * self.kdesc[
            'size1'] * self.kdesc['size2']
        self.kdesc['wg_size'] = self.kdesc['wg_size0'] * self.kdesc[
            'wg_size1'] * self.kdesc['wg_size2']

        self.kdesc['n_wg0'] = math.ceil(self.kdesc['size0'] /
                                        self.kdesc['wg_size0'])
        self.kdesc['n_wg1'] = math.ceil(self.kdesc['size1'] /
                                        self.kdesc['wg_size1'])
        self.kdesc['n_wg2'] = math.ceil(self.kdesc['size2'] /
                                        self.kdesc['wg_size2'])

        if self.kdesc['wg_size'] < 1 or self.kdesc['wg_size'] > 512:
            raise AssertionError()
        self.kdesc['nWF_WG'] = math.ceil(self.kdesc['wg_size'] / 64)

    def download_kernel_descriptor(self):
        """Download the kernel settings into the LRAM (Link RAM)
        
        A kernel descriptor consists of a total of 32 32bit entirs:
        * The first 16 ones are for general settings, e.g. size of index space
        * The last 16 ones are for kernel parameter values
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        """
        # clear descriptor
        for offset in range(0, 31):
            self.mmio.write(offset * 4, 0)
        #set number of wavefronts in a WG
        #set the start address of the first instruction to be executed
        self.mmio.write(
            0, ((self.kdesc['nWF_WG'] - 1) << 28 | self.kdesc['start_addr']))
        self.mmio.write(1 * 4, self.kdesc['size0'])
        self.mmio.write(2 * 4, self.kdesc['size1'])
        self.mmio.write(3 * 4, self.kdesc['size2'])
        self.mmio.write(4 * 4, self.kdesc['offset0'])
        self.mmio.write(5 * 4, self.kdesc['offset1'])
        self.mmio.write(6 * 4, self.kdesc['offset2'])
        self.mmio.write(
            7 * 4,
            ((self.kdesc['nDim'] - 1) << 30 | self.kdesc['wg_size2'] << 20
             | self.kdesc['wg_size1'] << 10 | self.kdesc['wg_size0']))
        self.mmio.write(8 * 4, self.kdesc['n_wg0'] - 1)
        self.mmio.write(9 * 4, self.kdesc['n_wg1'] - 1)
        self.mmio.write(10 * 4, self.kdesc['n_wg2'] - 1)
        self.mmio.write(11 * 4,
                        (self.kdesc['nParams'] << 28 | self.kdesc['wg_size']))

        if len(self.params) == 0:
            raise AssertionError()

        for i in range(0, len(self.params)):
            self.mmio.write((16 + i) * 4, self.params[i])

    def execute_kernel(self):
        """Execute a kernel and wait until execution ends
        
        Parameters
        ----------
        None
        
        Returns
        -------
        float
            Execution time in seconds
        """
        start = time.time()
        self.mmio.write(self.start_reg_offset, 0x1)
        while self.mmio.read(self.status_reg_offset) == 0:
            pass
        end = time.time()
        return (end - start)

    def set_paramerter(self, paramIndex, val, mem_obj):
        """Set the value of a kernel parameter 
        
        Kernel parametrs are defind in the kernel header.
        
        Examples
        --------
            __kernel void foo(__global unsigned *in, __global unsigned *out, unsigned len)
                                paramIndex = 0         paramIndex=1           paramIndex=2
        Parameters
        ----------
        paramIndex : unsigned integer in the range [0..15]
            The index of the parameter to be set in kernel header. 
            
        
        val: void
            The Value that the parameter should take. It will be bitcasted to 32 unsigned int.
            
        mem_obj: xlnk
            An object fo class xlnk defined by Xilinx.
            This xlnk class enbales CMA (Contiguous Memory Allocator) memry management.
            It is needed to get the physical address of the parameter/memory buffer passed from iPython.
            
        Returns
        -------
        None
        """
        if paramIndex not in range(0, 16):
            raise AssertionError()
        self.params[paramIndex] = mem_obj.cma_get_phy_addr(
            mem_obj.cma_cast(val, "void"))
        self.kdesc['nParams'] = len(self.params)

    def set_size(self, size, dim=0):
        """Set the size of the index space in any dimension.
        
        The size is equal to the number of work-items that will be launched 
        in the corresponding dimension.
        
        Parameters
        ----------
        size: unsigned int
            The required size for the index space in some dimension
        
        dim: unisgned int in range[0..2]
            The dimension whose size has to be set
            
        Returns
        -------
        None
        """
        if size < 1:
            raise AssertionError()
        if dim == 0:
            self.kdesc['size0'] = size
        elif dim == 1:
            self.kdesc['size1'] = size
        elif dim == 2:
            self.kdesc['size2'] = size
        else:
            raise AssertionError()

    def set_work_group_size(self, wg_size, dim=0):
        """Set the size of work-groups in any dimension
        
        Note
        Parameters
        ----------
        wg_size: unsigned int in range [1..512]
            The size of a work-group in some dimension
            
        dim: unsigned int in range [0..2]
            The dimension whose work-group size hast to be set
        
        Returns
        -------
        None
        """
        if wg_size < 1 | wg_size > 512:
            raise AssertionError()
        if dim == 0:
            self.kdesc['wg_size0'] = wg_size
        elif dim == 1:
            self.kdesc['wg_size1'] = wg_size
        elif dim == 2:
            self.kdesc['wg_size2'] = wg_size
        else:
            raise AssertionError()

    def set_num_dimensions(self, dims):
        """Set the number of dimesions of the required index space
        
        Note
        ----
        Only 1 & 2 dimensional index spaces are supported
        
        Parameters
        ----------
        dims: unsigned int in range [1..3]
            
        Returns
        -------
        None
        """
        if dims == 1 or dims == 2:  #dim=3 is not yet supported
            self.kdesc['nDim'] = dims
        else:
            raise AssertionError()

    def set_offset(self, value=0, dim=0):
        """Sets the offsets of the index space in any dimension
        
        Examples
        --------
            Considering a kernel in a single dimension where 
            * offset = 10
            * size = 30
            30 kernels will be launched whose indices are in the range [10,40]
            
        Parameters
        ----------
        value: unsigned int
            Minimum number of the global id of any work-item
        
        Returns
        -------
        None
        """
        if value < 0:
            raise AssertionError()
        if dim == 0:
            self.kdesc['offset0'] = value
        elif dim == 1:
            self.kdesc['offset1'] = value
        elif dim == 2:
            self.kdesc['offset2'] = value
        else:
            raise AssertionError()

    def set_kernel_file(self, fileName):
        """Set the name of the file that contains the kernel OpenCL code
        
        Parameters
        ----------
        fileName: string
        
        Returns
        -------
        None
        """
        if os.path.isfile(fileName):
            self.kernelFileName = os.path.abspath(fileName)
        else:
            raise AssertionError()

    def compile_kernel(self, show_objdump=False):
        """Compile the kernel OpenCL code and read the generated binary
        
        The compilation process consists of three steps executed by the script "compile.sh"
        1. Clang compiles the OpenCL code into LLVM IR assembly (code.ll)
        2. The FGPU backend translates the IR into FGPU ISA and generates the object file (code.bin)
        3. The .text section of the generated object file is converted to an integer array (code.array)
        
        The content of the file code.array is read afterwards and stored in the variable kernel_code
        
        Note
        ----
        * Any mistakes in the OpenCL code will be shown if the clang-compilation was not successful
        
        Parameters
        ----------
        showObjdump: boolean
            Print an objdump for the .text section of the generated object file if set to true
        
        Returns
        -------
        None
        """
        if not os.path.isfile(self.kernelFileName):
            raise AssertionError()
        # The OpenCL kernel is compiled with clang into LLVM IR.
        # The result is written in the file code.ll
        p = Popen([general_const.COMPILE_SH, self.kernelFileName],
                  stdout=PIPE,
                  stderr=PIPE)
        out = p.communicate(
        )  # returns a tuble of byte arrays from stdout and stderr
        print(str(out[0], "utf-8"))  # convert to string and print
        print(str(out[1], "utf-8"))  # convert to string and print
        if p.returncode != 0:
            # if clang failed; print the log file and return
            with open(general_const.CLANG_LOG, 'r') as fin:
                print(fin.read())
            return None
        #if clang compilation was not successful; the file code.ll will not exist
        if os.path.isfile(general_const.CODE_BIN):
            # Show the assembly of the compiled kernel
            if show_objdump:
                p = Popen(
                    [general_const.LLVM_OBJDUMP, "-d", general_const.CODE_BIN],
                    stdout=PIPE)
                out = p.communicate(
                )  # returns a tuble of byte arrays from stdout and stderr
                print(str(out[0], "utf-8"))  # convert to string and print
            with open(general_const.CODE_ARRAY) as f:
                self.kernel_code = []
                for line in f:  # read rest of lines
                    record = [int(x, 16) for x in line.split()]
                    self.kernel_code.append(record[0])

    def download_kernel(self):
        """Compute and download the kernel settings to FGPU
        
        Parameters
        ----------
        None
        
        Returns
        -------
        None
        """
        self.download_kernel_code()
        self.prepare_kernel_descriptor()
        self.download_kernel_descriptor()
        self.mmio.write(self.initiate_reg_offset, 0xFFFF)
        self.mmio.write(self.clean_cache_reg_offset, 0xFFFF)

    def set_bitFile(self, fileName):
        """Set the name of the bitstream file 
        
        Parameters
        ----------
        fileName: string
            
        Returns
        -------
        None
        """
        if os.path.isfile(fileName):
            self.bitfile = fileName
        else:
            raise AssertionError()
Beispiel #17
0
1    # coding: utf-8
2    
3    # In[1]:
4    
5    
6    ### SETUP load the overlay
7    # Set FPD and LPD interface widths
8    from pynq import MMIO
9    
10   fpd_cfg = MMIO(0xfd615000, 4)
11   fpd_cfg.write(0, 0x00000A00)
12   lpd_cfg = MMIO(0xff419000, 4)
13   lpd_cfg.write(0, 0x00000000)
14   
15   from pynq import Overlay
16   
17   overlay = Overlay("/home/xilinx/pynq/overlays/SMO_FULL_ULTRA_1/SMO_FULL_ULTRA_1.bit")
18   
19   
20   # In[2]:
21   
22   
23   from pynq import DefaultIP
24   import numpy as np
25   
26   class parse_files():
27       def __init__(self):
28           #super().__init__()
29           # dot product matrix will be computed from two training matrix streams 
30           self.training_labels_data_fi_uint8 = None
31           self.training_mat_data_fi_uint16 = None
Beispiel #18
0
class ST:
    def __init__(self):
        ol = Overlay("TEST_wrapper.bit", 0)
        ol.download()
        self.DATA = MMIO(0x43c00000, 0x10000)
        self.UTIL = MMIO(0x43c10000, 0x10000)
        self.loaded_data = []
        for i in range(FIFO_BUFFER):
            self.loaded_data.append(0)
        self.loaded_count = 0

    def calc_time(self, coarse, finet):
        ctime = coarse / REF_CLK
        finetimevalues = finet
        ftime0 = finetimevalues & 0xFF
        ftime1 = (finetimevalues & 0xFF00) >> 8
        #log.debug("FTIME0 -- "+bin(ftime0))
        #log.debug("FTIME1 -- " + bin(ftime1))
        return ctime + (ftime0 - ftime1) * FTIME

    def start(self):
        self.set_mreset(1)

    def stop(self):
        self.set_mreset(0)

    def flush_buffer(self):
        for i in range(FIFO_BUFFER):
            self.loaded_data[i] = 0
        self.loaded_count = 0

    def proc(self):
        self.read2048()
        return {"MOD": "ST", "LEN": self.loaded_count, "DAT": self.loaded_data}

    def read2048(self):
        if (self.read_empty() == 1):
            return
        for i in range(FIFO_BUFFER):
            if (self.read_empty() == 1):
                self.loaded_count = i
                return
            self.set_dreset(1)
            self.set_req(1)
            while (self.read_drdy() == 0):
                pass
            self.loaded_data[i] = self.read_coarse() | self.read_fine() << 32
            #print(self.loaded_data[i]&0xFFFFFFFF)
            self.set_req(0)
            self.set_dreset(0)
        self.loaded_count = FIFO_BUFFER

    def read_coarse(self):
        return self.DATA.read(0x0)

    def read_fine(self):
        return self.DATA.read(0x8)

    def read_drdy(self):
        return self.UTIL.read(0x8) & 0b1

    def read_empty(self):
        return (self.UTIL.read(0x8) & 0b10) >> 1

    def read_full(self):
        return (self.UTIL.read(0x8) & 0b100) >> 1

    def set_mreset(self, val):
        lastval = self.UTIL.read(0x0) & 0b110
        self.UTIL.write(0x0, lastval | (val & 0b1))

    def set_req(self, val):
        lastval = self.UTIL.read(0x0) & 0b101
        self.UTIL.write(0x0, lastval | ((val << 1) & 0b10))

    def set_dreset(self, val):
        lastval = self.UTIL.read(0x0) & 0b011
        self.UTIL.write(0x0, lastval | ((val << 2) & 0b100))
Beispiel #19
0
import time
from pynq import Overlay
from pynq import MMIO
ol = Overlay("numeroprimo.bit")
ol.download()
numeroprimo_ip = MMIO(0X43C00000, 0X10000)
numeroprimo_ip.write(0x10, 100000)
numeroprimo_ip.write(0x00, 1)
count = 0
inicio = time.time()
while (numeroprimo_ip.read(0x00) != 4):
    # Esperando Conclusao do calculo
    if (count == 0):
        count += 1
        print("Calculando...")
    # count+=1
fim = time.time()
print("Pronto! Status: %i, Loops: %i, Tempo: %.3fs" %
      (numeroprimo_ip.read(0x00), count, fim - inicio))
print("Numero primo na posicao %i eh %i" %
      (numeroprimo_ip.read(0x10), numeroprimo_ip.read(0x18)))
Beispiel #20
0
class PulseGen():
    def __init__(self, GPIO_ADDRESS, GPIO_RANGE, DMA_ADDRESS, DMA_RANGE):
        self.gpio = MMIO(GPIO_ADDRESS, GPIO_RANGE)
        self.dma = MMIO(DMA_ADDRESS, DMA_RANGE)
        self.gpioDataOut = 0
        return

    def setResetn(self, val):
        mask = 0b11111111111111111111111110
        self.gpioDataOut = (self.gpioDataOut & mask) | (val << 0)
        self.gpio.write(0, self.gpioDataOut)
        return

    def setTrig(self, val):
        mask = 0b11111111111111111111111101
        self.gpioDataOut = (self.gpioDataOut & mask) | (val << 1)
        self.gpio.write(0, self.gpioDataOut)
        return

    def setPulseWidth(self, val):
        mask = 0b00000000000000000000000011
        self.gpioDataOut = (self.gpioDataOut & mask) | (val << 2)
        self.gpio.write(0, self.gpioDataOut)
        return

    def getState(self):
        return self.gpio.read(0x0008) & 0b111

    def getStreamDownCounter(self):
        return (self.gpio.read(0x0008) >> 3)

    def dmaMM2SIsIdle(self):
        isIdle = bool(self.dma.read(0x4) & (1 << 1))
        return isIdle

    def dmaMM2SConfig(self, bufferAddress):
        self.dma.write(0x18, bufferAddress)
        return

    def dmaMM2SRun(self, bufferBytesLen):
        self.dma.write(0x28, bufferBytesLen)
        return

    def dmaMM2SReset(self):
        self.dma.write(0x0, (1 << 2))
        return

    def dmaMM2SHalt(self):
        self.dma.write(0x0, 0)
        return

    def dmaMM2SStart(self):
        self.dma.write(0x0, 1)
        return
Beispiel #21
0
class UartAXI:
    def __init__(self, address):
        # Setup axi core
        self.uart = MMIO(address, 0x10000, debug=False)
        self.address = address

    def getBit(self, num, pos):
        return (num & 1 << pos) >> pos

    def setupCtrlReg(self):
        # Reset FIFOs, disable interrupts
        self.uart.write(CTRL_REG, 1 << RST_TX | 1 << RST_RX)
        sleep(1)
        self.uart.write(CTRL_REG, 0)
        sleep(1)

    def currentStatus(self):
        """Returns object that specifies current status of axi core"""
        status = self.uart.read(STAT_REG)
        return {
            'RX_VALID': self.getBit(status, RX_VALID),
            'RX_FULL': self.getBit(status, RX_FULL),
            'TX_EMPTY': self.getBit(status, TX_EMPTY),
            'TX_FULL': self.getBit(status, TX_FULL),
            'IS_INTR': self.getBit(status, IS_INTR),
            'OVERRUN_ERR': self.getBit(status, OVERRUN_ERR),
            'FRAME_ERR': self.getBit(status, FRAME_ERR),
            'PARITY_ERR': self.getBit(status, PARITY_ERR)
        }

    def read(self, count, timeout=10):
        # status = currentStatus(uart) bad idea
        buf = ""
        stop_time = time() + timeout
        for i in range(count):
            # Wait till RX fifo has valid data, stop waiting if timeoutpasses
            while (not (self.uart.read(STAT_REG) & 1 << RX_VALID)) and (
                    time() < stop_time):
                pass
            if time() >= stop_time:
                break
            buf += chr(self.uart.read(RX_FIFO))
        return buf

    def write(self, buf, timeout=10):
        """
        buf: iterable
        
        """
        stop_time = time() + timeout
        wr_count = 0
        for i in buf:
            #Wait while TX FIFO is Full, stop waiting if timeout passes
            while (self.uart.read(STAT_REG)
                   & 1 << TX_FULL) and (time() < stop_time):
                pass
            # Check timeout
            if time() > stop_time:
                break
            self.uart.write(TX_FIFO, ord(i))
            wr_count += 1
        return wr_count

    def readLine(self):
        buf = self.read(1)
        if len(buf) == 0:
            return ""
        while '\r' not in buf:
            buf += self.read(1)
        return buf
Beispiel #22
0
def solve(boardstr, seed=12345, zero_padding=False):
    print('boardstr:')
    print(boardstr)
    print('seed:')
    print(seed)
    print('')

    # ボード文字列から X, Y, Z を読んでくる
    size_x = (ord(boardstr[1]) - ord('0')) * 10 + (ord(boardstr[2]) - ord('0'))
    size_y = (ord(boardstr[4]) - ord('0')) * 10 + (ord(boardstr[5]) - ord('0'))
    size_z = (ord(boardstr[7]) - ord('0'))

    # Overlay 読み込み
    OL = Overlay('pynqrouter.bit')
    OL.download()
    print(OL.ip_dict)
    print('Overlay loaded!')

    # MMIO 接続 (pynqrouter)
    mmio = MMIO(int(PL.ip_dict[IP][0]), int(PL.ip_dict[IP][1]))

    # MMIO 接続 & リセット (LED)
    mmio_led = MMIO(int(PL.ip_dict[IP_LED][0]), int(PL.ip_dict[IP_LED][1]))
    mmio_led.write(0, 0)

    # 入力データをセット
    imem = pack(boardstr)
    for i in range(len(imem)):
        mmio.write(OFFSET_BOARD + (i * 4), imem[i])

    mmio.write(OFFSET_SEED, seed)

    # スタート
    # ap_start (0 番地の 1 ビット目 = 1)
    mmio.write(0, 1)
    print('Start!')
    time_start = time.time()

    # ap_done (0 番地の 2 ビット目 = 2) が立つまで待ってもいいが
    #   done は一瞬だけ立つだけのことがあるから
    # ap_idle (0 番地の 3 ビット目 = 4) を待ったほうが良い
    iteration = 0
    while (mmio.read(0) & 4) == 0:
        # 動いてるっぽく見えるようにLチカさせる
        iteration += 1
        if iteration == 10000:
            mmio_led.write(0, 3)
        elif 20000 <= iteration:
            mmio_led.write(0, 12)
            iteration = 0

    # 完了の確認
    print('Done!')
    print('control:', mmio.read(0))
    time_done = time.time()
    elapsed = time_done - time_start
    print('elapsed:', elapsed)
    print('')

    # 状態の取得
    status = int(mmio.read(OFFSET_STATUS))
    print('status:', status)
    if status != 0:
        # 解けなかったらLEDを消す
        mmio_led.write(0, 0)
        sys.stderr.write('Cannot solve it!\n')
        return {'solved': False, 'solution': '', 'elapsed': -1.0}
    print('Solved!')

    # 解けたらLEDを全部つける
    mmio_led.write(0, 15)

    # 出力
    omem = []
    for i in range(len(imem)):
        omem.append(mmio.read(OFFSET_BOARD + (i * 4)))
    boards = unpack(omem)

    # 回答の生成
    solution = ('SIZE ' + str(size_x) + 'X' + str(size_y) + 'X' + str(size_z) +
                '\n')
    for z in range(size_z):
        solution += ('LAYER ' + str(z + 1) + '\n')
        for y in range(size_y):
            for x in range(size_x):
                if x != 0:
                    solution += ','
                i = ((x * MAX_X + y) << BITWIDTH_Z) | z
                if zero_padding:
                    solution += '{0:0>2}'.format(boards[i])  # 2桁の0詰め
                else:
                    solution += str(boards[i])  # 普通に表示
            solution += '\n'

    return {'solved': True, 'solution': solution, 'elapsed': elapsed}
Beispiel #23
0
class ConvLayer(object):
    def __init__(self, layer, fm, dim, xlnk, runFactor=1, batchsize=1):
        self.layer = layer
        self.fm = fm
        self.dim = dim
        self.xlnk = xlnk
        self.runFactor = runFactor
        self.batchsize = batchsize

        self.COMPUTE = 0
        self.CONV_WEIGHT = 1

        self.ol = Overlay(
            os.path.dirname(os.path.realpath(__file__)) + "/bitstream/" +
            layer + ".bit")
        self.dma = self.ol.axi_dma_0
        self.ip = MMIO(self.ol.ip_dict[self.layer]['phys_addr'],
                       self.ol.ip_dict[self.layer]['addr_range'])

        self.wBuff = []
        self.initWeights()

        self.cmaOut = []
        self.cmaTemp = []
        for b in range(self.batchsize):
            self.cmaOut.append(
                self.xlnk.cma_array(shape=(self.fm * (self.dim**2), ),
                                    dtype=np.float32))
            self.allocaCmaTemp()

    def __call__(self, input):
        self.ol.download()

        self.dma.sendchannel.start()
        self.dma.recvchannel.start()

        full = [list() for b in range(self.batchsize)]

        r = 0
        while r < self.runFactor:
            self.ip.write(0x10, self.CONV_WEIGHT)
            self.ip.write(0x00, 1)  # ap_start

            self.dma.sendchannel.transfer(self.wBuff[r])
            self.dma.sendchannel.wait()

            b = 0
            while b < self.batchsize:
                self.ip.write(0x10, self.COMPUTE)

                self.ip.write(0x00, 1)  # ap_start

                self.dma.recvchannel.transfer(self.cmaTemp[b][r])
                self.dma.sendchannel.transfer(input[b])

                self.dma.sendchannel.wait()
                self.dma.recvchannel.wait()

                temp = self.cmaTemp[b][r].reshape(
                    (self.dim**2, int(self.fm / self.runFactor)))
                temp = temp.transpose()
                temp = temp.reshape(
                    int(self.fm / self.runFactor) * (self.dim**2))
                full[b] = np.concatenate((full[b], temp))

                b += 1

            r += 1

        b = 0
        while b < self.batchsize:
            full[b] = full[b].reshape(self.fm,
                                      (self.dim**2)).transpose().flatten()
            np.copyto(self.cmaOut[b], full[b])
            b += 1

        return self.cmaOut

    def allocaCmaTemp(self):
        t = []
        for i in range(self.runFactor):
            t.append(
                self.xlnk.cma_array(shape=(int(self.fm / self.runFactor) *
                                           (self.dim**2), ),
                                    dtype=np.float32))
        self.cmaTemp.append(t)

    def initWeights(self):
        w = np.load(
            os.path.dirname(os.path.realpath(__file__)) + "/weights/" +
            self.layer + "/W.npy")
        b = np.load(
            os.path.dirname(os.path.realpath(__file__)) + "/weights/" +
            self.layer + "/b.npy")

        w = w.reshape((self.runFactor, -1))
        b = b.reshape((self.runFactor, -1))

        for i in range(self.runFactor):
            buff = self.xlnk.cma_array(shape=(w[i].size + b[i].size, ),
                                       dtype=np.float32)
            np.concatenate((w[i], b[i]), out=buff)
            self.wBuff.append(buff)
Beispiel #24
0
print("size = {} words".format(ddr4_array.size))

# AXI-Lite hls access

regs = ovl.ip_dict["resnet18_2_0"]
base_addr_snd = regs["phys_addr"]
addr_range_snd = regs["addr_range"]
print("snd:base_addr = 0x{:X}".format(base_addr_snd))
print("snd:addr_range = {}".format(addr_range_snd))
mmio_hls = MMIO(base_addr_snd, addr_range_snd)

n = mmio_axi32.read(OFFSET_ID_VERSION)
print("ID_VERSION = 0x{:X}".format(n))
bid = mmio_axi32.read(OFFSET_STATUS)
print("Board ID = 0x{:X}".format(bid))
mmio_axi32.write(OFFSET_LED, 0x80 | bid)

time.sleep(1)

mmio_axi32.write(OFFSET_EXT_ADDR, 0xfff8)
mmio_axi32.write(OFFSET_EXT_DATA, 0x2)
mcubecluster.settbl(mmio_axi32)

# set ddr data
ddr = np.loadtxt('../params/ddr2.txt', dtype='uint32')
ddr4_array[0:len(ddr)] = ddr
print('DDRSIZE: ' + str(len(ddr) * 2))

print("================Board ID = 0x{:X}=============".format(bid))
mcubecluster.moninf(mmio_axi32)
mcubecluster.monpktc(0, mmio_axi32)
Beispiel #25
0
class SP_TOOLS:
    def __init__(self):
        """Initializes the hardware by first loading and configuring the FPGA with the hardware design and then by creating handles for each AXI GPIO block that allows connection from the processing system to the FPGA fabric.

        """
        #Import FPGA configuration file and download
        self.OV = Overlay("Single_Photons/SP_OVERLAY.bit", 0)
        self.OV.download()
        ##Initialize pulse counter
        axi_offset = 0
        #Initialize data channels
        self.PC_DAT = []  #Holds all the handles for the data GPIO blocks
        #Initialize AXI GPIO modules
        for i in range(4):
            self.PC_DAT.append(
                MMIO(axi_base_addr + (axi_offset * axi_range), axi_range))
            self.PC_DAT[i].write(ch1_dir, agpi)  #ch1 is counts
            self.PC_DAT[i].write(ch2_dir, agpo)  #Ch2 is window
            self.PC_DAT[i].write(ch2_data, 0xFFFFFFFF)
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            axi_offset += 1

        #Initialize utility channels
        self.PC_UTIL = []  #Utility GPIO modules (containing reset signal and
        for i in range(4):
            self.PC_UTIL.append(
                MMIO(axi_base_addr + ((axi_offset) * axi_range), axi_range))
            self.PC_UTIL[i].write(ch1_dir, agpo)  #Reset
            self.PC_UTIL[i].write(ch1_data, 0x0)  #Hold in reset
            self.PC_UTIL[i].write(ch2_dir, agpi)  #Ready
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            axi_offset += 1
        #Initialize trigger controller
        self.T_UTIL = MMIO(0x41200000, 0x10000)
        self.T_UTIL.write(ch2_dir, 0x0)
        self.T_UTIL.write(ch2_data, 0x0)
        self.T_RDY_UTIL = MMIO(0x41210000, 0x10000)
        self.T_RDY_UTIL.write(ch1_dir, 0x1)
        ##Initialize single channel inter-rising_edge detection
        self.ST_DATA = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.ST_UTIL = MMIO(axi_base_addr + (axi_offset) * axi_range,
                            axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        ##Initialize interchannel coincidence timer
        self.CT_DATA = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.CT_UTIL = MMIO(axi_base_addr + (axi_offset) * axi_range,
                            axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        ##Initialize time tagger
        self.TT_CONFIG = MMIO(axi_base_addr + (axi_offset * axi_range),
                              axi_range)
        plog.info("TT_CONFIG: " + hex(axi_base_addr +
                                      (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_DATA0 = MMIO(axi_base_addr + (axi_offset * axi_range),
                             axi_range)
        plog.info("TT_DATA0: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_DATA1 = MMIO(axi_base_addr + (axi_offset * axi_range),
                             axi_range)
        plog.info("TT_DATA1: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_DELAY_DATA = MMIO(axi_base_addr + (axi_offset * axi_range),
                                  axi_range)
        plog.info("TT_DELAY: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_UTIL = MMIO(axi_base_addr + (axi_offset * axi_range),
                            axi_range)
        plog.info("TT_UTIL: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        ##Initialize Pulse generator
        iDC = 0.5  #Initial duty cycle and frequency
        iFREQ = 440.0
        ph0, ph1 = self.encode_phase_inc(iFREQ)
        iDCenc = self.calc_dc_lim(iFREQ, iDC)
        self.PG_PH = [
        ]  #AXI GPIO handles for phase increments for each channel
        self.PG_AUX = [
        ]  #AXI GPIO handles for duty cycle(ch1) and delay(ch2) of the GPIO block
        self.chfreqs = [440.0, 440.0, 440.0,
                        440.0]  #Initial frequency settings of each channel
        self.chdcs = [0.5, 0.5, 0.5, 0.5]  #Initial duty cycles of each channel
        self.chdelays = [0, 0, 0, 0]  #Initial delays of each channel
        for i in range(4):  #Duty length and delay
            tdc = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tdc.write(ch1_dir, agpo)
            tdc.write(ch1_data, iDCenc)
            tdc.write(ch2_dir, agpo)
            tdc.write(ch2_data, 0x0)
            self.PG_AUX.append(tdc)
            plog.info("DC" + str(i) + " " + hex(axi_base_addr +
                                                (axi_offset * axi_range)))
            axi_offset += 1
            self.chdcs[i] = 0.5
        for i in range(4):  #Phase increments
            tap = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tap.write(ch1_dir, agpo)
            tap.write(ch2_dir, agpo)
            tap.write(ch1_data, ph0)
            tap.write(ch2_data, ph1)
            self.PG_PH.append(tap)
            plog.info("PH" + str(i) + " " + hex(axi_base_addr +
                                                (axi_offset * axi_range)))
            axi_offset += 1
            self.chfreqs[i] = 440.0
        self.PG_UTIL = MMIO(axi_base_addr + (axi_offset * axi_range),
                            0x10000)  #increment load and master reset
        plog.info("PGUTIL: " + hex(axi_base_addr + (axi_offset * axi_range)))
        self.PG_UTIL.write(ch1_dir, agpo)
        self.PG_UTIL.write(ch2_dir, agpo)
        self.PG_UTIL.write(ch1_data, 0x0)  #SEt loader to 0
        self.PG_UTIL.write(ch2_data, 0x0)  #Hold in reset
        #Routine to write initial phase increments
        self.PG_UTIL.write(ch2_data, 0x1)
        self.PG_UTIL.write(ch1_data, 0xF)
        sleep(slt)
        self.PG_UTIL.write(ch1_data, 0x0)
        #Channel enable controller
        #The enable controller is a tristate controlled buffer which when disabling the output places the channels into
        #a high impedance state allowing other devices connected to the same output to assert control (also to prevent the pynq from blowing up if its connected to something that also outputs signals)
        self.T_UTIL.write(ch1_dir, 0x0)
        self.T_UTIL.write(ch1_data, 0xF)  #SEt all channels to high impedance
        axi_offset += 1
        self.pg_ch_stat = 0xF
        #self.PG_UTIL.write(ch2_data,0x0)
        ##Initialize IDELAY
        self.iDD_DATA = [
        ]  #AXI GPIO handles for delay data GPIO blocks (which control tap and stages)
        self.iDD_UTIL = []  #AXI GPIO handles for delay utility (reset)
        for i in range(6):
            tempdel = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            tempdel.write(ch1_data, 0x0)
            tempdel.write(ch2_data, 0x0)
            self.iDD_DATA.append(tempdel)
            axi_offset += 1
        for i in range(6):
            temputil = MMIO(axi_base_addr + (axi_offset * axi_range),
                            axi_range)
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            temputil.write(ch1_data, 0x1)
            temputil.write(ch2_data, 0x1)
            self.iDD_UTIL.append((temputil))
            axi_offset += 1

    ####------------------PHOTON COUNTER---------------------------------------------------####
    def pc_set_window(
            self, window,
            channels):  #Channels is 4 bit integer, window is in seconds
        """Sets the pulse counter counting window period



        Parameters
        ----------
        window : :class:`float`
            Time to count for (in seconds)
        channels : :class:`int`
            Channels to count on (binary encoded)


        """
        m = 0B0001
        wval = int(window * TIMER_CLK)
        if (wval > 0xFFFFFFFF or wval <= 0):
            plog.error(
                "Window must be between 34.35973836s and 0, cannot be 0 seconds"
            )
            return
        for i in range(4):
            if ((0B0001 << i) & channels) != 0:
                self.PC_DAT[i].write(ch2_data, wval)

    def pc_wait_for_rdy(self, channel, mode):
        """Hangs the thread until the counter has data ready to be acquired

        Parameters
        ----------
        channel : :class:`int`
            Channel to wait for
        mode : :class:`int`
            Mode of operation, 0 for fixed window mode, or 1 for external stop trigger mode


        """
        if mode == 0:  #If when the counter stops is defined by time window
            if (self.PC_UTIL[channel].read(ch2_data) == 0):
                while (self.PC_UTIL[channel].read(ch2_data) == 0):
                    pass
            else:
                while (self.PC_UTIL[channel].read(ch2_data) == 1):
                    pass
        else:  #If when the counter stops is defined by an external stop signal
            if (self.T_RDY_UTIL.read(ch1_data) == 0):
                while (self.T_RDY_UTIL.read(ch1_data) == 0):
                    pass

    def pc_ex_triggered(self, window):
        """Start counting function for externally supplied start signal

        Parameters
        ----------
        window : :class:`int`
            Counting window (in seconds)

        Returns
        -------
        :class:`list` of `int`
            List of counts for each channel

        """
        #Set the window of all channels to specified window value and start the counter
        self.pc_set_window(window, 0xF)
        self.T_UTIL.write(
            ch2_data, 0x1
        )  #Set the external trigger block to activate the counter once trigger pulse occurs
        #Wait till the counter finishes counting
        self.pc_wait_for_rdy(0, 0)
        retval = []
        for i in range(4):
            retval.append(self.pc_read_counts(
                i))  #Append each channels counts to output array
        self.T_UTIL.write(ch2_data, 0x0)
        return retval

    def pc_ex_trig_stop(self):
        """Enables and waits for the pulse counter to stop counting (based off when the stop signal is pulsed) and returns the counts for each channel.

        Returns
        -------
        :class:`list` of `int`
            Array of counts for each channel
        """
        # Set the trigger controller to start the counter when the start trigger is acquired
        # and stop the counter when the stop signal is acquired

        self.T_UTIL.write(ch2_data, 0x3)
        #Set the window for all channels to maximum (as window is unknown in this mode and externally defined)
        for i in range(4):
            self.PC_DAT[i].write(ch2_data, 0xFFFFFFFF)
        #Wait until the stop trigger is acquired
        self.pc_wait_for_rdy(0, 1)
        retval = []
        #Read, store and return all count values as an array
        for i in range(4):
            retval.append(self.pc_read_counts(i))
        self.T_UTIL.write(ch2_data, 0x0)
        return retval

    def pc_enable_channels(self, channels):  #channels a 4 bit integer
        """Enable counting on supplied channels

        Parameters
        ----------
        channels : :class:`int`
            Channels to enable counting on (binary encoded)


        """
        #Enable any channel that is indicated by a 1 in the 4 bit integer
        for i in range(4):
            if ((0B0001 << i) & channels) != 0:
                self.PC_UTIL[i].write(ch1_data, 0x1)

    def pc_disable_channels(self, channels):  #Channels a 4 bit integer
        """Disable counting on supplied channels

        Parameters
        ----------
        channels : :class:`int`
            Channels to disable counting on (binary encoded)



        """
        #Disable any channel that is indicated by a 1 in the 4 bit integer
        for i in range(4):
            if ((0B0001 << i) & channels) != 0:
                self.PC_UTIL[i].write(ch1_data, 0x0)

    def pc_read_counts(self, channel):
        """Read counts on channel specified

        Parameters
        ----------
        channel : :class:`int`
            Channel to read counts of (0-3)

        Returns
        -------
        :class:`int`
            Number of counts

        """
        return self.PC_DAT[channel].read(ch1_data)

    ####----------------------------------------------------------------------------------####
    ####------------------Single line inter-rising_edge timer-----------------------------####
    def st_arm_and_wait(self):
        """Arm single channel inter-rising_edge timer and hang until time data is ready to be acquired

        Returns
        -------
        :class:`float`
            Time between detected rising edges (in seconds)
        """
        self.ST_UTIL.write(ch1_data, 0x1)  #Enable
        while (self.ST_DATA.read(ch2_data) & 0b1) == 0:  #Wait for ready
            pass
        op = self.ST_DATA.read(ch1_data) / REF_CLK  #Read time
        dels = self.ST_DATA.read(
            ch2_data)  #Read start and finish delay line values
        #Count the number of ones in both start and finish delay line states, multiply with the delay resolution and add start delay value and subtract stop delay value
        #to the coarse time
        op = op + (self.uencode((dels & 0b111111110) >> 1, 8) - self.uencode(
            (dels & 0b11111111000000000) >> 9, 8)) * FTIME
        self.ST_UTIL.write(ch1_data, 0x0)
        return op

    ####----------------------------------------------------------------------------------####
    ####------------------Two channel photon coincidence timer----------------------------####
    def ct_arm_and_wait(self, first):
        """Arm two channel rising edge coincidence timer and hang until time data is ready (On channel 0 and 1)

        Parameters
        ----------
        first : :class:`int`
            Defines which channel to listen for start rising edge (0 or 1)

        Returns
        -------
        :class:`float`
            Time between rising edges (in seconds)

        """
        #Set which channel the hardware is listening to for the start pulse and take the submodule out of reset enabling it
        self.CT_UTIL.write(ch2_data, first)
        self.CT_UTIL.write(ch1_data, 0x1)
        #Wait for the coincidence time to be ready (waits until the second pulse)
        while (self.CT_DATA.read(ch2_data) & 0b1) == 0:
            pass
        #Read coarse time
        tm = self.CT_DATA.read(ch1_data) / REF_CLK
        dels = self.CT_DATA.read(
            ch2_data
        )  #Read delay line states including the data ready bit which must be shifted out below
        #Include fine time offsets with the coarse time
        tm = tm + (self.uencode((dels & 0b111111110) >> 1, 8) - self.uencode(
            (dels & 0b11111111000000000) >> 9, 8)) * FTIME
        self.CT_UTIL.write(
            ch1_data, 0x0)  #Disable coincidence timer by placing it in reset
        return tm

    ####---------------------Signal generator---------------------------------------------####

    def pg_disable(self):
        """Disable signal generator, holds the submodule in reset bringing all outputs low


        """
        self.PG_UTIL.write(ch2_data, 0x0)

    def pg_enable(self):
        """Enables the signal generator, takes hardware submodule out of reset


        """
        self.PG_UTIL.write(ch2_data, 0x1)

    def pg_enable_channel(self, channel):
        """Enable specified channel, takes channel out of tristate high Z mode

        Parameters
        ----------
        channel : :class:`int`
            Channel to enable (0-3)



        """
        #As the enable lines are active low, must set the channel specified's place from a 1 to a 0.
        self.pg_ch_stat = ~(~self.pg_ch_stat | (0B0001 << channel))
        self.T_UTIL.write(ch1_data, self.pg_ch_stat)

    def pg_disable_channel(self, channel):
        """Disable specified channel, places channel into tristate high Z mode

        Parameters
        ----------
        channel : :class:`int`
            Channel to disable (0-3)



        """
        self.pg_ch_stat = self.pg_ch_stat | (0b0001 << channel)
        self.T_UTIL.write(ch1_data, self.pg_ch_stat)

    def pg_set_channel_freq(self, channel, freq):
        """Sets the frequency of the specified channel

        Parameters
        ----------
        channel : :class:`int`
            Channel to set frequency of (0-3)
        freq : :class:`float`
            Frequency to set channel to (in Hz)


        """
        nenc = self.encode_phase_inc(
            2 * freq
        )  #Calculate the phase increment value required by the DDS Compiler
        self.PG_PH[channel].write(
            ch1_data,
            nenc[0])  #Write LSB(31 downto 0) of total 48 bits to the DDS
        self.PG_PH[channel].write(
            ch2_data, nenc[1])  #Write MSB(47 downto 32) of 48 bits to the DDS
        self.PG_UTIL.write(
            ch1_data,
            0xF)  #Enable loading of phase increments to the DDS Compiler
        sleep(slt)
        self.PG_UTIL.write(ch1_data, 0x0)
        #Calculate duty cycle counter limit
        newdc = self.calc_dc_lim(freq, self.chdcs[channel])
        self.PG_UTIL.write(ch2_data, 0x0)  #Disable signal generator
        #Write new settings to the hardware
        self.PG_AUX[channel].write(ch1_data, newdc)
        self.PG_AUX[channel].write(ch2_data,
                                   self.calc_delay(self.chdelays[channel]))
        self.PG_UTIL.write(ch2_data, 0x1)  #Re-enable signal generator
        self.chfreqs[
            channel] = freq  #Synchronzie the host setting of the frequency to the frequency setting on the hardware

    def pg_set_dc(self, channel, dc):  #Dc from 0 to 1
        """Sets the duty cycle of the specified channel

        Parameters
        ----------
        channel : :class:`int`
            Channel to set the duty cycle of (0-3)
        dc : :class:`float`
            Duty cycle to set the specified channel to (0-1)



        """
        #Calculate the duty cycle counter limit from new duty cycle value
        dcenc = self.calc_dc_lim(self.chfreqs[channel], dc)
        self.PG_UTIL.write(ch2_data, 0x0)  #dsaible signal generator
        self.PG_AUX[channel].write(ch1_data,
                                   dcenc)  #WRite new duty cycle counter value
        self.PG_UTIL.write(ch2_data, 0x1)  #Re-enable
        self.chdcs[
            channel] = dc  #Sync the host setting of the duty cycle to the duty cycyel setting on hardware

    def pg_set_pw(self, channel, pw):
        """Sets the pulse width of the channel specified

        Parameters
        ----------
        channel : :class:`int`
            Channel to set pulse width of (0-3)
        pw : :class:`float`
            Pulse width to set channel to (in milliseconds)



        """
        pwv = self.calc_delay(
            pw / 1000)  #Calculating duty cycle counter value from time
        self.PG_UTIL.write(ch2_data, 0x0)  #Disable signal generator
        self.PG_AUX[channel].write(
            ch1_data,
            pwv)  #Write the new duty cycle counter value to the hardware
        self.PG_UTIL.write(ch2_data, 0x1)  #Re-enable signal generator
        #Calculate what the new duty cycle of the signal is in 0-1 rather than pulse width and save that as the host setting
        tlim = REF_CLK / self.chfreqs[channel]
        self.chdcs[channel] = pwv / tlim

    def pg_set_delay(self, channel, delay):  #Delay in seconds
        """Sets the delay of the specified channel

        Parameters
        ----------
        channel : :class:`int`
            Channel to set delay of (0-3)
        delay : :class:`float`
            The delay the specified channel is to be set to(in seconds)



        """
        delv = self.calc_delay(
            delay
        )  #Calculate the counter value the delay counter must count upto before enabling the channel
        self.PG_UTIL.write(
            ch2_data, 0x0
        )  #Disable the signal generator, write the delay value to the delay controller
        self.PG_AUX[channel].write(ch2_data, delv)
        self.chdelays[channel] = delay  #Save the delay setting
        self.PG_UTIL.write(ch2_data, 0x1)  #Restart the signal generator

    def encode_phase_inc(self, freq):
        """Converts a supplied frequency to a phase increment amount that is supplied to the DDS modules to produce the necessary sine wave.
        Internally used function, should not be called directly.

        Parameters
        ----------
        freq : :class:`float`
            Frequency in Hz

        Returns
        -------
        :class:`list` of :class:`float`
            48 bit phase increment, first element is 32 bit LSB, second element is 16 bit MSB
        :class:`float`
            is 32 bit LSB
        :class:`float`
            is 16 bit MSB

        """
        enc = int(
            (freq * 2**PHASE_BIT_DEPTH) / REF_CLK
        )  #Calculate the phase increment of the DDS to produce the required frequency
        #Split the 48 bit number into 32 and 16 bits
        lsb = enc & 0xFFFFFFFF
        msb = (enc >> 32) & 0xFFFF
        return [lsb, msb]

    def calc_dc_lim(self, freq, dc):  #dc from 0 to 1
        """Calculates the count value of the hardware counter where the output changes from high to low after this count value is passed by the hardware counter

        Parameters
        ----------
        freq : :class:`float`
            Frequency of the signal currently being emitted.
        dc : :class:`float`
            Duty cycle value (0-1)

        Returns
        -------
        :class:`int`
            Count value the hardware counter counts up to before switching the output signal from high to low.

        """
        dc_t = int(REF_CLK / freq)
        return int(dc_t * dc)

    def calc_delay(self, delay):
        """Calculates the delay timer count value from a time in seconds

        Parameters
        ----------
        delay : :class:`float`
            Delay time in seconds

        Returns
        -------
        :class:`int`
            Count limit for delay timer

        """
        return int(delay * REF_CLK)

    def TT_wait_for_rdy(self):
        """Wait until time tagger tags each channel or times out (Hangs the thread)



        """
        if (self.TT_UTIL.read(ch2_data) & 0b1) == 0:
            while (self.TT_UTIL.read(ch2_data) & 0b1) == 0:
                pass
        else:
            while (self.TT_UTIL.read(ch2_data) & 0b1) == 1:
                pass

    def TT_set_timeout(self, timeval):
        """Set the time out of the time tagger

        Parameters
        ----------
        timeval : :class:`float`
            Time out in seconds


        """
        tcount = timeval * REF_CLK  #Calculate time out counter value
        self.TT_CONFIG.write(
            ch1_data,
            int(tcount))  #Write the new counter value to the time tagger

    def TT_activate(self, time):
        """Sets the time out of the time tagger and pulls the time tagger out of reset, activating it

        Parameters
        ----------
        time : :class:`float`
            Time out in seconds



        """
        self.TT_set_timeout(time)
        self.TT_UTIL.write(ch1_data, 0x1)

    def TT_proc(self):
        """Time tagger sampling process, waits until time tagger has data ready, then calculates time intervals for each channel from T0 and includes fine times and returns a time interval for each channel and which channels timed out.

        Returns
        -------
        :class:`dict`
            A dictionary containing time intervals ('T1'...'T4') and boolean time outs ('T1s'...'T4s')

        """
        self.TT_wait_for_rdy(
        )  #Wait until the time tagger has finished tagging or has timed out
        stimet0 = self.uencode(
            self.TT_DELAY_DATA.read(ch2_data),
            8) * FTIME  #Calculate the fine time offset of the t0 signal
        dels = self.TT_DELAY_DATA.read(
            ch1_data
        )  #Delay line states for channels 0-3 (Each is concatenated in binary)
        #Calculating the fine time offsets for each channel
        stimet1 = self.uencode((dels & 0xFF), 8) * FTIME
        stimet2 = self.uencode((dels & 0xFF00) >> 8, 8) * FTIME
        stimet3 = self.uencode((dels & 0xFF0000) >> 16, 8) * FTIME
        stimet4 = self.uencode((dels & 0xFF000000) >> 24, 8) * FTIME
        #Include fine time offsets with the coarse times
        ctime1 = self.TT_DATA0.read(ch1_data) / REF_CLK - stimet1 + stimet0
        ctime2 = self.TT_DATA0.read(ch2_data) / REF_CLK - stimet2 + stimet0
        ctime3 = self.TT_DATA1.read(ch1_data) / REF_CLK - stimet3 + stimet0
        ctime4 = self.TT_DATA1.read(ch2_data) / REF_CLK - stimet4 + stimet0
        timeouts = (self.TT_UTIL.read(ch2_data) & 0b11110
                    ) >> 1  #Read time outs and shift out the data ready line
        #Store all information in dictionary and return it
        outdict = {
            "T1": ctime1,
            "T2": ctime2,
            "T3": ctime3,
            "T4": ctime4,
            "T1s": timeouts & 0b1,
            "T2s": (timeouts & 0b10) >> 1,
            "T3s": (timeouts & 0b100) >> 2,
            "T4s": (timeouts & 0b1000) >> 3
        }
        return outdict

    def TT_reset(self):
        """Puts time tagger into reset, stopping it


        """
        self.TT_UTIL.write(ch1_data, 0x0)

    def DD_idelay(self, channel, tap, stage):
        """Sets the input delay of the specified channel by configuring the delay line taps and the number of delay line stages to include

        Parameters
        ----------
        channel : :class:`int`
            Channel to delay (0-3)
        tap : :class:`int`
            Delay line tap (0-31)
        stage : :class:`int`
            Number of delay line stages (0-7)


        """
        plog.info("Setting input delay on channel " + str(channel) +
                  " dline tap of " + str(tap) + " with " + str(stage) +
                  " stage(s).")
        self.iDD_UTIL[channel].write(ch1_data,
                                     0x0)  #Reset and unreset the delay block
        sleep(slt)
        self.iDD_UTIL[channel].write(ch1_data, 0x1)
        self.iDD_DATA[channel].write(
            ch1_data, tap)  #Load the delay line tap for the top stage
        self.iDD_DATA[channel].write(
            ch2_data,
            stage)  #Select how many stages are activated below the top stage

    def uencode(self, val, length):
        """Calculates the number of binary ones in an integer of specified length

        Parameters
        ----------
        val : :class:`int`
            Arbitrary integer to get the number of binary ones from
        length : :class:`int`
            Length of the binary integer to include when counting up the ones.

        Returns
        -------
        :class:`int`
            The total number of ones within the binary length specified in the specified integer

        """
        cnt = 0
        for i in range(
                length
        ):  #Just counts how many ones in binary there are in the range specified by length
            if ((val >> i) & 0b1 == 1):
                cnt += 1
        return cnt
class _PSTraceAnalyzer:
    """Class for the Trace Analyzer controlled by PS.

    A typical use of this class is on the base overlay.

    This class can capture digital IO patterns / stimulus on all the pins.
    There can by multiple such instances on the defined overlay.

    Attributes
    ----------
    trace_control : MMIO
        The trace controller associated with the analyzer.
    dma : DMA
        The PS controlled DMA object associated with the analyzer.
    intf_spec : dict
        The interface specification, e.g., PYNQZ1_PMODA_SPECIFICATION.
    num_analyzer_samples : int
        The number of samples to be analyzed.
    samples : numpy.ndarray
        The raw data samples expressed in numpy array.
    frequency_mhz: float
        The frequency of the trace analyzer, in MHz.
    clk : Clocks
        The clock management unit for the trace analyzer.
    xlnk : Xlnk
        The Xlnk object to control contiguous memory.

    """
    def __init__(self, ip_info, intf_spec_name):
        """Return a new PS controlled trace analyzer object. 

        The maximum sample rate is 100MHz. Usually the sample rate is set
        to no larger than 10MHz in order for the signals to be captured
        on pins / wires.

        For Pmod header, pin numbers 0-7 correspond to the pins on the
        Pmod interface.

        For Arduino header, pin numbers 0-13 correspond to D0-D13;
        pin numbers 14-19 correspond to A0-A5;
        pin numbers 20-21 correspond to SDA and SCL.

        Parameters
        ----------
        ip_info : dict
            The dictionary containing the IP associated with the analyzer.
        intf_spec_name : str/dict
            The name of the interface specification.

        """
        if type(intf_spec_name) is str:
            self.intf_spec = eval(intf_spec_name)
        elif type(intf_spec_name) is dict:
            self.intf_spec = intf_spec_name
        else:
            raise ValueError("Interface specification has to be str or dict.")

        trace_cntrl_info = ip_info['trace_cntrl_{}_0'.format(
            self.intf_spec['monitor_width'])]
        trace_dma_info = ip_info['axi_dma_0']
        self.trace_control = MMIO(trace_cntrl_info['phys_addr'],
                                  trace_cntrl_info['addr_range'])
        self.dma = DMA(trace_dma_info)
        self.num_analyzer_samples = 0
        self.samples = None
        self._cma_array = None
        self.frequency_mhz = 0
        self.clk = Clocks
        self.xlnk = Xlnk()
        self._status = 'RESET'

    def __repr__(self):
        """Disambiguation of the object.

        Users can call `repr(object_name)` to display the object information.

        """
        parameter_list = list()
        parameter_list.append('num_analyzer_samples={}'.format(
            self.num_analyzer_samples))
        parameter_list.append('frequency_mhz={}'.format(self.frequency_mhz))
        parameter_string = ", ".join(map(str, parameter_list))
        return '{}({})'.format(self.__class__.__name__, parameter_string)

    @property
    def status(self):
        """Return the analyzer's status.

        Returns
        -------
        str
            Indicating the current status of the analyzer; can be 
            'RESET', 'READY', or 'RUNNING'.

        """
        return self._status

    def setup(self,
              num_analyzer_samples=DEFAULT_NUM_TRACE_SAMPLES,
              frequency_mhz=DEFAULT_CLOCK_FREQUENCY_MHZ,
              fclk_index=3):
        """Configure the trace analyzer.

        This method prepares the trace analyzer by sending configuration 
        parameters to the Microblaze.

        Note that the analyzer is always attached to the pins, so there
        is no need to use any method like 'connect()'. In short, once the 
        analyzer has been setup, it is connected as well.

        FCLK3 will be configured during this method.

        Note
        ----
        The first sample captured is a dummy sample (for both pattern 
        generator and FSM generator), therefore we have to allocate a buffer 
        one sample larger.

        Parameters
        ----------
        num_analyzer_samples : int
            The number of samples to be analyzed.
        frequency_mhz: float
            The frequency of the captured samples, in MHz.
        fclk_index : int
            The index of the fclk controlled by clock management object.

        """
        if not 1 <= num_analyzer_samples <= MAX_NUM_TRACE_SAMPLES:
            raise ValueError('Number of samples should be in '
                             '[1, {}]'.format(MAX_NUM_TRACE_SAMPLES))
        self.num_analyzer_samples = num_analyzer_samples

        if not MIN_CLOCK_FREQUENCY_MHZ <= frequency_mhz <= \
                MAX_CLOCK_FREQUENCY_MHZ:
            raise ValueError("Clock frequency out of range "
                             "[{}, {}]".format(MIN_CLOCK_FREQUENCY_MHZ,
                                               MAX_CLOCK_FREQUENCY_MHZ))
        setattr(self.clk, "fclk{}_mhz".format(fclk_index), frequency_mhz)
        self.frequency_mhz = frequency_mhz

        trace_byte_width = round(self.intf_spec['monitor_width'] / 8)
        self._cma_array = self.xlnk.cma_array(
            [1, self.num_analyzer_samples],
            dtype=BYTE_WIDTH_TO_NPTYPE[trace_byte_width])
        self._status = 'READY'

    def reset(self):
        """Reset the trace analyzer.

        This method will bring the trace analyzer from any state to 
        'RESET' state.

        """
        if self._status == 'RUNNING':
            self.stop()

        self.samples = None
        self.num_analyzer_samples = 0
        self.frequency_mhz = 0
        if self._cma_array is not None:
            self._cma_array.close()
        self._status = 'RESET'

    def run(self):
        """Start the DMA to capture the traces.

        Return
        ------
        None

        """
        self.dma.recvchannel.transfer(self._cma_array)
        if self.intf_spec['monitor_width'] == 32:
            self.trace_control.write(TRACE_CNTRL_32_LENGTH,
                                     self.num_analyzer_samples)
            self.trace_control.write(TRACE_CNTRL_32_DATA_COMPARE, 0)
            self.trace_control.write(TRACE_CNTRL_32_ADDR_AP_CTRL, 1)
            self.trace_control.write(TRACE_CNTRL_32_ADDR_AP_CTRL, 0)
        else:
            self.trace_control.write(TRACE_CNTRL_64_LENGTH,
                                     self.num_analyzer_samples)
            self.trace_control.write(TRACE_CNTRL_64_DATA_COMPARE_MSW, 0)
            self.trace_control.write(TRACE_CNTRL_64_DATA_COMPARE_LSW, 0)
            self.trace_control.write(TRACE_CNTRL_64_ADDR_AP_CTRL, 1)
            self.trace_control.write(TRACE_CNTRL_64_ADDR_AP_CTRL, 0)

        self._status = 'RUNNING'

    def stop(self):
        """Stop the DMA after capture is done.

        Return
        ------
        None

        """
        self.dma.recvchannel.wait()
        self._status = 'READY'

    def __del__(self):
        """Destructor for trace buffer object.

        Returns
        -------
        None

        """
        if self._cma_array is not None:
            self._cma_array.close()

    def analyze(self, steps):
        """Analyze the captured pattern.

        This function will process the captured pattern and put the pattern
        into a Wavedrom compatible format.

        The data output is of format:

        [{'name': '', 'pin': 'D1', 'wave': '1...0.....'},
         {'name': '', 'pin': 'D2', 'wave': '0.1..01.01'}]

        Note the all the lanes should have the same number of samples.
        All the pins are assumed to be tri-stated and traceable.

        Currently only no `step()` method is supported for PS controlled 
        trace analyzer.

        Parameters
        ----------
        steps : int
            Number of samples to analyze. A value 0 means to analyze all the
            valid samples.

        Returns
        -------
        list
            A list of dictionaries, each dictionary consisting the pin number,
            and the waveform pattern in string format.

        """
        io_pins = get_tri_state_pins(self.intf_spec['traceable_io_pins'],
                                     self.intf_spec['traceable_tri_states'])

        if steps == 0:
            num_valid_samples = self.num_analyzer_samples
        else:
            num_valid_samples = steps

        trace_byte_width = round(self.intf_spec['monitor_width'] / 8)
        data_type = '>i{}'.format(trace_byte_width)
        self.samples = np.zeros(num_valid_samples, dtype=data_type)
        np.copyto(self.samples, self._cma_array)
        temp_bytes = np.frombuffer(self.samples, dtype=np.uint8)
        bit_array = np.unpackbits(temp_bytes)
        temp_lanes = bit_array.reshape(num_valid_samples,
                                       self.intf_spec['monitor_width']).T[::-1]

        wavelanes = list()
        for pin_label in io_pins:
            temp_lane = temp_lanes[self.intf_spec['traceable_io_pins']
                                   [pin_label]]
            bitstring = ''.join(temp_lane.astype(str).tolist())
            wave = bitstring_to_wave(bitstring)
            wavelanes.append({'name': '', 'pin': pin_label, 'wave': wave})

        return wavelanes
Beispiel #27
0
    def __init__(self):
        """Initializes the hardware by first loading and configuring the FPGA with the hardware design and then by creating handles for each AXI GPIO block that allows connection from the processing system to the FPGA fabric.

        """
        #Import FPGA configuration file and download
        self.OV = Overlay("Single_Photons/SP_OVERLAY.bit", 0)
        self.OV.download()
        ##Initialize pulse counter
        axi_offset = 0
        #Initialize data channels
        self.PC_DAT = []  #Holds all the handles for the data GPIO blocks
        #Initialize AXI GPIO modules
        for i in range(4):
            self.PC_DAT.append(
                MMIO(axi_base_addr + (axi_offset * axi_range), axi_range))
            self.PC_DAT[i].write(ch1_dir, agpi)  #ch1 is counts
            self.PC_DAT[i].write(ch2_dir, agpo)  #Ch2 is window
            self.PC_DAT[i].write(ch2_data, 0xFFFFFFFF)
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            axi_offset += 1

        #Initialize utility channels
        self.PC_UTIL = []  #Utility GPIO modules (containing reset signal and
        for i in range(4):
            self.PC_UTIL.append(
                MMIO(axi_base_addr + ((axi_offset) * axi_range), axi_range))
            self.PC_UTIL[i].write(ch1_dir, agpo)  #Reset
            self.PC_UTIL[i].write(ch1_data, 0x0)  #Hold in reset
            self.PC_UTIL[i].write(ch2_dir, agpi)  #Ready
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            axi_offset += 1
        #Initialize trigger controller
        self.T_UTIL = MMIO(0x41200000, 0x10000)
        self.T_UTIL.write(ch2_dir, 0x0)
        self.T_UTIL.write(ch2_data, 0x0)
        self.T_RDY_UTIL = MMIO(0x41210000, 0x10000)
        self.T_RDY_UTIL.write(ch1_dir, 0x1)
        ##Initialize single channel inter-rising_edge detection
        self.ST_DATA = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.ST_UTIL = MMIO(axi_base_addr + (axi_offset) * axi_range,
                            axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        ##Initialize interchannel coincidence timer
        self.CT_DATA = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.CT_UTIL = MMIO(axi_base_addr + (axi_offset) * axi_range,
                            axi_range)
        plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        ##Initialize time tagger
        self.TT_CONFIG = MMIO(axi_base_addr + (axi_offset * axi_range),
                              axi_range)
        plog.info("TT_CONFIG: " + hex(axi_base_addr +
                                      (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_DATA0 = MMIO(axi_base_addr + (axi_offset * axi_range),
                             axi_range)
        plog.info("TT_DATA0: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_DATA1 = MMIO(axi_base_addr + (axi_offset * axi_range),
                             axi_range)
        plog.info("TT_DATA1: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_DELAY_DATA = MMIO(axi_base_addr + (axi_offset * axi_range),
                                  axi_range)
        plog.info("TT_DELAY: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        self.TT_UTIL = MMIO(axi_base_addr + (axi_offset * axi_range),
                            axi_range)
        plog.info("TT_UTIL: " + hex(axi_base_addr + (axi_offset * axi_range)))
        axi_offset += 1
        ##Initialize Pulse generator
        iDC = 0.5  #Initial duty cycle and frequency
        iFREQ = 440.0
        ph0, ph1 = self.encode_phase_inc(iFREQ)
        iDCenc = self.calc_dc_lim(iFREQ, iDC)
        self.PG_PH = [
        ]  #AXI GPIO handles for phase increments for each channel
        self.PG_AUX = [
        ]  #AXI GPIO handles for duty cycle(ch1) and delay(ch2) of the GPIO block
        self.chfreqs = [440.0, 440.0, 440.0,
                        440.0]  #Initial frequency settings of each channel
        self.chdcs = [0.5, 0.5, 0.5, 0.5]  #Initial duty cycles of each channel
        self.chdelays = [0, 0, 0, 0]  #Initial delays of each channel
        for i in range(4):  #Duty length and delay
            tdc = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tdc.write(ch1_dir, agpo)
            tdc.write(ch1_data, iDCenc)
            tdc.write(ch2_dir, agpo)
            tdc.write(ch2_data, 0x0)
            self.PG_AUX.append(tdc)
            plog.info("DC" + str(i) + " " + hex(axi_base_addr +
                                                (axi_offset * axi_range)))
            axi_offset += 1
            self.chdcs[i] = 0.5
        for i in range(4):  #Phase increments
            tap = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            tap.write(ch1_dir, agpo)
            tap.write(ch2_dir, agpo)
            tap.write(ch1_data, ph0)
            tap.write(ch2_data, ph1)
            self.PG_PH.append(tap)
            plog.info("PH" + str(i) + " " + hex(axi_base_addr +
                                                (axi_offset * axi_range)))
            axi_offset += 1
            self.chfreqs[i] = 440.0
        self.PG_UTIL = MMIO(axi_base_addr + (axi_offset * axi_range),
                            0x10000)  #increment load and master reset
        plog.info("PGUTIL: " + hex(axi_base_addr + (axi_offset * axi_range)))
        self.PG_UTIL.write(ch1_dir, agpo)
        self.PG_UTIL.write(ch2_dir, agpo)
        self.PG_UTIL.write(ch1_data, 0x0)  #SEt loader to 0
        self.PG_UTIL.write(ch2_data, 0x0)  #Hold in reset
        #Routine to write initial phase increments
        self.PG_UTIL.write(ch2_data, 0x1)
        self.PG_UTIL.write(ch1_data, 0xF)
        sleep(slt)
        self.PG_UTIL.write(ch1_data, 0x0)
        #Channel enable controller
        #The enable controller is a tristate controlled buffer which when disabling the output places the channels into
        #a high impedance state allowing other devices connected to the same output to assert control (also to prevent the pynq from blowing up if its connected to something that also outputs signals)
        self.T_UTIL.write(ch1_dir, 0x0)
        self.T_UTIL.write(ch1_data, 0xF)  #SEt all channels to high impedance
        axi_offset += 1
        self.pg_ch_stat = 0xF
        #self.PG_UTIL.write(ch2_data,0x0)
        ##Initialize IDELAY
        self.iDD_DATA = [
        ]  #AXI GPIO handles for delay data GPIO blocks (which control tap and stages)
        self.iDD_UTIL = []  #AXI GPIO handles for delay utility (reset)
        for i in range(6):
            tempdel = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            tempdel.write(ch1_data, 0x0)
            tempdel.write(ch2_data, 0x0)
            self.iDD_DATA.append(tempdel)
            axi_offset += 1
        for i in range(6):
            temputil = MMIO(axi_base_addr + (axi_offset * axi_range),
                            axi_range)
            plog.info(hex(axi_base_addr + (axi_offset * axi_range)))
            temputil.write(ch1_data, 0x1)
            temputil.write(ch2_data, 0x1)
            self.iDD_UTIL.append((temputil))
            axi_offset += 1
input_fmt.fmt.pix.bytesperline = input_fmt.fmt.pix.width 
fcntl.ioctl(video_dev, VIDIOC_S_FMT, input_fmt)  

# Sub-device format setting IOCTL
sub_dev_obj = V4l2(1)
sub_dev_obj.SetSubDeviceFormat(args.width,args.height,sub_dev)                            #programming format of the sub device using c library

#Request buffer IOCTL call
req_buffer = v4l2_requestbuffers()
req_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE
req_buffer.memory = V4L2_MEMORY_USERPTR
req_buffer.count = args.numBuff                                                           #number of buffer 
fcntl.ioctl(video_dev, VIDIOC_REQBUFS, req_buffer)                                        # tell the driver that we want some buffers 
#Read_Data("REQBUF")                                                                      #to check VDMA registeres after request buffer

vdma.write(0x34,0xffffffff)    

#Allocating input buffer using xlnk
vir_addr_list  = []
in_data_arr = []
in_phy_arr  = []
def CreateInCma():
    for ind in range(req_buffer.count):
        in_cma = xlnk.cma_array(shape=(input_fmt.fmt.pix.sizeimage,), dtype=np.uint8)
        if in_cma.size ==0:
            return False
        in_data_arr.append(in_cma)
        in_phy_arr.append(in_cma.physical_address)
        cma_addr = in_data_arr[ind].__array_interface__['data']
        vir_addr_list.append(cma_addr[0])
Beispiel #29
0
    def publish_mmio(self, size, count, pl_mac_address, pl_ip_address,
                     server_ip_address, server_port_number,
                     topic_id, qos, verbose, net_iop, sensor_iop):
        """Publish data from the given temperature sensor to an MQTTSN server.

        This method will use the MMIO to control the accelerator.

        Parameters
        ----------
        size : int
            The size of frames to generate.
        count : int
            The number of publish events to complete.
        pl_mac_address : int/str
            The MAC Address of the PL accelerator (not the host MAC address).
        pl_ip_address : int/str
            The IP Address of the PL accelerator (not the host IP address).
        server_ip_address : int/str
            The IP Address of the MQTTSN server.
        server_port_number : int
            The port number of the MQTTSN server.
        topic_id : int
            The topic ID to publish on.
        qos : int
            The MQTTSN qos to use (0 means response is not required).
        verbose : int
            A non-zero value will get verbose debugging information.
        net_iop : NetworkIOP
            The network IOP object.
        sensor_iop : Pmod_TMP2
            The temperature sensor object.

        """
        pl_ip = pl_ip_address if type(pl_ip_address) is int \
            else ip_str_to_int(pl_ip_address)
        pl_mac = pl_mac_address if type(pl_mac_address) is int \
            else mac_str_to_int(pl_mac_address)
        server_ip = server_ip_address if type(server_ip_address) is int \
            else ip_str_to_int(server_ip_address)

        _ = self.map(net_iop.mmio)
        net_iop_phys = net_iop.mmio.base_addr + net_iop.mmio.virt_offset
        _ = self.map(sensor_iop.mmio)

        acc_mmio = MMIO(0x83c00000, 0x10000)
        acc_mmio.write(0x10, 1)
        acc_mmio.write(0x18, pl_mac & 0xFFFFFFFF)
        acc_mmio.write(0x1c, pl_mac >> 32)
        acc_mmio.write(0x24, pl_ip)
        acc_mmio.write(0x2c, 1)
        acc_mmio.write(0x34, server_ip)
        acc_mmio.write(0x3c, server_port_number)
        acc_mmio.write(0x44, topic_id)
        acc_mmio.write(0x4c, qos)
        acc_mmio.write(0x54, 0x0)
        acc_mmio.write(0x5c, 1)
        acc_mmio.write(0x64, net_iop_phys)
        acc_mmio.write(0x6c, count)
        acc_mmio.write(0x74, size)
        acc_mmio.write(0x7c, 1)
        acc_mmio.write(0x84, verbose)  # verbose

        # execute the accelerator once to reset things
        acc_mmio.write(0x0, 1)
        status = acc_mmio.read(0x0)
        while status & 0x2 == 0:
            status = acc_mmio.read(0x0)

        # deassert reset
        acc_mmio.write(0x7c, 0)  # reset

        # wait for the events to complete
        events_completed = 0
        i = 0
        while events_completed < count:
            status = acc_mmio.read(0x0)
            while status & 0x4 == 0:
                status = acc_mmio.read(0x0)
            # set our inputs and start
            acc_mmio.write(0x2c, i)
            # valid message
            acc_mmio.write(0x5c, i % 2)
            # start
            acc_mmio.write(0x0, 1)
            i = i + 1
            events_completed = acc_mmio.read(0x8c)
            if i % 1000 == 0:
                print("status", status)
                print("events_completed:", events_completed)
                print("PublishesSent:", acc_mmio.read(0x94))

        print("calls", i)
        print("events_completed:", events_completed)
        print("PublishesSent:", acc_mmio.read(0x94))
        print("PacketsReceived:", acc_mmio.read(0x9c))
        print("PacketsSent:", acc_mmio.read(0xa4))
Beispiel #30
0
 def __init__(self):
     self.OV = Overlay("Single_Photons/SP_OVERLAY.bit", 0)
     self.OV.download()
     ##Initialize pulse counter
     axi_offset = 0
     #Initialize data channels
     self.PC_DAT = []
     global axi_range
     for i in range(4):
         self.PC_DAT.append(MMIO(axi_base_addr + (i * axi_range),
                                 axi_range))
         self.PC_DAT[i].write(ch1_dir, agpi)  #ch1 is counts
         self.PC_DAT[i].write(ch2_dir, agpo)  #Ch2 is window
         self.PC_DAT[i].write(ch2_data, 0xFFFFFFFF)
     #Initialize utility channels
     axi_offset = 4
     self.PC_UTIL = []
     for i in range(4):
         self.PC_UTIL.append(
             MMIO(axi_base_addr + ((i + axi_offset) * axi_range),
                  axi_range))
         self.PC_UTIL[i].write(ch1_dir, agpo)  #Reset
         self.PC_UTIL[i].write(ch1_data, 0x0)  #Hold in reset
         self.PC_UTIL[i].write(ch2_dir, agpi)  #Ready
     #Initialize trigger controller
     self.T_UTIL = MMIO(0x41200000, 0x10000)
     self.T_UTIL.write(ch2_dir, 0x0)
     self.T_UTIL.write(ch2_data, 0x0)
     self.T_RDY_UTIL = MMIO(0x41210000, 0x10000)
     self.T_RDY_UTIL.write(ch1_dir, 0x1)
     ##Initialize single channel inter-rising_edge detection
     axi_offset = 8
     self.ST_DAT = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
     self.ST_DAT.write(ch1_dir, agpi)
     self.ST_DAT.write(ch2_dir, agpo)
     self.ST_DAT.write(ch2_data, 0x0)  #Hold in reset
     self.ST_RDY = MMIO(axi_base_addr + (axi_offset + 1) * axi_range,
                        axi_range)
     self.ST_RDY.write(ch1_dir, agpi)
     ##Initialize interchannel coincidence timer
     axi_offset = 10
     self.CT_DAT = MMIO(axi_base_addr + axi_offset * axi_range, axi_range)
     self.CT_DAT.write(ch1_dir, agpi)
     self.CT_DAT.write(ch2_dir, agpo)
     self.CT_DAT.write(ch2_data, 0x0)  #Hold in reset
     self.CT_RDY = MMIO(axi_base_addr + (axi_offset + 1) * axi_range,
                        axi_range)
     self.CT_RDY.write(ch1_dir, agpi)
     ##Initialize Pulse generator
     axi_offset = 12
     iDC = 0.5
     iFREQ = 440.0
     ph0, ph1 = self.encode_phase_inc(iFREQ)
     iDCenc = self.calc_dc_lim(iFREQ, iDC)
     self.PG_PH = []
     self.PG_AUX = []
     self.chfreqs = [440.0, 440.0, 440.0, 440.0]
     self.chdcs = [0.5, 0.5, 0.5, 0.5]
     self.chdelays = [0, 0, 0, 0]
     for i in range(4):  #Phase increments
         tap = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
         tap.write(ch1_dir, agpo)
         tap.write(ch2_dir, agpo)
         tap.write(ch1_data, ph0)
         tap.write(ch2_data, ph1)
         self.PG_PH.append(tap)
         axi_offset += 1
         self.chfreqs[i] = 440.0
     for i in range(4):  #Duty length and delay
         tdc = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
         tdc.write(ch1_dir, agpo)
         tdc.write(ch1_data, iDCenc)
         tdc.write(ch2_dir, agpo)
         tdc.write(ch2_data, 0x0)
         self.PG_AUX.append(tdc)
         axi_offset += 1
         self.chdcs[i] = 0.5
     self.PG_UTIL = MMIO(0x43D40000,
                         0x10000)  #increment load and master reset
     self.PG_UTIL.write(ch1_dir, agpo)
     self.PG_UTIL.write(ch2_dir, agpo)
     self.PG_UTIL.write(ch1_data, 0x0)  #SEt loader to 0
     self.PG_UTIL.write(ch2_data, 0x0)  #Hold in reset
     #Routine to write initial phase increments
     self.PG_UTIL.write(ch2_data, 0x1)
     self.PG_UTIL.write(ch1_data, 0xF)
     sleep(slt)
     self.PG_UTIL.write(ch1_data, 0x0)
     #Channel enable controller
     self.T_UTIL.write(ch1_dir, 0x0)
     self.T_UTIL.write(ch1_data, 0xF)  #SEt all channels to high impedance
     axi_offset += 1
     self.pg_ch_stat = 0xF
     #self.PG_UTIL.write(ch2_data,0x0)
     ##Initialize Time Tagger
     #initialize detector MMIOs
     self.TT_DET = []
     for i in range(4):
         temp = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
         temp.write(ch1_dir, 0xFFFFFFFF)
         temp.write(ch2_dir, 0xFFFFFFFF)
         self.TT_DET.append(temp)
         axi_offset += 1
     #Initialize timeout MMIO
     self.TT_TIME_OUT = MMIO(axi_base_addr + (axi_offset * axi_range),
                             axi_range)
     self.TT_TIME_OUT.write(ch1_dir, 0x0)
     self.TT_TIME_OUT.write(ch2_dir, 0x0)
     self.TT_TIME_OUT.write(ch1_data, 0xFFFFFFFF)
     self.TT_TIME_OUT.write(ch2_data, 0xFFFF)
     axi_offset += 1
     #Initialize utility
     print(hex(axi_base_addr + (axi_offset * axi_range)))
     print(hex(axi_range))
     self.TT_UTIL = MMIO(axi_base_addr + (axi_offset * axi_range),
                         axi_range)
     self.TT_UTIL.write(ch1_dir, 0x0)
     self.TT_UTIL.write(ch2_dir, 0xFFFFFFFF)
     self.TT_UTIL.write(ch1_data, 0x0)  #Hold system in reset
     axi_offset += 1
     ##Initialize IDELAY
     self.iDD_DATA = []
     self.iDD_UTIL = []
     for i in range(6):
         tempdel = MMIO(axi_base_addr + (axi_offset * axi_range), axi_range)
         tempdel.write(ch1_data, 0x0)
         tempdel.write(ch2_data, 0x0)
         self.iDD_DATA.append(tempdel)
         axi_offset += 1
     for i in range(6):
         temputil = MMIO(axi_base_addr + (axi_offset * axi_range),
                         axi_range)
         temputil.write(ch1_data, 0x1)
         temputil.write(ch2_data, 0x1)
         self.iDD_UTIL.append((temputil))
         axi_offset += 1
Beispiel #31
0
    #download the bitstream to fpga
    ol = Overlay(sys.argv[1])
    ol.download()
    math_ip = MMIO(0x43C40000,0x10000)

    #initialize SparkContext   
    sc = SparkContext(appName="Python Increment")
    testFile = sc.textFile(sys.argv[2])
    oldRDD = testFile.flatMap(lambda x: x.split())
    arr = [x for x in oldRDD.toLocalIterator()] #used spark_2.1.1 because of a spark bug with toLocalIterator() timeout error
    print(arr[0])
    print(arr[1])

    #The RDD is converted to array and we perform the increment function (fpga side) 
    math_ip.write(0x18,int(arr[0]))
    math_ip.write(0x20,int(arr[1]))
    op1=math_ip.read(0x18)
    print(hex(op1))
    op2=math_ip.read(0x20)
    print(hex(op2))
    result=math_ip.read(0x10)
    print(hex(result))

    #A new RDD is created from the values of op1 and op2
    result = str(op1)+" "+str(op2)
    print(result) 
    newRDD = sc.parallelize(list(result))
    newRDD.collect()
    sc.stop()
class PynqMicroblaze:
    """This class controls the active Microblaze instances in the system.

    Attributes
    ----------
    ip_name : str
        The name of the IP corresponding to the Microblaze.
    rst_name : str
        The name of the reset pin for the Microblaze.
    mb_program : str
        The absolute path of the Microblaze program.
    state : str
        The status (IDLE, RUNNING, or STOPPED) of the Microblaze.
    reset_pin : GPIO
        The reset pin associated with the Microblaze.
    mmio : MMIO
        The MMIO instance associated with the Microblaze.
    interrupt : Event
        An asyncio.Event-like class for waiting on and clearing interrupts.

    """
    def __init__(self, mb_info, mb_program, force=False):
        """Create a new Microblaze object.

        It looks for active instances on the same Microblaze, and prevents 
        users from silently reloading the Microblaze program. Users are 
        notified with an exception if a program is already running on the
        selected Microblaze, to prevent unwanted behavior.

        Two cases:

        1.  No previous Microblaze program loaded in the system, 
        or users want to request another instance using the same program.
        No exception will be raised in this case.

        2.  There is a previous Microblaze program loaded in the system.
        Users want to request another instance with a different 
        program. An exception will be raised.

        Note
        ----
        When a Microblaze program is already loaded in the system, and users
        want to instantiate another object using a different Microblaze 
        program, users are in danger of losing existing objects.

        Parameters
        ----------
        mb_info : dict
            A dictionary storing Microblaze information, such as the 
            IP name and the reset name.
        mb_program : str
            The Microblaze program loaded for the processor.

        Raises
        ------
        RuntimeError
            When another Microblaze program is already loaded.

        Examples
        --------
        The `mb_info` is a dictionary storing Microblaze information:

        >>> mb_info = {'ip_name': 'mb_bram_ctrl_1',
        'rst_name': 'mb_reset_1', 
        'intr_pin_name': 'iop1/dff_en_reset_0/q', 
        'intr_ack_name': 'mb_1_intr_ack'}

        """
        ip_dict = PL.ip_dict
        gpio_dict = PL.gpio_dict
        intr_dict = PL.interrupt_pins

        # Check program path
        if not os.path.isfile(mb_program):
            raise ValueError('{} does not exist.'.format(mb_program))

        # Get IP information
        ip_name = mb_info['ip_name']
        if ip_name not in ip_dict.keys():
            raise ValueError("No such IP {}.".format(ip_name))
        addr_base = ip_dict[ip_name]['phys_addr']
        addr_range = ip_dict[ip_name]['addr_range']
        ip_state = ip_dict[ip_name]['state']

        # Get reset information
        rst_name = mb_info['rst_name']
        if rst_name not in gpio_dict.keys():
            raise ValueError("No such reset pin {}.".format(rst_name))
        gpio_uix = gpio_dict[rst_name]['index']

        # Get interrupt pin information
        if 'intr_pin_name' in mb_info:
            intr_pin_name = mb_info['intr_pin_name']
            if intr_pin_name not in intr_dict.keys():
                raise ValueError(
                    "No such interrupt pin {}.".format(intr_pin_name))
        else:
            intr_pin_name = None

        # Get interrupt ACK information
        if 'intr_ack_name' in mb_info:
            intr_ack_name = mb_info['intr_ack_name']
            if intr_ack_name not in gpio_dict.keys():
                raise ValueError(
                    "No such interrupt ACK {}.".format(intr_ack_name))
            intr_ack_gpio = gpio_dict[intr_ack_name]['index']
        else:
            intr_ack_gpio = None

        # Set basic attributes
        self.ip_name = ip_name
        self.rst_name = rst_name
        self.mb_program = mb_program
        self.state = 'IDLE'
        self.reset_pin = GPIO(GPIO.get_gpio_pin(gpio_uix), "out")
        self.mmio = MMIO(addr_base, addr_range)

        # Check to see if Microblaze in user
        if (ip_state is not None) and (ip_state != mb_program):
            if force:
                self.reset()
            else:
                raise RuntimeError(
                    'Another program {} already running.'.format(ip_state))

        # Set optional attributes
        if (intr_pin_name is not None) and (intr_ack_gpio is not None):
            self.interrupt = MBInterruptEvent(intr_pin_name, intr_ack_gpio)
        else:
            self.interrupt = None

        # Reset, program, and run
        self.program()

    def run(self):
        """Start the Microblaze to run program loaded.

        This method will update the status of the Microblaze.

        Returns
        -------
        None

        """
        self.state = 'RUNNING'
        self.reset_pin.write(0)

    def reset(self):
        """Reset the Microblaze to stop it from running.

        This method will update the status of the Microblaze.

        Returns
        -------
        None

        """
        self.state = 'STOPPED'
        self.reset_pin.write(1)

    def program(self):
        """This method programs the Microblaze.

        This method is called in __init__(); it can also be called after that.
        It uses the attribute `self.mb_program` to program the Microblaze.

        Returns
        -------
        None

        """
        self.reset()
        PL.load_ip_data(self.ip_name, self.mb_program)
        if self.interrupt:
            self.interrupt.clear()
        self.run()

    def write(self, offset, data):
        """This method write data into the shared memory of the Microblaze.

        Parameters
        ----------
        offset : int
            The beginning offset where data are written into.
        data : int/list
            A list of 32b words to be written.

        Returns
        -------
        None

        """
        if type(data) is int:
            self.mmio.write(offset, data)
        elif type(data) is list:
            for i, word in enumerate(data):
                self.mmio.write(offset + 4 * i, word)
        else:
            raise ValueError('Type of write data has to be int or lists.')

    def read(self, offset, length=1):
        """This method reads data from the shared memory of Microblaze.

        Parameters
        ----------
        offset : int
            The beginning offset where data are read from.
        length : int
            The number of data (32-bit int) to be read.

        Returns
        -------
        int/list
            An int of a list of data read from the shared memory.

        """
        if length == 1:
            return self.mmio.read(offset)
        elif length > 1:
            return [self.mmio.read(offset + 4 * i) for i in range(length)]
        else:
            raise ValueError('Length of read data has to be 1 or more.')
Beispiel #33
0
class Trace_Buffer:
    """Class for the trace buffer, leveraging the sigrok libraries.
    
    This trace buffer class gets the traces from DMA and processes it using 
    the sigrok commands.
    
    Note
    ----
    The `sigrok-cli` library has to be installed before using this class.
    
    Attributes
    ----------
    protocol : str
        The protocol the sigrok decoder are using.
    trace_csv: str
        The absolute path of the trace file `*.csv`.
    trace_sr: str
        The absolute path of the trace file `*.sr`, translated from `*.csv`.
    trace_pd : str
        The absolute path of the decoded file by sigrok.
    probes : list
        The list of probes used for the trace.
    dma : DMA
        The DMA object associated with the trace buffer.
    ctrl : MMIO
        The MMIO class used to control the DMA.
    samplerate: int
        The samplerate of the traces.
    data : cffi.FFI.CData
        The pointer to the starting address of the trace data.
        
    """
    
    def __init__(self, if_id, protocol, trace=None, data=None, 
                 samplerate=500000):
        """Return a new trace buffer object. 
        
        Users have to specify the location of the traces, even if no trace 
        has been imported from DMA yet. This method will construct the trace
        from the DMA data.
        
        The maximum sample rate is 100MHz.
        
        Note
        ----
        The probes selected by `mask` does not include any tristate probe.
        
        Parameters
        ----------
        if_id : int
            The interface ID (PMODA, PMODB, ARDUINO).
        protocol : str
            The protocol the sigrok decoder are using.
        trace: str
            The relative/absolute path of the trace file.
        data : cffi.FFI.CData
            The pointer to the starting address of the data.
        samplerate : int
            The rate of the samples.
        
        """
        if os.geteuid() != 0:
            raise EnvironmentError('Root permissions required.')
        if not isinstance(protocol, str):
            raise TypeError("Protocol name has to be a string.")
        
        if data != None:
            if not isinstance(data, cffi.FFI.CData):
                raise TypeError("Data pointer has wrong type.")
        if not isinstance(samplerate, int):
            raise TypeError("Sample rate has to be an integer.")
        if not 1 <= samplerate <= 100000000:
            raise ValueError("Sample rate out of range.")
        
        if if_id in [PMODA, PMODB]:
            dma_base = int(PL.ip_dict["SEG_axi_dma_0_Reg"][0],16)
            ctrl_base = int(PL.ip_dict["SEG_trace_cntrl_0_Reg2"][0],16)
            ctrl_range = int(PL.ip_dict["SEG_trace_cntrl_0_Reg2"][1],16)
        elif if_id in [ARDUINO]:
            dma_base = int(PL.ip_dict["SEG_axi_dma_0_Reg1"][0],16)
            ctrl_base = int(PL.ip_dict["SEG_trace_cntrl_0_Reg"][0],16)
            ctrl_range = int(PL.ip_dict["SEG_trace_cntrl_0_Reg"][1],16)
        else:
            raise ValueError("No such IOP for instrumentation.")
            
        self.dma = DMA(dma_base, direction=1)
        self.ctrl = MMIO(ctrl_base, ctrl_range)
        self.samplerate = samplerate
        self.protocol = protocol
        self.data = data
        self.probes = []
        self.trace_pd = ''
        
        if trace != None: 
            if not isinstance(trace, str):
                raise TypeError("Trace path has to be a string.")
            if not os.path.isfile(trace):
                trace_abs = os.getcwd() + '/' + trace
            else:
                trace_abs = trace
            if not os.path.isfile(trace_abs):
                raise ValueError("Specified trace file does not exist.")
            
            _, format = os.path.splitext(trace_abs)
            if format == '.csv':
                self.trace_csv = trace_abs
                self.trace_sr = ''
            elif format == '.sr':
                self.trace_sr = trace_abs
                self.trace_csv = ''
            else:
                raise ValueError("Only supporting csv or sr files.")
        
    def __del__(self):
        """Destructor for trace buffer object.

        Parameters
        ----------
        None
        
        Returns
        -------
        None

        """
        del(self.dma)
        
    def start(self, timeout=10):
        """Start the DMA to capture the traces.
        
        Parameters
        ----------
        timeout : int
            The time in number of milliseconds to wait for DMA to be idle.
            
        Return
        ------
        None
        
        """
        # Create buffer
        self.dma.create_buf(MAX_NUM_SAMPLES*8)
        self.dma.transfer(MAX_NUM_SAMPLES*8, direction=1)
        
        # Wait for DMA to be idle
        timer = timeout
        while (self.ctrl.read(0x00) & 0x04)==0:
            sleep(0.001)
            timer -= 1
            if (timer==0):
                raise RuntimeError("Timeout when waiting DMA to be idle.")
                
        # Configuration
        self.ctrl.write(TRACE_LENGTH_OFFSET, MAX_NUM_SAMPLES)
        self.ctrl.write(TRACE_SAMPLE_RATE_OFFSET, \
                        int(MAX_SAMPLE_RATE / self.samplerate))
        self.ctrl.write(TRACE_CMP_LSW_OFFSET, 0x00000)
        self.ctrl.write(TRACE_CMP_MSW_OFFSET, 0x00000)
        
        # Start the DMA
        self.ctrl.write(TRACE_CTRL_OFFSET,0x01)
        self.ctrl.write(TRACE_CTRL_OFFSET,0x00)
    
    def stop(self):
        """Stop the DMA after capture is done.
        
        Note
        ----
        There is an internal timeout mechanism in the DMA class.
        
        Parameters
        ----------
        None
            
        Return
        ------
        None
        
        """
        # Wait for the DMA
        self.dma.wait()
        
        # Get 64-bit samples from DMA
        self.data = self.dma.get_buf(64)
        
    def show(self):
        """Show information about the specified protocol.
        
        Parameters
        ----------
        None
        
        Return
        ------
        None
        
        """
        if os.system("sigrok-cli --protocol-decoders " + \
                    self.protocol+" --show"):
            raise RuntimeError('Sigrok-cli show failed.')
        
    def csv2sr(self):
        """Translate the `*.csv` file to `*.sr` file.
        
        The translated `*.sr` files can be directly used in PulseView to show 
        the waveform.
        
        Note
        ----
        This method also modifies the input `*.csv` file (the comment header, 
        usually 3 lines, will be removed).
        
        Parameters
        ----------
        None
        
        Return
        ------
        None
        
        """
        name, _ = os.path.splitext(self.trace_csv)
        self.trace_sr = name + ".sr"
        temp = name + ".temp"
        
        if os.system("rm -rf " + self.trace_sr):
            raise RuntimeError('Trace sr file cannot be deleted.')
            
        in_file = open(self.trace_csv, 'r')
        out_file = open(temp, 'w')
        # Copy only the contents; ignore comments
        for i, line in enumerate(in_file):
            if not line.startswith(';'):
                out_file.write(line)
        in_file.close()
        out_file.close()
        os.remove(self.trace_csv)
        os.rename(temp, self.trace_csv)
        
        command = "sigrok-cli -i " + self.trace_csv + \
                    " -I csv -o " + self.trace_sr
        if os.system(command):
            raise RuntimeError('Sigrok-cli csv to sr failed.')
        
    def sr2csv(self):
        """Translate the `*.sr` file to `*.csv` file.
        
        The translated `*.csv` files can be used for interactive plotting. 
        It is human readable.
        
        Note
        ----
        This method also removes the redundant header that is generated by 
        sigrok. 
        
        Parameters
        ----------
        None
        
        Return
        ------
        None
        
        """
        name, _ = os.path.splitext(self.trace_sr)
        self.trace_csv = name + ".csv"
        temp = name + ".temp"
        
        if os.system("rm -rf " + self.trace_csv):
            raise RuntimeError('Trace csv file cannot be deleted.')
            
        command = "sigrok-cli -i " + self.trace_sr + \
                    " -O csv > " + temp
        if os.system(command):
            raise RuntimeError('Sigrok-cli sr to csv failed.')
        
        in_file = open(temp, 'r')
        out_file = open(self.trace_csv, 'w')
        # Copy only the contents; ignore comments
        for i, line in enumerate(in_file):
            if not line.startswith(';'):
                out_file.write(line)
        in_file.close()
        out_file.close()
        os.remove(temp)
        
    def decode(self, decoded_file, options=''):
        """Decode and record the trace based on the protocol specified.
        
        The `decoded_file` contains the name of the output file.
        
        The `option` specifies additional options to be passed to sigrok-cli.
        For example, users can use option=':wordsize=9:cpol=1:cpha=0' to add 
        these options for the SPI decoder.
        
        The decoder will also ignore the pin collected but not required for 
        decoding.
        
        Note
        ----
        The output file will have `*.pd` extension.
        
        Note
        ----
        The decoded file will be put into the specified path, or in the 
        working directory in case the path does not exist.
        
        Parameters
        ----------
        decoded_file : str
            The name of the file recording the outputs.
        options : str
            Additional options to be passed to sigrok-cli.
        
        Return
        ------
        None
        
        """
        if not isinstance(decoded_file, str):
            raise TypeError("File name has to be a string.")
        if self.probes == []:
            raise ValueError("Cannot decode without metadata.")
        
        if os.path.isdir(os.path.dirname(decoded_file)):
            decoded_abs = decoded_file
        else:
            decoded_abs = os.getcwd() + '/' + decoded_file
            
        name, _ = os.path.splitext(self.trace_sr)
        temp_file = name + '.temp'
        if os.system('rm -rf ' + temp_file):
            raise RuntimeError("Cannot remove temporary file.")
        self.trace_pd = ''
        if os.system('rm -rf ' + decoded_abs):
            raise RuntimeError("Cannot remove old decoded file.")
            
        pd_annotation = ''
        for i in self.probes:
            if not i=='NC':
                # Ignore pins not connected to device
                pd_annotation += (':'+i.lower()+'='+i)
        command = "sigrok-cli -i " + self.trace_sr + " -P " + \
            self.protocol + options + pd_annotation + (' > ' + temp_file)
        if os.system(command):
            raise RuntimeError('Sigrok-cli decode failed.')
            
        f_decoded = open(decoded_abs, 'w')
        f_temp = open(temp_file, 'r')
        j = 0
        for line in f_temp:
            m = re.search('([0-9]+)-([0-9]+)  (.*)', line)
            if m:
                while (j < int(m.group(1))):
                    f_decoded.write('\n')
                    j += 1
                while (j <= int(m.group(2))):
                    f_decoded.write(m.group(3) + '\n')
                    j += 1
        f_temp.close()
        f_decoded.close()
        self.trace_pd = decoded_abs
        
        if os.system('rm -rf ' + temp_file):
            raise RuntimeError("Cannot remove temporary file.")
        if os.path.getsize(self.trace_pd)==0:
            raise RuntimeError("No transactions and decoded file is empty.")
        
    def set_metadata(self, probes):
        """Set metadata for the trace.
        
        A `*.sr` file directly generated from `*.csv` will not have any 
        metadata. This method helps to set the sample rate, probe names, etc.
        
        The list `probes` depends on the protocol. For instance, the I2C
        protocol requires a list of ['SDA','SCL'].
        
        Parameters
        ----------
        probes : list
            A list of probe names.
        
        Return
        ------
        None
        
        """
        if not isinstance(probes, list):
            raise TypeError("Probes have to be in a list.")
            
        # Convert csv file to sr file, if necessary
        if self.trace_sr == '':
            self.csv2sr()
        self.probes = probes
            
        name, _ = os.path.splitext(self.trace_sr)
        if os.system("rm -rf " + name):
            raise RuntimeError('Directory cannot be deleted.')
        if os.system("mkdir " + name):
            raise RuntimeError('Directory cannot be created.')
        if os.system("unzip -q "+ self.trace_sr + " -d " + name):
            raise RuntimeError('Unzip sr file failed.')
        
        metadata = open(name + '/metadata', 'r')
        temp = open(name + '/temp', 'w')
        pat = "samplerate=0 Hz"
        subst = "samplerate=" + str(self.samplerate) +" Hz"
        j = 0
        for i, line in enumerate(metadata):
            if line.startswith("probe"):
                # Set the probe names
                temp.write("probe"+str(j+1)+"="+probes[j]+'\n')
                j += 1
            else:
                # Set the sample rate
                temp.write(line.replace(pat, subst))
        metadata.close()
        temp.close()
        
        if os.system("rm -rf "+ name + '/metadata'):
            raise RuntimeError('Cannot remove metadata folder.')
        if os.system("mv " + name + '/temp ' + name + '/metadata'):
            raise RuntimeError('Cannot rename metadata folder.')
        if os.system("cd "+ name +"; zip -rq " + \
                    self.trace_sr + " * ; cd .."):
            raise RuntimeError('Zip sr file failed.')
        if os.system("rm -rf " + name):
            raise RuntimeError('Cannnot remove temporary folder.')
        
    def parse(self, parsed, start=0, stop=MAX_NUM_SAMPLES, mask=MASK_ALL,
              tri_sel=[], tri_0=[], tri_1=[]):
        """Parse the input data and generate a `*.csv` file.
        
        This method can be used along with the DMA. The input data is assumed
        to be 64-bit. The generated `*.csv` file can be then used as the trace
        file.
        
        To extract certain bits from the 64-bit data, use the parameter
        `mask`. 
        
        Note
        ----
        The probe pins selected by `mask` does not include any tristate probe.
        
        To specify a set of tristate probe pins, e.g., users can set 
        tri_sel = [0x0000000000000004],
        tri_0   = [0x0000000000000010], and
        tri_1   = [0x0000000000000100].
        In this example, the 3rd probe from the LSB is the selection probe; 
        the 5th probe is selected if selection probe is 0, otherwise the 9th
        probe is selected. There can be multiple sets of tristate probe pins.
        
        Note
        ----
        The parsed file will be put into the specified path, or in the 
        working directory in case the path does not exist.
        
        Parameters
        ----------
        parsed : str
            The file name of the parsed output.
        start : int
            The first 64-bit sample of the trace.
        stop : int
            The last 64-bit sample of the trace.
        mask : int
            A 64-bit mask to be applied to the 64-bit samples.
        tri_sel : list
            The list of tristate selection probe pins.
        tri_0 : list
            The list of probe pins selected when the selection probe is 0.
        tri_1 : list
            The list probe pins selected when the selection probe is 1.
        
        Return
        ------
        None
        
        """
        if not isinstance(parsed, str):
            raise TypeError("File name has to be an string.")
        if not isinstance(start, int):
            raise TypeError("Sample number has to be an integer.")
        if not isinstance(stop, int):
            raise TypeError("Sample number has to be an integer.")
        if not 1 <= (stop-start) <= MAX_NUM_SAMPLES:
            raise ValueError("Data length has to be in [1,{}]."\
                            .format(MAX_NUM_SAMPLES))
        if not isinstance(mask, int):
            raise TypeError("Data mask has to be an integer.")
        if not 0<=mask<=MASK_ALL:
            raise ValueError("Data mask out of range.")
        if not isinstance(tri_sel, list):
            raise TypeError("Selection probe pins have to be in a list.")
        if not isinstance(tri_0, list) or not isinstance(tri_1, list):
            raise TypeError("Data probe pins have to be in a list.")
        if not len(tri_sel)==len(tri_0)==len(tri_1):
            raise ValueError("Inconsistent length for tristate lists.")
        for element in tri_sel:
            if not isinstance(element, int) or not 0<element<=MASK_ALL:
                raise TypeError("Selection probe has to be an integer.")
            if not (element & element-1)==0:
                raise ValueError("Selection probe can only have 1-bit set.")
            if not (element & mask)==0:
                raise ValueError("Selection probe has be excluded from mask.")
        for element in tri_0:
            if not isinstance(element, int) or not 0<element<=MASK_ALL:
                raise TypeError("Data probe has to be an integer.")
            if not (element & element-1)==0:
                raise ValueError("Data probe can only have 1-bit set.")
            if not (element & mask)==0:
                raise ValueError("Data probe has be excluded from mask.")
        for element in tri_1:
            if not isinstance(element, int) or not 0<element<=MASK_ALL:
                raise TypeError("Data probe has to be an integer.")
            if not (element & element-1)==0:
                raise ValueError("Data probe can only have 1-bit set.")
            if not (element & mask)==0:
                raise ValueError("Data probe has be excluded from mask.")
            
        if os.path.isdir(os.path.dirname(parsed)):
            parsed_abs = parsed
        else:
            parsed_abs = os.getcwd() + '/' + parsed
            
        if os.system('rm -rf ' + parsed_abs):
            raise RuntimeError("Cannot remove old parsed file.")
        with open(parsed_abs, 'w') as f:
            for i in range(start, stop):
                raw_val = self.data[i] & MASK_ALL
                list_val = []
                for j in range(63,-1,-1):
                    if (mask & 1<<j)>>j:
                        list_val.append(str((raw_val & 1<<j)>>j))
                    else:
                        for selection in tri_sel:
                            idx = tri_sel.index(selection)
                            if (selection & 1<<j)>>j:
                                if ((raw_val & 1<<j)>>j)==0:
                                    log = tri_0[idx].bit_length()-1
                                    list_val.append(
                                        str((raw_val & 1<<log)>>log))
                                else:
                                    log = tri_1[idx].bit_length()-1
                                    list_val.append(
                                        str((raw_val & 1<<log)>>log))
                                
                temp = ','.join(list_val)
                f.write(temp + '\n')
                
        self.trace_csv = parsed_abs
        self.trace_sr = ''
        
    def display(self, start_pos, stop_pos):
        """Draw digital waveforms in ipython notebook.
        
        It utilises the wavedrom java script library, documentation for which 
        can be found here: https://code.google.com/p/wavedrom/.
        
        Note
        ----
        Only use this method in Jupyter notebook.
        
        Note
        ----
        WaveDrom.js and WaveDromSkin.js are required under the subdirectory js.
        
        Example of the data format to draw waveform:
        
        >>> data = {'signal': [
        
        {'name': 'clk', 'wave': 'p.....|...'},
        
        {'name': 'dat', 'wave': 'x.345x|=.x', 'data': ['D','A','T','A']},
        
        {'name': 'req', 'wave': '0.1..0|1.0'},
        
        {},
        
        {'name': 'ack', 'wave': '1.....|01.'}
        
        ]}
        
        Parameters
        ----------
        start_pos : int
            The starting sample number (relative to the trace).
        stop_pos : int
            The stopping sample number (relative to the trace).
            
        Returns
        -------
        None
        
        """
        if self.probes == []:
            raise ValueError("Cannot display without metadata.")
        if not isinstance(start_pos, int):
            raise TypeError("Start position has to be an integer.")
        if not 1 <= start_pos <= MAX_NUM_SAMPLES:
            raise ValueError("Start position out of range.")
        if not isinstance(stop_pos, int):
            raise TypeError("Stop position has to be an integer.")
        if not 1 <= stop_pos <= MAX_NUM_SAMPLES:
            raise ValueError("Stop position out of range.")
        
        # Copy the javascript to the notebook location
        if os.system("cp -rf " + \
                    os.path.dirname(os.path.realpath(__file__)) + \
                    '/js' + ' ./'):
            raise RuntimeError('Cannnot copy wavedrom javascripts.')
        
        # Convert sr file to csv file, if necessary
        if self.trace_csv == '':
            self.sr2csv()
            
        # Read csv trace file
        with open(self.trace_csv, 'r') as data_file:
            csv_data = list(csv.reader(data_file))
            
        # Read decoded file
        with open(self.trace_pd, 'r') as pd_file:
            pd_data = list(csv.reader(pd_file))
        
        # Construct the decoded transactions
        data = {}
        data['signal']=[]
        if self.trace_pd != '':
            temp_val = {'name': '', 'wave': '', 'data': []}
            for i in range(start_pos, stop_pos):
                if i==start_pos:
                    ref = pd_data[i]
                    if not ref:
                        temp_val['wave'] += 'x'
                    else:
                        temp_val['wave'] += '4'
                        temp_val['data'].append(''.join(pd_data[i]))
                else:
                    if pd_data[i] == ref:
                        temp_val['wave'] += '.'
                    else:
                        ref = pd_data[i]
                        if not ref:
                            temp_val['wave'] += 'x'
                        else:
                            temp_val['wave'] += '4'
                            temp_val['data'].append(''.join(pd_data[i]))
            data['signal'].append(temp_val)
        
        # Construct the jason format data
        for signal_name in self.probes:
            index = self.probes.index(signal_name)
            temp_val = {'name': signal_name, 'wave': ''}
            for i in range(start_pos, stop_pos):
                if i==start_pos:
                    ref = csv_data[i][index]
                    temp_val['wave'] += str(csv_data[i][index])
                else:
                    if csv_data[i][index] == ref:
                        temp_val['wave'] += '.'
                    else:
                        ref = csv_data[i][index]
                        temp_val['wave'] += str(csv_data[i][index])
            data['signal'].append(temp_val)
            
        # Construct the sample numbers and headers
        head = {}
        head['text'] = ['tspan', {'class':'info h4'}, \
            'Protocol decoder: ' + self.protocol + \
            '; Sample rate: ' + str(self.samplerate) + ' samples/s']
        head['tock'] = ''
        for i in range(start_pos, stop_pos):
            if i%2:
                head['tock'] += ' '
            else:
                head['tock'] += (str(i)+' ')
        data['head'] = head
        
        htmldata = '<script type="WaveDrom">' + json.dumps(data) + '</script>'
        IPython.core.display.display_html(IPython.core.display.HTML(htmldata))
        jsdata = 'WaveDrom.ProcessAll();'
        IPython.core.display.display_javascript(
            IPython.core.display.Javascript(
                data=jsdata, \
                lib=['files/js/WaveDrom.js', 'files/js/WaveDromSkin.js']))