#!/usr/bin/env python3
#
# Each LUT that goes to several FF can be duplicated to gain some LCs.
#
# Copyright (C) 2020 Sylvain Munaut
# SPDX-License-Identifier: MIT
#


def run_opt(ctx):

	cnt_grp = 0
	cnt_new = 0

	for cn, ci in ctx.cells:
		# Only look at lut4
		if ci.type != 'SB_LUT4':
			continue

		# Scan users
		ff = []
		other = False
		for u in ci.ports['O'].net.users:
			# If we have any other users than D port on DFFs, then it's no use
			if (not u.cell.type.startswith('SB_DFF')) or (u.port != 'D'):
				other = True
				break

			ff.append(u)

		# Should we do duplication ?
		if other or len(ff) < 2:
			continue

		# Count
		cnt_grp += 1
		cnt_new += len(ff) - 1

		# Duplicate as needed
		for i,d in enumerate(ff[1:]):
			# Get previous data
			on = ci.ports['O'].net

			# New Cell
			nc = ctx.createCell(ci.name + '_dup' + str(i), 'SB_LUT4')

				# Copy inputs
			for pn in ['I0', 'I1', 'I2', 'I3']:
				if pn not in ci.ports:
					continue
				nc.addInput(pn)
				if ci.ports[pn] is None:
					continue
				ctx.connectPort(ci.ports[pn].net.name, nc.name, pn)

				# Create output
			nc.addOutput('O')

				# Copy config
			for an,av in ci.attrs:
				nc.setAttr(an,av)
			for pn,pv in ci.params:
				nc.setParam(pn,pv)

			# Rewire
			ctx.disconnectPort(d.cell.name, 'D')

			nn = ctx.createNet(on.name + '_dup' + str(i))
			ctx.connectPort(nn.name, d.cell.name, 'D')
			ctx.connectPort(nn.name, nc.name, 'O')

	print("LUT replication: %d new LUTs in %d groups" % (cnt_new, cnt_grp))