예제 #1
0
파일: task.py 프로젝트: Blaok/tapa
  def convert_axis_to_fifo(self, axis_name: str) -> str:
    assert len(self.get_fifo_directions(axis_name)) == 1, \
        "axis interfaces should have one direction"
    direction_axis = {
        'consumed_by': 'produced_by',
        'produced_by': 'consumed_by',
    }[self.get_fifo_directions(axis_name)[0]]
    data_width = self.ports[axis_name].width

    # add FIFO registerings to provide timing isolation
    fifo_name = 'tapa_fifo_' + axis_name
    self.module.add_fifo_instance(name=fifo_name,
        width=data_width+1, depth=2)

    # add FIFO's wires
    for suffix in rtl.STREAM_PORT_DIRECTION:
      wire_name = rtl.wire_name(fifo_name, suffix)
      wire_width = rtl.get_stream_width(suffix, data_width)
      self.module.add_signals([ast.Wire(name=wire_name, width=wire_width)])

    # add constant outputs for AXIS output ports
    if direction_axis == 'consumed_by':
      for axis_suffix, bit in rtl.AXIS_CONSTANTS.items():
        port_name = self.module.find_port(axis_name, axis_suffix)
        width = rtl.get_axis_port_width_int(axis_suffix, data_width)

        self.module.add_logics([
            ast.Assign(left=ast.Identifier(port_name),
                       right=ast.IntConst("%d'b%s"%(width, str(bit)*width)))])

    # connect the FIFO to the AXIS interface
    for suffix in self.get_fifo_suffixes(direction_axis):
      wire_name = rtl.wire_name(fifo_name, suffix)

      offset = 0
      for axis_suffix in rtl.STREAM_TO_AXIS[suffix]:
        port_name = self.module.find_port(axis_name, axis_suffix)
        width = rtl.get_axis_port_width_int(axis_suffix, data_width)

        if len(rtl.STREAM_TO_AXIS[suffix]) > 1:
          wire = ast.Partselect(ast.Identifier(wire_name),
              ast.IntConst(str(offset + width - 1)),
              ast.IntConst(str(offset)))
        else:
          wire = ast.Identifier(wire_name)

        self.assign_directional(
            ast.Identifier(port_name), wire,
            rtl.STREAM_PORT_DIRECTION[suffix])

        offset += width

    return fifo_name
예제 #2
0
파일: task.py 프로젝트: Blaok/tapa
  def connect_fifo_externally(self, internal_name: str, top: bool) -> None:
    assert len(self.get_fifo_directions(internal_name)) == 1, \
        "externally connected fifos should have one direction"
    direction = self.get_fifo_directions(internal_name)[0]
    external_name = self.convert_axis_to_fifo(internal_name) \
        if top else internal_name

    # connect fifo with external ports
    for suffix in self.get_fifo_suffixes(direction):
      self.assign_directional(
          ast.Identifier(rtl.wire_name(internal_name, suffix)),
          ast.Identifier(
              self.module.get_port_of(external_name, suffix).name
              if external_name == internal_name
              else rtl.wire_name(external_name, suffix)),
          rtl.STREAM_PORT_DIRECTION[suffix])
예제 #3
0
파일: instance.py 프로젝트: dotkrnl/tapa
    def done(self) -> ast.Identifier:
        """The handshake done signal.

    This signal is asserted for 1 cycle when the instance of task finishes.

    Returns:
      The ast.Identifier node of this signal.
    """
        return ast.Identifier(f'{self.name}__{rtl.HANDSHAKE_DONE}')
예제 #4
0
파일: instance.py 프로젝트: dotkrnl/tapa
    def start(self) -> ast.Identifier:
        """The handshake start signal.

    This signal is asserted until the ready signal is asserted when the instance
    of task starts.

    Returns:
      The ast.Identifier node of this signal.
    """
        return ast.Identifier(f'{self.name}__{rtl.HANDSHAKE_START}')
예제 #5
0
파일: m_axi.py 프로젝트: dotkrnl/tapa
def rename_m_axi_port(
    mapping: Dict[str, str],
    port: IOPort,
) -> IOPort:
    new_port = copy.copy(port)
    new_port.name = rename_m_axi_name(mapping, port.name, 2, -1)
    if port.width is not None and isinstance(port.width.msb, ast.Minus):
        new_port.width = copy.copy(new_port.width)
        new_port.width.msb = copy.copy(new_port.width.msb)
        new_port.width.msb.left = ast.Identifier(
            rename_m_axi_name(mapping, port.width.msb.left.name, 3, -2))
    return new_port
예제 #6
0
파일: core.py 프로젝트: mfkiwl/tapa
    def _connect_fifos(self, task: Task) -> None:
        _logger.debug("  connecting %s's children tasks", task.name)
        for fifo_name, fifo in task.fifos.items():
            directions = {
                'consumed_by': rtl.ISTREAM_SUFFIXES,
                'produced_by': rtl.OSTREAM_SUFFIXES
            }

            for direction, suffixes in directions.items():
                # skip if not in this direction
                if direction not in fifo:
                    continue

                task_name, _, fifo_port = task.get_fifo_port(
                    fifo_name, direction)
                child_ports = self.get_task(task_name).module.ports

                for suffix in suffixes:
                    # declare wires for FIFOs
                    wire_name = rtl.wire_name(fifo_name, suffix)
                    wire_width = child_ports[rtl.fifo_port_name(
                        fifo_port, suffix)].width
                    wire = ast.Wire(name=wire_name, width=wire_width)
                    task.module.add_signals([wire])

                    # if this FIFO is not declared, connect it directly to ports
                    if 'depth' not in fifo:
                        port_name = rtl.fifo_port_name(fifo_name, suffix)
                        port_direction = rtl.STREAM_PORT_DIRECTION[suffix]
                        if port_direction == 'input':
                            task.module.add_logics([
                                ast.Assign(left=ast.Identifier(wire_name),
                                           right=ast.Identifier(port_name))
                            ])
                        elif port_direction == 'output':
                            task.module.add_logics([
                                ast.Assign(left=ast.Identifier(port_name),
                                           right=ast.Identifier(wire_name))
                            ])
예제 #7
0
 def __init__(self, name: str, level: int, width: Optional[int] = None):
     self.level = level
     self._ids = tuple(
         ast.Identifier(f'{name}__q%d' % i) for i in range(level + 1))
     self._width: Optional[ast.Width] = width and ast.make_width(width)
예제 #8
0
파일: instance.py 프로젝트: dotkrnl/tapa
 def ready(self) -> ast.Identifier:
     """Whether this isntance is ready to take new input."""
     return ast.Identifier(f'{self.name}__{rtl.HANDSHAKE_READY}')
예제 #9
0
파일: instance.py 프로젝트: dotkrnl/tapa
 def idle(self) -> ast.Identifier:
     """Whether this isntance is idle."""
     return ast.Identifier(f'{self.name}__{rtl.HANDSHAKE_IDLE}')
예제 #10
0
파일: instance.py 프로젝트: dotkrnl/tapa
 def is_done(self) -> ast.Identifier:
     """Signal used to determine the upper-level state."""
     return ast.Identifier(f'{self.name}__is_done')
예제 #11
0
파일: instance.py 프로젝트: dotkrnl/tapa
 def rst_n(self) -> ast.Identifier:
     """The handshake synchronous active-low reset signal."""
     return ast.Identifier(f'{self.name}__{rtl.HANDSHAKE_RST_N}')
예제 #12
0
파일: instance.py 프로젝트: dotkrnl/tapa
 def state(self) -> ast.Identifier:
     """State of this instance."""
     return ast.Identifier(f'{self.name}__state')
예제 #13
0
파일: core.py 프로젝트: Blaok/tapa
    def _instantiate_global_fsm(
        self,
        task: Task,
        is_done_signals: List[rtl.Pipeline],
    ) -> None:
        # global state machine

        def is_state(state: ast.IntConst) -> ast.Eq:
            return ast.Eq(left=rtl.STATE, right=state)

        def set_state(state: ast.IntConst) -> ast.NonblockingSubstitution:
            return ast.NonblockingSubstitution(left=rtl.STATE, right=state)

        countdown = ast.Identifier('countdown')
        countdown_width = (self.register_level - 1).bit_length()

        task.module.add_signals([
            ast.Reg(rtl.STATE.name, width=ast.make_width(2)),
            ast.Reg(countdown.name, width=ast.make_width(countdown_width)),
        ])

        state01_action = set_state(STATE10)
        if is_done_signals:
            state01_action = ast.make_if_with_block(
                cond=ast.make_operation(
                    operator=ast.Land,
                    nodes=(x[-1] for x in reversed(is_done_signals)),
                ),
                true=state01_action,
            )

        global_fsm = ast.make_case_with_block(
            comp=rtl.STATE,
            cases=[
                (
                    STATE00,
                    ast.make_if_with_block(
                        cond=self.start_q[-1],
                        true=set_state(STATE01),
                    ),
                ),
                (
                    STATE01,
                    state01_action,
                ),
                (
                    STATE10,
                    [
                        set_state(STATE11 if self.register_level else STATE00),
                        ast.NonblockingSubstitution(
                            left=countdown,
                            right=ast.make_int(max(0,
                                                   self.register_level - 1)),
                        ),
                    ],
                ),
                (
                    STATE11,
                    ast.make_if_with_block(
                        cond=ast.Eq(
                            left=countdown,
                            right=ast.make_int(0, width=countdown_width),
                        ),
                        true=set_state(STATE00),
                        false=ast.NonblockingSubstitution(
                            left=countdown,
                            right=ast.Minus(
                                left=countdown,
                                right=ast.make_int(1, width=countdown_width),
                            ),
                        ),
                    ),
                ),
            ],
        )

        task.module.add_logics([
            ast.Always(
                sens_list=rtl.CLK_SENS_LIST,
                statement=ast.make_block(
                    ast.make_if_with_block(
                        cond=rtl.RST,
                        true=set_state(STATE00),
                        false=global_fsm,
                    )),
            ),
            ast.Assign(left=rtl.IDLE, right=is_state(STATE00)),
            ast.Assign(left=rtl.DONE, right=self.done_q[-1]),
            ast.Assign(left=rtl.READY, right=self.done_q[0]),
        ])

        task.module.add_pipeline(self.start_q, init=rtl.START)
        task.module.add_pipeline(self.done_q, init=is_state(STATE10))
예제 #14
0
파일: core.py 프로젝트: Blaok/tapa
    def _instantiate_children_tasks(
        self,
        task: Task,
        width_table: Dict[str, int],
    ) -> List[ast.Identifier]:
        is_done_signals: List[rtl.Pipeline] = []
        arg_table: Dict[str, rtl.Pipeline] = {}
        async_mmap_args: Dict[Instance.Arg,
                              List[str]] = collections.OrderedDict()

        task.add_m_axi(width_table, self.tcl_files)

        for instance in task.instances:
            child_port_set = set(instance.task.module.ports)

            # add signal delcarations
            for arg in instance.args:
                if arg.cat not in {
                        Instance.Arg.Cat.ISTREAM,
                        Instance.Arg.Cat.OSTREAM,
                }:
                    width = 64  # 64-bit address
                    if arg.cat == Instance.Arg.Cat.SCALAR:
                        width = width_table.get(arg.name, 0)
                        if width == 0:
                            width = int(arg.name.split("'d")[0])
                    q = rtl.Pipeline(
                        name=instance.get_instance_arg(arg.name),
                        level=self.register_level,
                        width=width,
                    )
                    arg_table[arg.name] = q
                    task.module.add_pipeline(q, init=ast.Identifier(arg.name))

                # arg.name is the upper-level name
                # arg.port is the lower-level name

                # check which ports are used for async_mmap
                if arg.cat == Instance.Arg.Cat.ASYNC_MMAP:
                    for tag in rtl.ASYNC_MMAP_SUFFIXES:
                        if set(x.portname
                               for x in rtl.generate_async_mmap_ports(
                                   tag=tag,
                                   port=arg.port,
                                   arg=arg.name,
                                   instance=instance,
                               )) & child_port_set:
                            async_mmap_args.setdefault(arg, []).append(tag)

                # declare wires or forward async_mmap ports
                for tag in async_mmap_args.get(arg, []):
                    if task.is_upper and instance.task.is_lower:
                        task.module.add_signals(
                            rtl.generate_async_mmap_signals(
                                tag=tag,
                                arg=arg.mmap_name,
                                data_width=width_table[arg.name],
                            ))
                    else:
                        task.module.add_ports(
                            rtl.generate_async_mmap_ioports(
                                tag=tag,
                                arg=arg.name,
                                data_width=width_table[arg.name],
                            ))

            # add reset registers
            rst_q = rtl.Pipeline(instance.rst_n, level=self.register_level)
            task.module.add_pipeline(rst_q, init=rtl.RST_N)

            # add start registers
            start_q = rtl.Pipeline(
                f'{instance.start.name}_global',
                level=self.register_level,
            )
            task.module.add_pipeline(start_q, self.start_q[0])

            if instance.is_autorun:
                # autorun modules start when the global start signal is asserted
                task.module.add_logics([
                    ast.Always(
                        sens_list=rtl.CLK_SENS_LIST,
                        statement=ast.make_block(
                            ast.make_if_with_block(
                                cond=ast.Unot(rst_q[-1]),
                                true=ast.NonblockingSubstitution(
                                    left=instance.start,
                                    right=rtl.FALSE,
                                ),
                                false=ast.make_if_with_block(
                                    cond=start_q[-1],
                                    true=ast.NonblockingSubstitution(
                                        left=instance.start,
                                        right=rtl.TRUE,
                                    ),
                                ),
                            )),
                    ),
                ])
            else:
                # set up state
                is_done_q = rtl.Pipeline(
                    f'{instance.is_done.name}',
                    level=self.register_level,
                )
                done_q = rtl.Pipeline(
                    f'{instance.done.name}_global',
                    level=self.register_level,
                )
                task.module.add_pipeline(is_done_q, instance.is_state(STATE10))
                task.module.add_pipeline(done_q, self.done_q[0])

                if_branch = (instance.set_state(STATE00))
                else_branch = ((
                    ast.make_if_with_block(
                        cond=instance.is_state(STATE00),
                        true=ast.make_if_with_block(
                            cond=start_q[-1],
                            true=instance.set_state(STATE01),
                        ),
                    ),
                    ast.make_if_with_block(
                        cond=instance.is_state(STATE01),
                        true=ast.make_if_with_block(
                            cond=instance.ready,
                            true=ast.make_if_with_block(
                                cond=instance.done,
                                true=instance.set_state(STATE10),
                                false=instance.set_state(STATE11),
                            )),
                    ),
                    ast.make_if_with_block(
                        cond=instance.is_state(STATE11),
                        true=ast.make_if_with_block(
                            cond=instance.done,
                            true=instance.set_state(STATE10),
                        ),
                    ),
                    ast.make_if_with_block(
                        cond=instance.is_state(STATE10),
                        true=ast.make_if_with_block(
                            cond=done_q[-1],
                            true=instance.set_state(STATE00),
                        ),
                    ),
                ))
                task.module.add_logics([
                    ast.Always(
                        sens_list=rtl.CLK_SENS_LIST,
                        statement=ast.make_block(
                            ast.make_if_with_block(
                                cond=ast.Unot(rst_q[-1]),
                                true=if_branch,
                                false=else_branch,
                            )),
                    ),
                    ast.Assign(
                        left=instance.start,
                        right=instance.is_state(STATE01),
                    ),
                ])

                is_done_signals.append(is_done_q)

            # insert handshake signals
            task.module.add_signals(instance.handshake_signals)

            # add task module instances
            portargs = list(rtl.generate_handshake_ports(instance, rst_q))
            for arg in instance.args:
                if arg.cat == Instance.Arg.Cat.SCALAR:
                    portargs.append(
                        ast.PortArg(portname=arg.port,
                                    argname=arg_table[arg.name][-1]))
                elif arg.cat == Instance.Arg.Cat.ISTREAM:
                    portargs.extend(
                        instance.task.module.generate_istream_ports(
                            port=arg.port,
                            arg=arg.name,
                        ))
                    portargs.extend(portarg
                                    for portarg in rtl.generate_peek_ports(
                                        rtl, port=arg.port, arg=arg.name)
                                    if portarg.portname in child_port_set)
                elif arg.cat == Instance.Arg.Cat.OSTREAM:
                    portargs.extend(
                        instance.task.module.generate_ostream_ports(
                            port=arg.port,
                            arg=arg.name,
                        ))
                elif arg.cat == Instance.Arg.Cat.MMAP:
                    portargs.extend(
                        rtl.generate_m_axi_ports(
                            module=instance.task.module,
                            port=arg.port,
                            arg=arg.mmap_name,
                            arg_reg=arg_table[arg.name][-1].name,
                        ))
                elif arg.cat == Instance.Arg.Cat.ASYNC_MMAP:
                    for tag in async_mmap_args[arg]:
                        portargs.extend(
                            rtl.generate_async_mmap_ports(
                                tag=tag,
                                port=arg.port,
                                arg=arg.mmap_name,
                                instance=instance,
                            ))

            task.module.add_instance(
                module_name=util.get_module_name(instance.task.name),
                instance_name=instance.name,
                ports=portargs,
            )

        # instantiate async_mmap modules at the upper levels
        if task.is_upper:
            for arg in async_mmap_args:
                task.module.add_async_mmap_instance(
                    name=arg.mmap_name,
                    offset_name=arg_table[arg.name][-1],
                    tags=async_mmap_args[arg],
                    data_width=width_table[arg.name],
                )

        return is_done_signals
예제 #15
0
파일: core.py 프로젝트: Blaok/tapa
    def _instantiate_fifos(self, task: Task) -> None:
        _logger.debug('  instantiating FIFOs in %s', task.name)

        # skip instantiating if the fifo is not declared in this task
        fifos = {
            name: fifo
            for name, fifo in task.fifos.items() if 'depth' in fifo
        }
        if not fifos:
            return

        col_width = max(
            max(len(name), len(util.get_instance_name(fifo['consumed_by'])),
                len(util.get_instance_name(fifo['produced_by'])))
            for name, fifo in fifos.items())

        for fifo_name, fifo in fifos.items():
            _logger.debug('    instantiating %s.%s', task.name, fifo_name)

            # add FIFO instances
            task.module.add_fifo_instance(
                name=fifo_name,
                width=self._get_fifo_width(task, fifo_name),
                depth=fifo['depth'],
            )

            # print debugging info
            debugging_blocks = []
            fmtargs = {
                'fifo_prefix': '\\033[97m',
                'fifo_suffix': '\\033[0m',
                'task_prefix': '\\033[90m',
                'task_suffix': '\\033[0m',
            }
            for suffixes, fmt, fifo_tag in zip(
                (rtl.ISTREAM_SUFFIXES, rtl.OSTREAM_SUFFIXES),
                ('DEBUG: R: {fifo_prefix}{fifo:>{width}}{fifo_suffix} -> '
                 '{task_prefix}{task:<{width}}{task_suffix} %h',
                 'DEBUG: W: {task_prefix}{task:>{width}}{task_suffix} -> '
                 '{fifo_prefix}{fifo:<{width}}{fifo_suffix} %h'),
                ('consumed_by', 'produced_by')):
                display = ast.SingleStatement(statement=ast.SystemCall(
                    syscall='display',
                    args=(ast.StringConst(value=fmt.format(
                        width=col_width,
                        fifo=fifo_name,
                        task=(util.get_instance_name(fifo[fifo_tag])),
                        **fmtargs)),
                          ast.Identifier(
                              name=rtl.wire_name(fifo_name, suffixes[0])))))
                debugging_blocks.append(
                    ast.Always(
                        sens_list=rtl.CLK_SENS_LIST,
                        statement=ast.make_block(
                            ast.IfStatement(
                                cond=ast.Eq(
                                    left=ast.Identifier(name=rtl.wire_name(
                                        fifo_name, suffixes[-1])),
                                    right=rtl.TRUE,
                                ),
                                true_statement=ast.make_block(display),
                                false_statement=None))))
            task.module.add_logics(debugging_blocks)
예제 #16
0
HANDSHAKE_READY = 'ap_ready'

HANDSHAKE_INPUT_PORTS = (
    HANDSHAKE_CLK,
    HANDSHAKE_RST_N,
    HANDSHAKE_START,
)
HANDSHAKE_OUTPUT_PORTS = (
    HANDSHAKE_DONE,
    HANDSHAKE_IDLE,
    HANDSHAKE_READY,
)

# const ast nodes

START = ast.Identifier(HANDSHAKE_START)
DONE = ast.Identifier(HANDSHAKE_DONE)
IDLE = ast.Identifier(HANDSHAKE_IDLE)
READY = ast.Identifier(HANDSHAKE_READY)
TRUE = ast.IntConst("1'b1")
FALSE = ast.IntConst("1'b0")
SENS_TYPE = 'posedge'
CLK = ast.Identifier(HANDSHAKE_CLK)
RST = ast.Identifier(HANDSHAKE_RST)
RST_N = ast.Identifier(HANDSHAKE_RST_N)
CLK_SENS_LIST = ast.SensList((ast.Sens(CLK, type=SENS_TYPE), ))
ALL_SENS_LIST = ast.SensList((ast.Sens(None, type='all'), ))
STATE = ast.Identifier('tapa_state')

BUILTIN_INSTANCES = {'hmss_0'}