Exemplo n.º 1
0
	sgm0_done = sgm0_done or sgm_optim_0.register_map.CTRL.AP_DONE
	sgm1_done = sgm1_done or sgm_optim_1.register_map.CTRL.AP_DONE
	#print(count)
	#count = count + 1
	pass

print("--- %s seconds ---" % (time.time() - start_time))

raw_iml_buffer = np.zeros((IMG_HEIGHT,IMG_WIDTH),dtype=np.ubyte)
raw_imr_buffer = np.zeros((IMG_HEIGHT,IMG_WIDTH),dtype=np.ubyte)
rec_iml_buffer = np.zeros((IMG_HEIGHT,IMG_WIDTH),dtype=np.ubyte)
rec_imr_buffer = np.zeros((IMG_HEIGHT,IMG_WIDTH),dtype=np.ubyte)
disp_im_buffer = np.zeros((IMG_HEIGHT,IMG_WIDTH),dtype=np.ubyte)

for i in range(IMG_HEIGHT):
	for j in range(IMG_WIDTH):
			disp_im_buffer[i][j] = Image_buf[12*image_size+i*IMG_WIDTH+j]
			raw_imr_buffer[i][j] = Image_buf[1*image_size+i*IMG_WIDTH+j]
			raw_iml_buffer[i][j] = Image_buf[0*image_size+i*IMG_WIDTH+j]
			rec_imr_buffer[i][j] = Image_buf[11*image_size+i*IMG_WIDTH+j]
			rec_iml_buffer[i][j] = Image_buf[10*image_size+i*IMG_WIDTH+j]

cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/raw_iml_buffer.png',raw_iml_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/raw_imr_buffer.png',raw_imr_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/rec_iml_buffer.png',rec_iml_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/rec_imr_buffer.png',rec_imr_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/disp_im_buffer.png',disp_im_buffer)


Xlnk.cma_free(Image_buf)
# while(count < 5000):
# 	print(count)
# 	count = count +1
# 	for i in range(IMG_HEIGHT):
# 		for j in range(IMG_WIDTH):
# 			disp_im_buffer[i][j] = Image_buf[12*image_size+i*IMG_WIDTH+j]
# 	cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/disp_im_buffer.png',disp_im_buffer)
# 	Image_buf[0:image_size] = test1[0:image_size]                       #left raw image
# 	Image_buf[image_size:image_size*2] = test2[0:image_size]            #right raw image

for i in range(IMG_HEIGHT):
    for j in range(IMG_WIDTH):
        disp_im_buffer[i][j] = Image_buf[12 * image_size + i * IMG_WIDTH + j]
        raw_imr_buffer[i][j] = Image_buf[1 * image_size + i * IMG_WIDTH + j]
        raw_iml_buffer[i][j] = Image_buf[0 * image_size + i * IMG_WIDTH + j]
        rec_imr_buffer[i][j] = Image_buf[11 * image_size + i * IMG_WIDTH + j]
        rec_iml_buffer[i][j] = Image_buf[10 * image_size + i * IMG_WIDTH + j]

cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/raw_iml_buffer.png',
            raw_iml_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/raw_imr_buffer.png',
            raw_imr_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/rec_iml_buffer.png',
            rec_iml_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/rec_imr_buffer.png',
            rec_imr_buffer)
cv2.imwrite('/home/xilinx/sgm_pynq_ver/output_images/disp_im_buffer.png',
            disp_im_buffer)

xlnk.cma_free(Image_buf)
Exemplo n.º 3
0
class Arduino_LCD18(object):
    """This class controls the Adafruit 1.8" LCD shield from AdaFruit. 
    
    The LCD panel consists of ST7735 LCD controller, a joystick, and a microSD
    socket. This class uses the LCD panel (128x160 pixels) and the joystick. 
    The joystick uses A3 analog channel. https://www.adafruit.com/product/802.
    
    Attributes
    ----------
    microblaze : Arduino
        Microblaze processor instance used by this module.
    buf_manager : Xlnk
        DDR management unit that provides the physical address of the image.
        
    """
    def __init__(self, mb_info):
        """Return a new instance of an Arduino_LCD18 object.
        
        Parameters
        ----------
        mb_info : dict
            A dictionary storing Microblaze information, such as the
            IP name and the reset name.

        """
        self.microblaze = Arduino(mb_info, ARDUINO_LCD18_PROGRAM)
        self.buf_manager = Xlnk()

    def clear(self):
        """Clear the screen.
        
        Returns
        -------
        None
        
        """
        self.microblaze.write_blocking_command(CLEAR_SCREEN)

    def display(self,
                img_path,
                x_pos=0,
                y_pos=127,
                orientation=3,
                background=None,
                frames=1):
        """Animate the image at the desired location for multiple frames.

        The maximum screen resolution is 160x128.

        Users can specify the position to display the image. For example, to
        display the image in the center, `x_pos` can be (160-`width`/2),
        `y_pos` can be (128/2)+(`height`/2).

        A typical orientation is 3. The origin of orientation 0, 1, 2, and 3
        corresponds to upper right corner, lower right corner, lower left
        corner, and upper left corner, respectively. Currently, only 1 and 3
        are valid orientations. If users choose orientation 1, the picture
        will be shown upside-down. If users choose orientation 3, the picture
        will be shown consistently with the LCD screen orientation.

        Parameter `background` specifies the color of the background;
        it is a list of 3 elements: R, G, and B, each with 8 bits for color
        level.

        Parameters
        ----------
        img_path : str
            The file path to the image stored in the file system.
        x_pos : int
            x position of a pixel where the image starts.
        y_pos : int
            y position of a pixel where the image starts.
        background : list
            A list of [R, G, B] components for background, each of 8 bits.
        orientation : int
            orientation of the image; valid values are 1 and 3.
        frames : int
            Number of frames the image is moved, must be less than 65536.

        Returns
        -------
        None

        """
        task = asyncio.ensure_future(
            self.display_async(img_path, x_pos, y_pos, orientation, background,
                               frames))
        loop = asyncio.get_event_loop()
        loop.run_until_complete(task)

    @asyncio.coroutine
    def display_async(self,
                      img_path,
                      x_pos=0,
                      y_pos=127,
                      orientation=3,
                      background=None,
                      frames=1):
        """Animate the image at the desired location for multiple frames.

        The maximum screen resolution is 160x128.

        Users can specify the position to display the image. For example, to
        display the image in the center, `x_pos` can be (160-`width`/2),
        `y_pos` can be (128/2)+(`height`/2).

        A typical orientation is 3. The origin of orientation 0, 1, 2, and 3
        corresponds to upper right corner, lower right corner, lower left
        corner, and upper left corner, respectively. Currently, only 1 and 3
        are valid orientations. If users choose orientation 1, the picture
        will be shown upside-down. If users choose orientation 3, the picture
        will be shown consistently with the LCD screen orientation.

        Parameter `background` specifies the color of the background;
        it is a list of 3 elements: R, G, and B, each with 8 bits for color
        level.

        Parameters
        ----------
        img_path : str
            The file path to the image stored in the file system.
        x_pos : int
            x position of a pixel where the image starts.
        y_pos : int
            y position of a pixel where the image starts.
        background : list
            A list of [R, G, B] components for background, each of 8 bits.
        orientation : int
            orientation of the image; valid values are 1 and 3.
        frames : int
            Number of frames the image is moved, must be less than 65536.

        Returns
        -------
        None

        """
        if x_pos not in range(160):
            raise ValueError("Valid x_pos is 0 - 159.")
        if y_pos not in range(128):
            raise ValueError("Valid y_pos is 0 - 127.")
        if orientation not in [1, 3]:
            raise ValueError("Valid orientation is 1 or 3.")
        if frames not in range(1, 65536):
            raise ValueError("Valid number of frames is 1 - 65535.")
        if not os.path.isfile(img_path):
            raise ValueError("Specified image file does not exist.")

        if background is None:
            background = [0, 0, 0]
        background16 = _convert_color(background)

        image_file = Image.open(img_path)
        width, height = image_file.size
        if width not in range(161) or height not in range(129):
            raise ValueError("Picture too large to be fit in 160x128 screen.")
        image_file.resize((width, height), Image.ANTIALIAS)
        image_array = array(image_file)
        image_file.close()

        file_size = width * height * 2
        buf0 = self.buf_manager.cma_alloc(file_size, data_type="uint8_t")
        buf1 = self.buf_manager.cma_get_buffer(buf0, file_size)
        phy_addr = self.buf_manager.cma_get_phy_addr(buf0)
        try:
            for j in range(width):
                for i in range(height):
                    red, green, blue = image_array[i][j]
                    temp = ((blue & 0xF8) << 8) | ((green & 0xFC) << 3) | \
                           ((red & 0xF8) >> 3)
                    index = 2 * ((height - i - 1) * width + j)
                    buf1[index] = bytes([temp & 0xFF])
                    buf1[index + 1] = bytes([(temp & 0xFF00) >> 8])

            data = [
                x_pos, y_pos, width, height, phy_addr, background16,
                orientation, frames
            ]
            self.microblaze.write_mailbox(0, data)

            # Ensure interrupt is reset before issuing command
            if self.microblaze.interrupt:
                self.microblaze.interrupt.clear()
            self.microblaze.write_non_blocking_command(DISPLAY)
            while self.microblaze.read(MAILBOX_OFFSET +
                                       MAILBOX_PY2IOP_CMD_OFFSET) != 0:
                if self.microblaze.interrupt:
                    yield from self.microblaze.interrupt.wait()
        finally:
            if self.microblaze.interrupt:
                self.microblaze.interrupt.clear()
            self.buf_manager.cma_free(buf0)

    def draw_line(self,
                  x_start_pos,
                  y_start_pos,
                  x_end_pos,
                  y_end_pos,
                  color=None,
                  background=None,
                  orientation=3):
        """Draw a line from starting point to ending point.

        The maximum screen resolution is 160x128.

        Parameter `color` specifies the color of the line; it is a list of 3
        elements: R, G, and B, each with 8 bits for color level.

        Parameter `background` is similar to parameter `color`, except that it
        specifies the background color.

        A typical orientation is 3. The origin of orientation 0, 1, 2, and 3
        corresponds to upper right corner, lower right corner, lower left
        corner, and upper left corner, respectively. Currently, only 1 and 3
        are valid orientations. If users choose orientation 1, the picture
        will be shown upside-down. If users choose orientation 3, the picture
        will be shown consistently with the LCD screen orientation.

        Parameters
        ----------
        x_start_pos : int
            x position (in pixels) where the line starts.
        y_start_pos : int
            y position (in pixels) where the line starts.
        x_end_pos : int
            x position (in pixels ) where the line ends.
        y_end_pos : int
            y position (in pixels) where the line ends.
        color : list
            A list of [R, G, B] components for line color, each of 8 bits.
        background : list
            A list of [R, G, B] components for background, each of 8 bits.
        orientation : int
            orientation of the image; valid values are 1 and 3.

        Returns
        -------
        None

        """
        if x_start_pos not in range(160):
            raise ValueError("Valid x start position is 0 - 159.")
        if y_start_pos not in range(128):
            raise ValueError("Valid y start position is 0 - 127.")
        if x_end_pos not in range(160):
            raise ValueError("Valid x end position is 0 - 159.")
        if y_end_pos not in range(128):
            raise ValueError("Valid y end position is 0 - 127.")
        if orientation not in [1, 3]:
            raise ValueError("Valid orientation is 1 or 3.")

        if color is None:
            color = [255, 255, 255]
        color16 = _convert_color(color)
        if background is None:
            background = [0, 0, 0]
        background16 = _convert_color(background)

        data = [
            x_start_pos, y_start_pos, x_end_pos, y_end_pos, color16,
            background16, orientation
        ]
        self.microblaze.write_mailbox(0, data)
        self.microblaze.write_blocking_command(DRAW_LINE)

    def print_string(self,
                     x_start_pos,
                     y_start_pos,
                     text,
                     color=None,
                     background=None,
                     orientation=3):
        """Draw a character with a specific color.

        The maximum screen resolution is 160x128.

        Parameter `color` specifies the color of the text; it is a list of 3
        elements: R, G, and B, each with 8 bits for color level.

        Parameter `background` is similar to parameter `color`, except that it
        specifies the background color.

        A typical orientation is 3. The origin of orientation 0, 1, 2, and 3
        corresponds to upper right corner, lower right corner, lower left
        corner, and upper left corner, respectively. Currently, only 1 and 3
        are valid orientations. If users choose orientation 1, the picture
        will be shown upside-down. If users choose orientation 3, the picture
        will be shown consistently with the LCD screen orientation.
        
        Parameters
        ----------
        x_start_pos : int
            x position (in pixels) where the line starts.
        y_start_pos : int
            y position (in pixels) where the line starts.
        text : str
            printable ASCII characters.
        color : list
            A list of [R, G, B] components for line color, each of 8 bits.
        background : list
            A list of [R, G, B] components for background, each of 8 bits.
        orientation : int
            orientation of the image; valid values are 1 and 3.

        Returns
        -------
        None

        """
        if x_start_pos not in range(160):
            raise ValueError("Valid x start position is 0 - 159.")
        if y_start_pos not in range(128):
            raise ValueError("Valid y start position is 0 - 127.")
        if type(text) is not str:
            raise ValueError("Character has to be of string type.")
        if orientation not in [1, 3]:
            raise ValueError("Valid orientation is 1 or 3.")

        if color is None:
            color = [255, 255, 255]
        color16 = _convert_color(color)
        if background is None:
            background = [0, 0, 0]
        background16 = _convert_color(background)

        temp_txt = text
        count = len(text)
        for _ in range(count % 4):
            temp_txt = temp_txt + str('\0')

        data = [x_start_pos, y_start_pos, color16, background16, orientation]
        temp = 0
        for i in range(len(temp_txt)):
            temp = temp | (ord(temp_txt[i]) << 8 * (i % 4))
            if i % 4 == 3:
                data.append(temp)
                temp = 0

        self.microblaze.write_mailbox(0, data)
        self.microblaze.write_blocking_command(PRINT_STRING)

    def draw_filled_rectangle(self,
                              x_start_pos,
                              y_start_pos,
                              width,
                              height,
                              color=None,
                              background=None,
                              orientation=3):
        """Draw a filled rectangle.

        Parameter `color` specifies the color of the text; it is a list of 3
        elements: R, G, and B, each with 8 bits for color level.

        Parameter `background` is similar to parameter `color`, except that it
        specifies the background color.

        A typical orientation is 3. The origin of orientation 0, 1, 2, and 3
        corresponds to upper right corner, lower right corner, lower left
        corner, and upper left corner, respectively. Currently, only 1 and 3
        are valid orientations. If users choose orientation 1, the picture
        will be shown upside-down. If users choose orientation 3, the picture
        will be shown consistently with the LCD screen orientation.

        Parameters
        ----------
        x_start_pos : int
            x position (in pixels) where the rectangle starts.
        y_start_pos : int
            y position (in pixels) where the rectangle starts.
        width : int
            Width of the rectangle (in pixels).
        height : int
            Height of the rectangle (in pixels).
        color : list
            A list of [R, G, B] components for line color, each of 8 bits.
        background : list
            A list of [R, G, B] components for background, each of 8 bits.
        orientation : int
            orientation of the image; valid values are 1 and 3.

        Returns
        -------
        None

        """
        if x_start_pos not in range(160):
            raise ValueError("Valid x start position is 0 - 159.")
        if y_start_pos not in range(128):
            raise ValueError("Valid y start position is 0 - 127.")
        if width not in range(160):
            raise ValueError("Valid x end position is 0 - 159.")
        if height not in range(128):
            raise ValueError("Valid y end position is 0 - 127.")
        if orientation not in [1, 3]:
            raise ValueError("Valid orientation is 1 or 3.")

        if color is None:
            color = [255, 255, 255]
        color16 = _convert_color(color)
        if background is None:
            background = [0, 0, 0]
        background16 = _convert_color(background)

        data = [
            x_start_pos, y_start_pos, width, height, color16, background16,
            orientation
        ]
        self.microblaze.write_mailbox(0, data)
        self.microblaze.write_blocking_command(FILL_RECTANGLE)

    def read_joystick(self):
        """Read the joystick values.

        The joystick values can be read when user is pressing the button
        toward a specific direction.

        The returned values can be:
        1: left;
        2: down;
        3: center;
        4: right;
        5: up;
        0: no button pressed.

        Returns
        -------
        int
            Indicating the direction towards which the button is pushed.

        """
        self.microblaze.write_blocking_command(READ_BUTTON)
        value = self.microblaze.read_mailbox(0)
        return value
Exemplo n.º 4
0
class LogicToolsController(PynqMicroblaze):
    """This class controls all the logic generators.

    This class uses the PynqMicroblaze class. It extends 
    PynqMicroblaze with capability to control boolean generators, pattern
    generators, and Finite State Machine (FSM) generators.

    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 : 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.
    clk : Clocks
        The instance to control PL clocks.
    buf_manager : Xlnk
        The Xlnk memory manager used for contiguous memory allocation.
    buffers : dict
        A dictionary of cffi.FFI.CData buffer, each can be accessed similarly
        as arrays.
    intf_spec : dict
        The interface specification, e.g., PYNQZ1_LOGICTOOLS_SPECIFICATION.
    pin_map : dict
        A dictionary of pins available from the interface specification.
    status : dict
        A dictionary keeping track of the generator status.
    steps : int
        The number of steps during `step()` method. Equals 
        `num_analyzer_samples` when `run()` is called.

    """
    __instance = None
    __initialized = False
    __time_stamp = None

    def __new__(cls,
                mb_info,
                intf_spec_name='PYNQZ1_LOGICTOOLS_SPECIFICATION'):
        """Create a new Microblaze object.

        This method overwrites the default `new()` method so that the same
        instance can be reused by many modules. The internal variable 
        `__instance` is private and used as a singleton.

        Parameters
        ----------
        mb_info : dict
            A dictionary storing Microblaze information, such as the 
            IP name and the reset name.
        intf_spec_name : str
            The name of the interface specification.

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

        >>> mb_info = {'ip_name': 'mb_bram_ctrl_3',
        'rst_name': 'mb_reset_3', 
        'intr_pin_name': 'iop3/dff_en_reset_0/q', 
        'intr_ack_name': 'mb_3_intr_ack'}

        """
        if cls.__instance is None or cls.__time_stamp != PL.timestamp:
            cls.__instance = PynqMicroblaze.__new__(cls)
            cls.__time_stamp = PL.timestamp
            cls.__initialized = False
        return cls.__instance

    def __init__(self,
                 mb_info,
                 intf_spec_name='PYNQZ1_LOGICTOOLS_SPECIFICATION',
                 logictools_microblaze_bin=LOGICTOOLS_ARDUINO_BIN):
        """Initialize the created Microblaze object.

        This method leverages the initialization method of its parent. It 
        also deals with relative / absolute path of the program.

        Parameters
        ----------
        mb_info : dict
            A dictionary storing Microblaze information, such as the 
            IP name and the reset name.
        intf_spec_name : str
            The name of the interface specification.
        logictools_microblaze_bin : str
            The name of the microblaze program to be loaded.

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

        >>> mb_info = {'ip_name': 'mb_bram_ctrl_3',
        'rst_name': 'mb_reset_3', 
        'intr_pin_name': 'iop3/dff_en_reset_0/q', 
        'intr_ack_name': 'mb_3_intr_ack'}

        """
        if not os.path.isabs(logictools_microblaze_bin):
            mb_program = os.path.join(BIN_LOCATION, logictools_microblaze_bin)
        else:
            mb_program = logictools_microblaze_bin

        if not self.__initialized:
            super().__init__(mb_info, mb_program)

            self.clk = Clocks
            self.buf_manager = Xlnk()
            self.buffers = dict()
            self.status = {k: 'RESET' for k in GENERATOR_ENGINE_DICT.keys()}
            self.intf_spec = eval(intf_spec_name)
            pin_list = list(
                set(self.intf_spec['traceable_io_pins'].keys())
                | set(self.intf_spec['non_traceable_outputs'].keys())
                | set(self.intf_spec['non_traceable_inputs'].keys()))
            self.pin_map = {k: 'UNUSED' for k in pin_list}
            self.steps = 0
            self.__class__.__initialized = True

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

        This method is called in `__init__()`; it can also be called after 
        that. It overwrites the `program()` method defined in the parent class.

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

    def write_control(self, ctrl_parameters):
        """This method writes control parameters to the Microblaze.

        Parameters
        ----------
        ctrl_parameters : list
            A list of control parameters, each being an int.

        Returns
        -------
        None

        """
        self.write(MAILBOX_OFFSET, ctrl_parameters)

    def read_results(self, num_words):
        """This method reads results from the Microblaze.

        Parameters
        ----------
        num_words : int
            Number of 32b words to read from Microblaze mailbox.

        Returns
        -------
        list
            list of results read from mailbox

        """
        return self.read(MAILBOX_OFFSET, num_words)

    def write_command(self, command):
        """This method writes the commands to the Microblaze.

        The program waits in the loop until the command is cleared by the
        Microblaze.

        Parameters
        ----------
        command : int
            The command to write to the Microblaze.

        Returns
        -------
        None

        """
        self.write(MAILBOX_OFFSET + MAILBOX_PY2DIF_CMD_OFFSET, command)
        while self.read(MAILBOX_OFFSET + MAILBOX_PY2DIF_CMD_OFFSET) != 0:
            pass

    def check_status(self):
        """Check the status of all the generators.

        This method will send the command to the Microblaze, and wait for the 
        Microblaze to return the status for all the generator.

        """
        self.write_command(CMD_CHECK_STATUS)
        one_hot_status_list = self.read_results(len(GENERATOR_ENGINE_DICT))
        generator_name_list = GENERATOR_ENGINE_DICT.keys()
        for generator_name, one_hot_status in zip(generator_name_list,
                                                  one_hot_status_list):
            for state_name, state_code in GENERATOR_STATE.items():
                if one_hot_status == state_code:
                    self.status[generator_name] = state_name
                    break

    def reset(self, generator_list):
        """Reset the specified generators.

        After reset, the corresponding generators will have to be setup again
        before it can be run or step. During reset, each generator will be 
        stopped first.

        Parameters
        ----------
        generator_list : list
            A list of generators in any state, each being a generator object.

        """
        self.stop(generator_list)
        cmd_reset = CMD_RESET
        for generator in generator_list:
            generator_type = generator.__class__.__name__
            cmd_reset |= GENERATOR_ENGINE_DICT[generator_type]
            if generator.analyzer is not None:
                analyzer_type = generator.analyzer.__class__.__name__
                cmd_reset |= GENERATOR_ENGINE_DICT[analyzer_type]
        self.write_command(cmd_reset)
        for generator in generator_list:
            generator.reset()
        self.steps = 0
        self.check_status()

    def run(self, generator_list):
        """Send the command `RUN` to the Microblaze.

        Send the command to the Microblaze, and wait for the Microblaze
        to return control.

        Valid generators must be objects of BooleanGenerator, PatternGenerator, 
        FSMGenerator, or TraceAnalyzer.

        Parameters
        ----------
        generator_list : list
            A list of READY generators, each being a generator object.

        """
        for generator in generator_list:
            generator_type = generator.__class__.__name__
            if self.status[generator_type] == 'RESET':
                raise ValueError(
                    "{} must be at least READY before RUNNING.".format(
                        generator_type))

        cmd_run = CMD_RUN
        for generator in generator_list:
            generator_type = generator.__class__.__name__
            generator.connect()
            cmd_run |= GENERATOR_ENGINE_DICT[generator_type]
            if generator.analyzer is not None:
                analyzer_type = generator.analyzer.__class__.__name__
                cmd_run |= GENERATOR_ENGINE_DICT[analyzer_type]

        self.write_command(cmd_run)
        for generator in generator_list:
            generator.analyze()
        self.check_status()

    def step(self, generator_list):
        """Send the command `STEP` to the Microblaze.

        Send the command to the Microblaze, and wait for the Microblaze
        to return control.

        Valid generators must be objects of BooleanGenerator, PatternGenerator, 
        FSMGenerator, or TraceAnalyzer.

        Parameters
        ----------
        generator_list : list
            A list of READY generators, each being a generator object.

        """
        for generator in generator_list:
            generator_type = generator.__class__.__name__
            if self.status[generator_type] == 'RESET':
                raise ValueError(
                    "{} must be at least READY before RUNNING.".format(
                        generator_type))

        cmd_step = CMD_STEP
        for generator in generator_list:
            generator_type = generator.__class__.__name__
            cmd_step |= GENERATOR_ENGINE_DICT[generator_type]
            if generator.analyzer is not None:
                analyzer_type = generator.analyzer.__class__.__name__
                cmd_step |= GENERATOR_ENGINE_DICT[analyzer_type]

        if self.steps == 0:
            for generator in generator_list:
                generator.connect()
            self.write_command(cmd_step)
        self.steps += 1

        self.write_command(cmd_step)
        for generator in generator_list:
            generator.analyze()
        self.check_status()

    def stop(self, generator_list):
        """Send the command `STOP` to the Microblaze.

        Send the command to the Microblaze, and wait for the Microblaze
        to return control.

        Valid generators must be objects of BooleanGenerator, PatternGenerator, 
        FSMGenerator, or TraceAnalyzer.

        Parameters
        ----------
        generator_list : list
            A list of RUNNING generators, each being a generator object.

        """
        cmd_stop = CMD_STOP
        for generator in generator_list:
            generator_type = generator.__class__.__name__
            cmd_stop |= GENERATOR_ENGINE_DICT[generator_type]
            if generator.analyzer is not None:
                analyzer_type = generator.analyzer.__class__.__name__
                cmd_stop |= GENERATOR_ENGINE_DICT[analyzer_type]
        self.write_command(cmd_stop)
        for generator in generator_list:
            generator.disconnect()
            generator.clear_wave()
        self.steps = 0
        self.check_status()

    def __del__(self):
        """Clean up the object when it is no longer used.

        Contiguous memory buffers have to be freed.

        """
        self.reset_buffers()

    def allocate_buffer(self, name, num_samples, data_type="unsigned int"):
        """This method allocates the source or the destination buffers.

        Usually, the source buffer stores 32-bit samples, while the
        destination buffer stores 64-bit samples.

        Note that the numpy array has to be deep-copied before users can
        free the buffer.

        Parameters
        ----------
        name : str
            The name of the string, used for indexing the buffers.
        num_samples : int
            The number of samples that needs to be generated or captured.
        data_type : str
            The type of the data.

        Returns
        -------
        int
            The address of the source or destination buffer.

        """
        buf = self.buf_manager.cma_alloc(num_samples, data_type=data_type)
        self.buffers[name] = buf
        return self.buf_manager.cma_get_phy_addr(buf)

    def ndarray_from_buffer(self, name, num_bytes, dtype=np.uint32):
        """This method returns a numpy array from the buffer.

        If not data type is specified, the returned numpy array will have
        data type as `numpy.uint32`.

        The numpy array is copied. Hence even if the underlying buffer is
        freed, the returned numpy array is still usable.

        Parameters
        ----------
        name : str
            The name of the buffer where the numpy array can be constructed.
        num_bytes : int
            The length of the buffer, in bytes.
        dtype : str
            Data type of the numpy array.

        Returns
        -------
        numpy.ndarray
            The numpy array constructed from the buffer.

        """
        if name not in self.buffers:
            raise ValueError(
                "No such buffer {} allocated previously.".format(name))
        buffer = self.buffers[name]
        buf_temp = self.buf_manager.cma_get_buffer(buffer, num_bytes)
        return np.frombuffer(buf_temp, dtype=dtype).copy()

    def free_buffer(self, name):
        """This method frees the buffer.

        Note that the numpy array built on top of the buffer should be
        deep-copied before users can free the buffer.

        Parameters
        ----------
        name : str
            The name of the buffer to be freed.

        """
        if name in self.buffers:
            self.buf_manager.cma_free(self.buffers[name])
            del (self.buffers[name])

    def phy_addr_from_buffer(self, name):
        """Get the physical address from the buffer.

        The method takes the name of the buffer as input, and returns the 
        physical address.

        Parameters
        ----------
        name : str
            The name of the buffer.

        Returns
        -------
        int
            The physical address of the buffer.

        """
        if name not in self.buffers:
            raise ValueError(
                "No such buffer {} allocated previously.".format(name))
        return self.buf_manager.cma_get_phy_addr(self.buffers[name])

    def reset_buffers(self):
        """This method resets all the buffers.

        Note that the numpy array built on top of the buffer should be
        deep-copied before users can free the buffer.

        """
        if self.buffers:
            for name in self.buffers:
                self.buf_manager.cma_free(self.buffers[name])
        self.buffers = dict()

    def config_ioswitch(self, ioswitch_pins, ioswitch_select_value):
        """Configure the IO switch.

        This method configures the IO switch based on the input parameters.

        Parameters
        ----------
        ioswitch_pins : list
            List of pins to be configured.
        ioswitch_select_value : int
            Function selection parameter.

        """
        # Read switch config
        self.write_command(CMD_READ_INTF_SWITCH_CONFIG)
        mailbox_addr = self.mmio.base_addr + MAILBOX_OFFSET
        ioswitch_config = [
            Register(addr) for addr in [mailbox_addr, mailbox_addr + 4]
        ]

        # Modify switch for requested entries
        for ix in ioswitch_pins:
            if ix < 10:
                lsb = ix * 2
                msb = ix * 2 + 1
                ioswitch_config[0][msb:lsb] = ioswitch_select_value
            else:
                lsb = (ix - 10) * 2
                msb = (ix - 10) * 2 + 1
                ioswitch_config[1][msb:lsb] = ioswitch_select_value

        # Write switch config
        self.write_command(CMD_INTF_SWITCH_CONFIG)