From b296cbcde2bfdef6c8375f0b733199621a138eae Mon Sep 17 00:00:00 2001 From: Tim Callahan Date: Sat, 14 May 2022 15:41:42 -0700 Subject: [PATCH 1/3] Scripts for plotting ice40 placement. Signed-off-by: Tim Callahan --- scripts/critpath.py | 119 ++++++++++++++++++++++++++++++++++++++ scripts/save-placement.py | 67 +++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100755 scripts/critpath.py create mode 100644 scripts/save-placement.py diff --git a/scripts/critpath.py b/scripts/critpath.py new file mode 100755 index 000000000..dd0933701 --- /dev/null +++ b/scripts/critpath.py @@ -0,0 +1,119 @@ +#!/bin/bash +# Copyright 2022 The CFU-Playground Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# Display color-coded floowplan and critical path, +# using data files written by nextpnr. +# Currently the critical path display is disabled +# since it hasn't been tested with ice40. +# + + + +import json +import matplotlib.pyplot as plt +import matplotlib.patches as mpatches +import random + +fig, ax = plt.subplots(dpi=200) + +# read placement file +with open('placement_data.txt', 'r') as pfile: + placement_data=pfile.readlines() + +if False: + # read critical path file + with open('hps_proto2_platform-report.json', 'r') as myfile: + data=myfile.read() + + # parse file + obj = json.loads(data) + + # assume first CP is the one we're interested in (maybe print out from/to clk domains) + cp = obj['critical_paths'][0]['path'] + #print(cp) + + accum = {} + accum['logic'] = 0.0 + accum['routing'] = 0.0 + accum['clk-to-q'] = 0.0 + accum['setup'] = 0.0 + +# plot placement data first +for line in placement_data: + if 'KEY' in line: + continue + [type,x,y,color]=line.rstrip().split(' ') + x = int(x) + y = int(y) + if type == 'small': + rx = random.uniform(0,0.7) + ry = random.uniform(0,0.7) + ax.add_patch(mpatches.Rectangle( + [x+rx, y+ry], 0.1, 0.1, + color=color, fill=True)) + if type == 'med': + ax.add_patch(mpatches.Rectangle( + [x, y-0.2], 1.6, 1.6, + color=color, ec='white', fill=True)) + if type == 'circle': + ax.add_patch(mpatches.Circle( + [x, y+0.5], 0.7, + color=color, ec='white', fill=True)) + +ax.set_aspect('equal') +ax.autoscale_view() + + +if 'cp' in locals(): + xs = [] + ys = [] + for hop in cp: + dtype = hop['type'] + accum[dtype] += hop['delay'] + fromcell = hop['from']['cell'] + tocell = hop['to']['cell'] + delay = "%.3f" % hop['delay'] + fromloc = hop['from']['loc'] + toloc = hop['to']['loc'] + floc = str(fromloc[0]) + ":" + str(fromloc[1]) + tloc = str(toloc[0]) + ":" + str(toloc[1]) + if toloc != fromloc: + xs.append(fromloc[0]) + ys.append(fromloc[1]) + xs.append(toloc[0]) + ys.append(toloc[1]) + if 'clk' in dtype: + print(f"from {tloc} {tocell} {dtype} --> {delay} ->") + else: + print(f"from {floc} {fromcell} {dtype} --> {delay} ->") + + plt.plot(xs, ys, marker='x', linewidth=3, color='black', label=delay) + + for k,v in accum.items(): + delay = "%.2f" % v + print(f"total {k}: {delay}") + +for line in placement_data: + if 'KEY' in line: + print(line.rstrip()) +print("KEY Multiplier Circle") +print("KEY Memory Square") + +plt.xlim([0, 27]) +plt.ylim([0, 32]) +plt.show() +plt.savefig("critpath.png", format="png", dpi=300) +print("Done writing critical path image.\n") diff --git a/scripts/save-placement.py b/scripts/save-placement.py new file mode 100644 index 000000000..aa04a7b2f --- /dev/null +++ b/scripts/save-placement.py @@ -0,0 +1,67 @@ +#!/bin/bash +# Copyright 2022 The CFU-Playground Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# When executed by nextpnr-ice40 using the "--pre-route" option, +# this saves placement data in a file "placement_data.txt". + + +import sys + +print("\nSaving placement data...\n") + +COLOR_TABLE = [ + ('Vex', 'gray'), + ('Cfu', 'seagreen'), + ('litespi', 'blue'), + ('cdcusbphy', 'red'), + ('_usb_', 'red'), +] + +with open('placement_data.txt', 'w') as f: + for cell, cellinfo in ctx.cells: + if cellinfo.bel: + bel = cellinfo.bel + #print(cell, file=f) + #print(bel, file=f) + loc = ctx.getBelLocation(bel) + x = int(loc.x) + y = int(loc.y) + + color = 'black' + for match, c in COLOR_TABLE: + if match in cell: + color = c + + mul = "DSP" in cell + ebr = "/ram" in bel + + # Set color for LRAMs + lram = "spram_" in bel + color= 'tan' if lram else color + + if mul: + print(f"circle {x} {y} {color}", file=f) + elif ebr or lram: + print(f"med {x} {y} {color}", file=f) + else: + print(f"small {x} {y} {color}", file=f) + + for i, (match, c) in enumerate(COLOR_TABLE): + print(f"KEY {match} {c}", file=f) + print("KEY LiteX black", file=f) + +print("\nDone\n") + +sys.exit() From 891e79f1db013d2cad627f6ee88f50bc4e3a66f7 Mon Sep 17 00:00:00 2001 From: Tim Callahan Date: Thu, 19 May 2022 23:37:16 -0700 Subject: [PATCH 2/3] Update ice40 plotting scripts & invoke from ice40 flow. Signed-off-by: Tim Callahan --- scripts/critpath.py | 10 ++++++---- scripts/save-placement.py | 4 ++-- soc/board_specific_workflows/ice40up5k.py | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) mode change 100644 => 100755 scripts/save-placement.py diff --git a/scripts/critpath.py b/scripts/critpath.py index dd0933701..18788162d 100755 --- a/scripts/critpath.py +++ b/scripts/critpath.py @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env python3 # Copyright 2022 The CFU-Playground Authors # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,9 +33,9 @@ with open('placement_data.txt', 'r') as pfile: placement_data=pfile.readlines() -if False: +if True: # read critical path file - with open('hps_proto2_platform-report.json', 'r') as myfile: + with open('kosagi_fomu_pvt-report.json', 'r') as myfile: data=myfile.read() # parse file @@ -102,10 +102,12 @@ plt.plot(xs, ys, marker='x', linewidth=3, color='black', label=delay) + print(""); for k,v in accum.items(): delay = "%.2f" % v print(f"total {k}: {delay}") +print(""); for line in placement_data: if 'KEY' in line: print(line.rstrip()) @@ -114,6 +116,6 @@ plt.xlim([0, 27]) plt.ylim([0, 32]) -plt.show() +# plt.show() plt.savefig("critpath.png", format="png", dpi=300) print("Done writing critical path image.\n") diff --git a/scripts/save-placement.py b/scripts/save-placement.py old mode 100644 new mode 100755 index aa04a7b2f..d0b8a4f7d --- a/scripts/save-placement.py +++ b/scripts/save-placement.py @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env python3 # Copyright 2022 The CFU-Playground Authors # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -64,4 +64,4 @@ print("\nDone\n") -sys.exit() +# sys.exit() diff --git a/soc/board_specific_workflows/ice40up5k.py b/soc/board_specific_workflows/ice40up5k.py index a0960cdbe..f713b3531 100644 --- a/soc/board_specific_workflows/ice40up5k.py +++ b/soc/board_specific_workflows/ice40up5k.py @@ -23,6 +23,16 @@ from typing import Callable +_ice40_placement_build_template = [ + "yosys -l {build_name}.rpt {build_name}.ys", + "nextpnr-ice40 --json {build_name}.json --pcf {build_name}.pcf --asc {build_name}.txt \ + --pre-route ../../../../scripts/save-placement.py \ + --report={build_name}-report.json \ + --pre-pack {build_name}_pre_pack.py --{architecture} --package {package} {timefailarg} {ignoreloops} --seed {seed}", + "icepack -s {build_name}.txt {build_name}.bin", + "critpath.py > critpath.log" +] + class Ice40UP5KWorkflow(general.GeneralSoCWorkflow): """Workflow for boards derived from the Ice40UP5K. @@ -64,6 +74,10 @@ def make_soc(self, **kwargs) -> litex_soc.LiteXSoC: soc.bus.regions["sram"].size = 128 * 1024; soc.bus.regions["main_ram"].origin = 128 * 1024; soc.bus.regions["main_ram"].size = 0; + + # add scripts for plotting placement + soc.platform.toolchain.build_template = _ice40_placement_build_template + return soc def software_load( From 81bd24753a2926ad4ca5fae82b04a89b73bbfd8a Mon Sep 17 00:00:00 2001 From: Tim Callahan Date: Fri, 20 May 2022 12:47:02 -0700 Subject: [PATCH 3/3] Add matplotlib to Python requirements.txt. Signed-off-by: Tim Callahan --- conf/requirements-symbiflow.txt | 1 + conf/requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/conf/requirements-symbiflow.txt b/conf/requirements-symbiflow.txt index 8192f5036..1fa074d05 100644 --- a/conf/requirements-symbiflow.txt +++ b/conf/requirements-symbiflow.txt @@ -20,5 +20,6 @@ sympy textx python-constraint fasm +matplotlib git+https://github.com/SymbiFlow/prjxray.git@e25c20a8f158cc5e94eb62e3b74e16fc9d6c1d26#egg=prjxray git+https://github.com/symbiflow/xc-fasm.git@14afc2bae24cbf6ee5e7d057a58b4cbd776358d0#egg=xc-fasm diff --git a/conf/requirements.txt b/conf/requirements.txt index 762727573..d7f4865e0 100644 --- a/conf/requirements.txt +++ b/conf/requirements.txt @@ -7,3 +7,4 @@ meson Pillow six Wave +matplotlib