Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions bazel/tapa_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ def _tapa_xo_impl(ctx):
# Build the command for tapa-cli synth.
tapa_cmd.extend(["synth"])

# Add floorplan path, if specified.
if ctx.file.floorplan_path:
tapa_cmd.extend(["--floorplan-path", ctx.file.floorplan_path.path])

# Add floorplan config, if specified.
if ctx.file.floorplan_config:
tapa_cmd.extend(["--floorplan-config", ctx.file.floorplan_config.path])

# Add device config path, if specified.
if ctx.file.device_config:
tapa_cmd.extend(["--device-config", ctx.file.device_config.path])

# Redact report schema version for better cache hit.
tapa_cmd.extend(["--override-report-schema-version", "redacted"])

Expand Down Expand Up @@ -106,6 +118,10 @@ def _tapa_xo_impl(ctx):
inputs = [src] + ctx.files.hdrs + ctx.files.custom_rtl_files
if ctx.file.floorplan_path:
inputs.append(ctx.file.floorplan_path)
if ctx.file.floorplan_config:
inputs.append(ctx.file.floorplan_config)
if ctx.file.device_config:
inputs.append(ctx.file.device_config)
ctx.actions.run(
outputs = outputs,
inputs = inputs,
Expand Down Expand Up @@ -159,6 +175,8 @@ tapa_xo = rule(
"gen_ab_graph": attr.bool(),
"flatten_hierarchy": attr.bool(),
"floorplan_path": attr.label(allow_single_file = True),
"floorplan_config": attr.label(allow_single_file = True),
"device_config": attr.label(allow_single_file = True),
"vitis_hls_env": attr.label(
cfg = "exec",
default = Label("//bazel:vitis_hls_env"),
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ those contributing to or extending the TAPA framework itself.
tutorial/mini_example
tutorial/realworld_example
tutorial/custom_rtl
tutorial/floorplan_dse_compile

.. toctree::
:caption: Reference
Expand Down
94 changes: 94 additions & 0 deletions docs/tutorial/floorplan_dse_compile.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
Run TAPA Projects With Floorplan DSE
====================================

.. note::

In this tutorial, we explore how to compile a tapa project with floorplan design space exploration (DSE) and add pipeline to the project.

Example: Compile Autosa with Floorplan DSE
------------------------------------------

The following example demonstrates how to compile a TAPA project with floorplan DSE.
You can use the ``tapa generate-floorplan`` command to run the floorplan DSE and get floorplan
solutions.

.. code-block:: bash

tapa generate-floorplan \
-f tapa/src/kernel_kernel.cpp \
-t kernel0 \
--device-config device_config.json \
--floorplan-config floorplan_config.json \
--clock-period 3.00 \
--part-num xcu55c-fsvh2892-2L-e

After generating the floorplan solutions, you can compile the project with a specific
floorplan solution with the ``tapa compile`` command by specifying the ``--floorplan-path`` option.
The application will be reorganized according to the floorplan solution, and pipeline
will be added. An xo file and floorplan constrain xdc file will be generated.

.. code-block:: bash

tapa compile \
-f tapa/src/kernel_kernel.cpp \
-t kernel0 \
--device-config device_config.json \
--floorplan-path floorplan_0.json \
--clock-period 3.00 \
--part-num xcu55c-fsvh2892-2L-e \
--pipeline-config pipeline_config.json

Alternatively, you can use the ``tapa compile-with-floorplan-dse`` command to compile the project
with floorplan DSE directly. This command will automatically run the floorplan DSE, compile,
and add pipeline to the project for each floorplan solution generated.

.. code-block:: bash

tapa compile-with-floorplan-dse \
-f tapa/src/kernel_kernel.cpp \
-t kernel0 \
--device-config device_config.json \
--floorplan-config floorplan_config.json \
--clock-period 3.00 \
--part-num xcu55c-fsvh2892-2L-e \
--pipeline-config pipeline_config.json

The ``--floorplan-config`` option specifies the floorplan DSE configuration file.
An example of a floorplan DSE configuration file is as follows:

.. code-block:: json

{
"max_seconds": 1000,
"dse_range_min": 0.7,
"dse_range_max": 0.88,
"partition_strategy": "flat",
"cell_pre_assignments": {},
"cpp_arg_pre_assignments": {
"a": "SLOT_X1Y0:SLOT_X1Y0",
"b_0": "SLOT_X2Y0:SLOT_X2Y0",
"b_1": "SLOT_X2Y0:SLOT_X2Y0",
"c_.*": "SLOT_X2Y0:SLOT_X2Y0"
},
"sys_port_pre_assignments": {
"ap_clk": "SLOT_X2Y0:SLOT_X2Y0",
"ap_rst_n": "SLOT_X2Y0:SLOT_X2Y0",
"interrupt": "SLOT_X2Y0:SLOT_X2Y0",
"s_axi_control_.*": "SLOT_X2Y1:SLOT_X2Y1"
},
"grouping_constraints": [],
"reserved_slot_to_cells": {},
"partition_schedule": [],
"slot_to_rtype_to_min_limit": {
"SLOT_X0Y2:SLOT_X0Y2": {
"LUT": 0.85
}
},
"slot_to_rtype_to_max_limit": {},
"ignore_narrow_edge_threshold": 1
}

The ``cpp_arg_pre_assignments`` field specifies the pre-assignments of the C++ top function
arguments to the slots. If the top port is an array, you can either specify each element
individually or use a regex pattern to match the elements. ``sys_port_pre_assignments`` specifies
the pre-assignments of the verilog system ports to the slots.
5 changes: 4 additions & 1 deletion tapa/abgraph/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,8 @@ py_library(
py_doc_test(
name = "abgraph_doc_test",
package = "tapa.abgraph",
deps = ["//tapa/abgraph"],
deps = [
"//tapa/abgraph",
"//tapa/steps",
],
)
56 changes: 43 additions & 13 deletions tapa/abgraph/gen_abgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,36 @@
RapidStream Contributor License Agreement.
"""

import json
import logging
import re
from pathlib import Path

from tapa.abgraph.ab_graph import ABEdge, ABGraph, ABVertex, Area, convert_area
from tapa.core import Program
from tapa.steps.floorplan import convert_region_format
from tapa.util import as_type
from tapa.verilog.xilinx.module import get_streams_fifos

TAPA_PORT_PREFIX = "__tapa_port_"

MMAP_WIDTH = (405, 43)

_logger = logging.getLogger().getChild(__name__)

def get_top_level_ab_graph(program: Program) -> ABGraph:

def get_top_level_ab_graph(program: Program, floorplan_config: Path) -> ABGraph:
"""Generates the top level ab graph."""
with open(floorplan_config, encoding="utf-8") as f:
floorplan_config_dict: dict = json.load(f)

task_area = collect_task_area(program)
fifo_width = collect_fifo_width(program)
port_width = collect_port_width(program)
graph = get_basic_ab_graph(program, task_area, fifo_width)
graph = add_port_iface_connections(program, graph, port_width)
graph = add_port_iface_connections(
program, graph, port_width, floorplan_config_dict["cpp_arg_pre_assignments"]
)
return add_scalar_connections(program, graph, port_width)


Expand Down Expand Up @@ -107,15 +118,13 @@ def replace_bracketed_number(s: str) -> str:
# each fifo has a producer and a consumer, but the fifo_inst only tells
# the task name, not the instance name. So we need to check all instances
# port connection to find the instance name.
consumer_task = fifo_inst["consumed_by"][0]
consumer_task_inst = program.get_inst_by_port_arg_name(
consumer_task, top, replace_bracketed_number(fifo_name)
).name
consumer_task_inst = (
f"{fifo_inst['consumed_by'][0]}_{fifo_inst['consumed_by'][1]}"
)

producer_task = fifo_inst["produced_by"][0]
producer_task_inst = program.get_inst_by_port_arg_name(
producer_task, top, replace_bracketed_number(fifo_name)
).name
producer_task_inst = (
f"{fifo_inst['produced_by'][0]}_{fifo_inst['produced_by'][1]}"
)

edges.append(
ABEdge(
Expand All @@ -129,8 +138,11 @@ def replace_bracketed_number(s: str) -> str:
return ABGraph(vs=list(vertices.values()), es=edges)


def add_port_iface_connections(
program: Program, graph: ABGraph, port_width: dict[str, int | tuple[int, int]]
def add_port_iface_connections( # noqa: C901
program: Program,
graph: ABGraph,
port_width: dict[str, int | tuple[int, int]],
cpp_arg_pre_assignments: dict[str, str],
) -> ABGraph:
"""Add port interface connections to the ab graph.

Expand All @@ -144,11 +156,29 @@ def add_port_iface_connections(
for port in top.ports.values():
if not (port.cat.is_stream or port.cat.is_mmap or port.is_streams):
continue

# find matching preassignment pattern
region = None
for pattern, current_region in cpp_arg_pre_assignments.items():
if re.fullmatch(pattern, port.name):
if region and region != current_region:
msg = (
f"Port {port.name} matches multiple preassignment patterns: "
f"{region} and {current_region}. "
"Please check your configuration."
)
raise ValueError(msg)
region = current_region

if not region:
msg = f"Port {port.name} does not match any preassignment pattern."
_logger.warning(msg)

dummy_vertex = ABVertex(
name=port.name,
area=Area(lut=0, ff=0, bram_18k=0, dsp=0, uram=0),
sub_cells=(port.name,),
target_slot=None,
target_slot=convert_region_format(region),
reserved_slot=None,
current_slot=None,
)
Expand Down
Loading