Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForceAllCarryPins #523

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5452bd5
Make sure all pins appear on carry4s in netlist
reillymck Feb 13, 2025
fe69458
Add is_const prop to nets
reillymck Feb 13, 2025
9709624
update compare flow build count
reillymck Feb 13, 2025
a4f9fc9
fix const logic
reillymck Feb 13, 2025
cdf10ad
change netlist_cleanup back to main
reillymck Feb 20, 2025
4d2fb04
Merge branch 'main' into mem_fix
reillymck Feb 20, 2025
4967137
Merge branch 'main' into mem_fix
yonnorc42 Feb 21, 2025
6fe7817
add full cleaning time to log
yonnorc42 Feb 21, 2025
3a3a8e2
pylint
yonnorc42 Feb 21, 2025
f5b01ee
add some more timing statements, memory dump, and update process_resu…
yonnorc42 Feb 21, 2025
feb6e82
add memory dump logic to structural.py and process_results.py
yonnorc42 Feb 24, 2025
05f3ca1
Merge branch 'main' into mem_fix
yonnorc42 Feb 24, 2025
3c625e8
pylint
yonnorc42 Feb 24, 2025
aba295f
Merge branch 'mem_fix' of github.com:byuccl/bfasst into mem_fix
yonnorc42 Feb 24, 2025
3240406
Merge branch 'main' into mem_fix
reillymck Feb 27, 2025
f7b75fe
format
reillymck Feb 27, 2025
fc41f46
utilize set comprehension, enumeration, and dump mem size of possible…
yonnorc42 Feb 28, 2025
38ae684
update logging and file dependency tree
reillymck Feb 28, 2025
08deaaa
Merge branch 'mem_fix' of github.com:byuccl/bfasst into mem_fix
reillymck Feb 28, 2025
e926be6
fix bram cascade parse
reillymck Feb 28, 2025
cabcb1b
format
reillymck Feb 28, 2025
052d2da
Output physical interchange file of phy netlist
reillymck Mar 3, 2025
d8841c8
format
reillymck Mar 3, 2025
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
2 changes: 2 additions & 0 deletions bfasst/tools/compare/structural/structural.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ def _init_outputs(self):
def add_ninja_deps(self, deps):
self._add_ninja_deps_default(deps, __file__)
deps.append(BFASST_UTILS_PATH / "structural.py")
deps.append(BFASST_UTILS_PATH / "structural_helpers.py")
deps.append(BFASST_UTILS_PATH / "sdn_helpers.py")
1 change: 1 addition & 0 deletions bfasst/tools/transform/phys_netlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,5 @@ def _init_outputs(self):
def add_ninja_deps(self, deps):
self._add_ninja_deps_default(deps, __file__)
deps.append(BFASST_UTILS_PATH / "rw_phys_netlist.py")
deps.append(BFASST_UTILS_PATH / "rw_helpers.py")
deps.append(NINJA_TRANSFORM_TOOLS_PATH / "checkpoint_to_v.tcl.mustache")
19 changes: 19 additions & 0 deletions bfasst/utils/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,22 @@ def get_family_from_part(part):
will have to be changed if we start supporting more part families
"""
return "kintex7" if part[3] == "k" else "artix7"


def get_size(obj, seen=None):
"""Recursively finds size of objects using generators."""
size = sys.getsizeof(obj)
if seen is None:
seen = set()
obj_id = id(obj)
if obj_id in seen:
return 0
seen.add(obj_id)
if isinstance(obj, dict):
size += sum(get_size(v, seen) for v in obj.values())
size += sum(get_size(k, seen) for k in obj.keys())
elif hasattr(obj, "__dict__"):
size += get_size(obj.__dict__, seen)
elif hasattr(obj, "__iter__") and not isinstance(obj, (str, bytes, bytearray)):
size += sum(get_size(i, seen) for i in obj)
return size
5 changes: 5 additions & 0 deletions bfasst/utils/netlist_cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def __init__(self, build_path, netlist_in_path, netlist_out_path, logging_level)

self.log_path = self.build_path / "log.txt"
self.log_path.unlink(missing_ok=True)
self.start_time = time.perf_counter()
self.cleanup_time_log = self.build_path / "cleanup_time.txt"

logging.basicConfig(
filename=self.log_path,
Expand Down Expand Up @@ -97,6 +99,9 @@ def write_netlist(self, netlist_ir):
t_begin = time.perf_counter()
sdn.compose(netlist_ir, self.netlist_out, write_blackbox=False)
logging.info("Total time to write out netlist: %s", time.perf_counter() - t_begin)
logging.info("Total time to clean netlist: %s", time.perf_counter() - self.start_time)
with open(self.cleanup_time_log, "w") as f:
f.write(f"{time.perf_counter() - self.start_time}\n")


if __name__ == "__main__":
Expand Down
29 changes: 26 additions & 3 deletions bfasst/utils/rw_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,7 @@ def remove_and_disconnect_cell(cell, log=logging.info):


def lut_move_net_to_new_cell(
old_edif_cell_inst,
new_edif_cell_inst,
edif_cell_insts,
old_logical_pin,
physical_pin,
log=logging.info,
Expand All @@ -225,6 +224,8 @@ def lut_move_net_to_new_cell(

log(f" Processing logical pin {old_logical_pin}, physical pin {physical_pin}")

old_edif_cell_inst, new_edif_cell_inst = edif_cell_insts

port_inst = old_edif_cell_inst.getPortInst(old_logical_pin)
logical_net = port_inst.getNet()
assert logical_net
Expand Down Expand Up @@ -468,11 +469,33 @@ def cell_is_default_mapping(self, cell):
l2p = cell.getPinMappingsL2P()
for logical, physical in default_l2p_map.items():
if logical in l2p and list(l2p[logical]) != [physical]:
print(list(l2p[logical]), "<>", [physical])
logging.warning(list(l2p[logical]), "<>", [physical])
return False

return True

def ensure_connected(self, edif_cell_inst, net, log=logging.info):
"""
Ensure that all ports on the cell are connected to the net.

Sometimes Vivado leaves ports undriven, which can cause the port to not be
explicitly shown in the verilog netlist. This can cause issues since
spydrnet will not infer ground for these signals. Use this function to make
sure all ports are shown by connecting them.
"""

type_name = edif_cell_inst.getCellType().getName()
port_names = self.CELL_PIN_MAP[type_name]

for phys_name, log_name in port_names.items():
port = edif_cell_inst.getPortInst(phys_name)
if port is None:
log(
f" Port {phys_name} not found on {edif_cell_inst.getName()}, connecting to net"
)
new_port = edif_cell_inst.getPort(log_name)
net.createPortInst(new_port, edif_cell_inst)


class _PinMap(MutableMapping):
"""
Expand Down
67 changes: 41 additions & 26 deletions bfasst/utils/rw_phys_netlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from com.xilinx.rapidwright.device import SiteTypeEnum
from com.xilinx.rapidwright.design import Design, Unisim
from com.xilinx.rapidwright.edif import EDIFNet, EDIFPropertyValue, EDIFValueType
from com.xilinx.rapidwright.interchange import LogNetlistWriter
from com.xilinx.rapidwright.interchange import LogNetlistWriter, PhysNetlistWriter
from java.lang import System
from java.io import PrintStream, File

Expand Down Expand Up @@ -252,6 +252,13 @@ def __run_rapidwright(
LogNetlistWriter.writeLogNetlist(
self.rw_netlist, str(self.stage_dir / "phys_logical_netlist.capnp")
)
logging.info(
"Writing capnp interchange physical netlist: %s",
str(self.stage_dir / "phys_physical_netlist.capnp"),
)
PhysNetlistWriter.writePhysNetlist(
self.rw_design, str(self.stage_dir / "phys_physical_netlist.capnp")
)

def __process_all_luts(self, cells_already_visited):
"""Visit all LUTs and replace them with LUT6_2 instances"""
Expand All @@ -269,7 +276,10 @@ def __process_all_luts(self, cells_already_visited):
lut5_cell = site_inst.getCell(lut5_bel)

gnd_luts = self.__check_lut_const_nets(
lut6_cell, lut6_pin_out, lut5_cell, lut5_pin_out, gnd_nets, vcc_nets, site_inst
(lut6_cell, lut6_pin_out),
(lut5_cell, lut5_pin_out),
(gnd_nets, vcc_nets),
site_inst,
)
if gnd_luts:
cells_already_visited.update(gnd_luts)
Expand Down Expand Up @@ -334,43 +344,47 @@ def __check_lutram_srl(self, lut6_cell, lut5_cell, lut_rams, cells_already_visit
return True
return False

# pylint: disable=too-many-positional-arguments
def __check_lut_const_nets(
self, lut6_cell, lut6_pin_out, lut5_cell, lut5_pin_out, gnd_nets, vcc_nets, site_inst
):
def __check_lut_const_nets(self, lut6, lut5, const_nets, site_inst):
"""
Check if the LUT6 or LUT5 are connected to a const net
Covers O5/O6 being gnd
Covers O5/O6 being vcc
Covers one output being gnd and the other being vcc

lut6: Tuple (lut6_cell, lut6_pin_out)
lut5: Tuple (lut5_cell, lut5_pin_out)
const_nets: Tuple (gnd_nets, vcc_nets)
"""

gnd_nets, vcc_nets = const_nets

const_generator_pins = [None, None]
pin1_gnd = None
pin2_gnd = None
for is_gnd, const_net in ((True, gnd_nets), (False, vcc_nets)):
if lut6_pin_out in const_net:
if lut6[1] in const_net:
# If a gnd net, then there can't be a cell there
assert lut6_cell is None
if lut5_cell is not None:
self.__process_lut5_and_const_lut(lut5_cell, lut6_pin_out, site_inst, is_gnd)
assert lut6[0] is None
if lut5[0] is not None:
self.__process_lut5_and_const_lut(lut5[0], lut6[1], site_inst, is_gnd)
return {
lut5_cell,
lut5[0],
}
assert const_generator_pins[0] is None
const_generator_pins[0] = lut6_pin_out
const_generator_pins[0] = lut6[1]
pin1_gnd = is_gnd

if lut5_pin_out in const_net:
if lut5[1] in const_net:
# If a gnd net, then there can't be a cell there
# This assumption is not true for LUTRAMs
assert lut5_cell is None
if lut6_cell is not None:
self.__process_lut5_and_const_lut(lut6_cell, lut5_pin_out, site_inst, is_gnd)
assert lut5[0] is None
if lut6[0] is not None:
self.__process_lut5_and_const_lut(lut6[0], lut5[1], site_inst, is_gnd)
return {
lut6_cell,
lut6[0],
}
assert const_generator_pins[1] is None
const_generator_pins[1] = lut5_pin_out
const_generator_pins[1] = lut5[1]
pin2_gnd = is_gnd

if const_generator_pins[0] is not None or const_generator_pins[1] is not None:
Expand Down Expand Up @@ -590,6 +604,8 @@ def __process_carry4(self, cell):
logging.info(" Inputs not permuted, skipping")
return []

rw.PinMap.ensure_connected(cell.getEDIFCellInst(), self.gnd)

raise NotImplementedError

def __process_bufg(self, bufg_cell):
Expand Down Expand Up @@ -636,12 +652,14 @@ def __process_bufg(self, bufg_cell):

return [bufg_cell]

def __check_carry4_const_net(self, site_inst, const_type, pin_out, new_net, is_gnd):
def __check_carry4_const_net(self, site_inst, const_info, pin_out, new_net):
"""
It seems that if the const lut output is routed to a carry4, the
mux it routes through also doesn't have a cell, so you have to check
the c4 input pins.
"""

const_type, is_gnd = const_info
cell = site_inst.getCell("CARRY4")
assert cell, f"{const_type} LUT routed to no cells"
pin_in = "DI" if pin_out.endswith("O5") else "S"
Expand All @@ -658,8 +676,6 @@ def __check_carry4_const_net(self, site_inst, const_type, pin_out, new_net, is_g
new_net.createPortInst(new_port, routed_to_cell_inst)
new_net.createPortInst(new_port, routed_to_cell_inst)

# pylint: enable=too-many-positional-arguments

def __process_lut_const_net(self, site_inst, new_cell_inst, pin_out, is_gnd):
"""
Replace the global const net on an input with the const routethru LUT output.
Expand Down Expand Up @@ -711,7 +727,7 @@ def __process_lut_const_net(self, site_inst, new_cell_inst, pin_out, is_gnd):
new_net.createPortInst(routed_to_port_inst.getPort(), routed_to_cell_inst)

if site_inst.getCell("CARRY4") is not None:
self.__check_carry4_const_net(site_inst, const_type, pin_out, new_net, is_gnd)
self.__check_carry4_const_net(site_inst, (const_type, is_gnd), pin_out, new_net)

def __process_lut_const(self, site_inst, pins, pin1_gnd, pin2_gnd):
"""
Expand Down Expand Up @@ -797,7 +813,7 @@ def __process_lut(self, lut6_cell, lut5_cell, lut5_only=False):
physical_pins_to_nets[physical_pin] = port_inst.getNet()

rw.lut_move_net_to_new_cell(
lut6_edif_cell_inst, new_cell_inst, logical_pin, physical_pin
(lut6_edif_cell_inst, new_cell_inst), logical_pin, physical_pin
)

# Now do the same for the other LUT
Expand All @@ -814,8 +830,7 @@ def __process_lut(self, lut6_cell, lut5_cell, lut5_only=False):
# Disconnect net from logical pin on old cell,
# and connect to new logical pin (based on physical pin) of new cell
rw.lut_move_net_to_new_cell(
lut5_edif_cell_inst,
new_cell_inst,
(lut5_edif_cell_inst, new_cell_inst),
logical_pin,
physical_pin,
logging.info,
Expand Down Expand Up @@ -887,7 +902,7 @@ def __process_lut5_and_const_lut(self, lut5, const_pin, site_inst, is_gnd):
assert port_inst

rw.lut_move_net_to_new_cell(
lut5_edif_cell_inst, new_cell_inst, logical_pin, physical_pin
(lut5_edif_cell_inst, new_cell_inst), logical_pin, physical_pin
)

if lut5.isRoutethru():
Expand Down
5 changes: 5 additions & 0 deletions bfasst/utils/sdn_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def __init__(self, wire):
self.driver_pin = None
self.is_vdd = False
self.is_gnd = False
self.is_const = False
self.is_connected = None

def add_alias_wire(self, wire):
Expand Down Expand Up @@ -225,11 +226,13 @@ def find_driver(self):
or self.wire.cable.name in SdnNetlistWrapper.GND_NAMES
):
self.is_gnd = True
self.is_const = True
elif (
self.wire.cable.name == r"\<const1>"
or self.wire.cable.name in SdnNetlistWrapper.VCC_NAMES
):
self.is_vdd = True
self.is_const = True

def set_driver_pin(self, pin):
"""Set the driver pin"""
Expand All @@ -239,13 +242,15 @@ def set_driver_pin(self, pin):
# Check for constant GND/VDD. Top-level I/O will not be GND/VDD
if isinstance(pin, sdn.OuterPin) and self.driver_pin.instance.reference.name == "GND":
self.is_gnd = True
self.is_const = True
else:
self.is_gnd = False
if isinstance(pin, sdn.OuterPin) and self.driver_pin.instance.reference.name in (
"VDD",
"VCC",
):
self.is_vdd = True
self.is_const = True
else:
self.is_vdd = False

Expand Down
Loading