| #!/usr/bin/env python3 |
| """ |
| This utility script allows to visualize VPR placement. It reads a VPR .place |
| file and generates a bitmap with the visualization. |
| """ |
| import argparse |
| import re |
| import itertools |
| |
| from PIL import Image, ImageDraw |
| |
| # ============================================================================= |
| |
| |
| def load_placement(placement_file): |
| """ |
| Loads VPR placement file. Returns a tuple with the grid size and a dict |
| indexed by locations that contains top-level block names. |
| """ |
| |
| RE_PLACEMENT = re.compile( |
| r"^\s*(?P<net>\S+)\s+(?P<x>[0-9]+)\s+(?P<y>[0-9]+)\s+(?P<z>[0-9]+)" |
| ) |
| |
| RE_GRID_SIZE = re.compile( |
| r"Array size:\s+(?P<x>[0-9]+)\s+x\s+(?P<y>[0-9]+)\s+logic blocks" |
| ) |
| |
| # Load the file |
| with open(placement_file, "r") as fp: |
| lines = fp.readlines() |
| |
| # Parse |
| grid_size = None |
| placement = {} |
| |
| for line in lines: |
| line = line.strip() |
| |
| if line.startswith("#"): |
| continue |
| |
| # Placement |
| match = RE_PLACEMENT.match(line) |
| if match is not None: |
| |
| loc = (int(match.group("x")), int(match.group("y"))) |
| |
| placement[loc] = match.group("net") |
| |
| # Grid size |
| match = RE_GRID_SIZE.match(line) |
| if match is not None: |
| |
| grid_size = (int(match.group("x")), int(match.group("y"))) |
| |
| return grid_size, placement |
| |
| |
| def generate_image(grid_size, placement, block_size=8, colormap=None): |
| """ |
| Generates a visualization of the placement. |
| """ |
| |
| block_size = max(block_size, 3) |
| gap_size = 1 |
| cell_size = block_size + 2 * gap_size |
| |
| # Create new image |
| dx = grid_size[0] * cell_size + 1 |
| dy = grid_size[1] * cell_size + 1 |
| image = Image.new("RGB", (dx, dy), color="#FFFFFF") |
| |
| # Draw stuff |
| draw = ImageDraw.Draw(image) |
| for cx, cy in itertools.product(range(grid_size[0]), range(grid_size[1])): |
| |
| x0 = cx * cell_size + gap_size |
| y0 = cy * cell_size + gap_size |
| x1 = x0 + block_size |
| y1 = y0 + block_size |
| |
| if (cx, cy) in placement: |
| name = placement[(cx, cy)] |
| if colormap is not None and name in colormap: |
| color = colormap[name] |
| else: |
| color = "#2080C0" |
| else: |
| color = "#FFFFFF" |
| |
| draw.rectangle((x0, y0, x1, y1), color, "#000000") |
| |
| return image |
| |
| |
| # ============================================================================= |
| |
| |
| def main(): |
| |
| # Parse arguments |
| parser = argparse.ArgumentParser( |
| description=__doc__, |
| formatter_class=argparse.RawDescriptionHelpFormatter |
| ) |
| |
| parser.add_argument("place", type=str, help="A VPR .place file") |
| |
| parser.add_argument( |
| "-o", type=str, default="placement.png", help="Output image file" |
| ) |
| |
| parser.add_argument( |
| "--block-size", type=int, default=4, help="Block size (def. 4)" |
| ) |
| |
| args = parser.parse_args() |
| |
| # Load placement |
| grid_size, placement = load_placement(args.place) |
| |
| # Colormap |
| colormap = { |
| "$true": "#C02020", |
| "$false": "#000000", |
| } |
| |
| # Generate the image |
| image = generate_image(grid_size, placement, args.block_size, colormap) |
| image.save(args.o) |
| |
| |
| # ============================================================================= |
| |
| if __name__ == "__main__": |
| main() |