#!/usr/local/bin/bash

#   calibre_cvc: runs calibre svs to create a standardized netlist

#   Copyright 2106-2019 D. Mitch Bailey  cvc at shuharisystem dot com

#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.

#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.

echo $0 $*

rulefile=cvc.svrf

if [[ ${#*} -ne 4 ]]; then 
	echo "usage: calibre_cvc rulefile topBlock dataPath output"
	exit 1
fi

RULEFILE="$1"
PRIMARY="$2"
DATA="$3"
OUTPUT="$4"

if [[ ! -f $RULEFILE ]]; then
	echo "ERROR: can not open $RULEFILE"
	exit 1
fi

while [[ -L $DATA ]]; do
	DATA=`readlink $DATA`
done

additionalRules="cvc.include"
#   Additional rules include the following statements
#   Switches for CVC
#   Device filters for CVC

cellOverrides="override.list"
#   Cell overrides are
#   EXPAND cell  <- force flattening
#   KEEP cell    <- prevent explicit flattening (parameterized cells always flattened)
#   IGNORE cell  <- ignore

if [[ -f box.awk ]]; then
	BOX_FILTER='awk -f box.awk'
else
	BOX_FILTER=cat
fi

if [[ "${OUTPUT##*.}" == "gz" ]]; then
	compress=
	OUTPUT="${OUTPUT%%.gz}"
fi

log="cdl.log"
echo "log file: $log"

if [[ ( $DATA -nt expand.list ) \
		|| ( $cellOverrides -nt expand.list ) \
		|| ( ! -s expand.list ) ]]; then
	echo "Finding cells to expand using $cellOverrides ..."
	if [[ -f $cellOverrides ]]; then
		expand_cells.py $cellOverrides $PRIMARY $DATA > expand.list
		expand_status=$?
	else
		echo "Warning: missing $cellOverrides"
		expand_cells.py /dev/null $PRIMARY $DATA > expand.list
		expand_status=$?
	fi
	if [[ $expand_status -ne 0 ]]; then
		echo "ERROR: could not create expand.list"
		rm -f expand.list
		exit 1
	fi
else
	echo "Reusing expand.list"
fi

cat > $rulefile <<-svs_rule
	LAYOUT PRIMARY $PRIMARY
	LAYOUT PATH "$DATA"
	SOURCE PRIMARY $PRIMARY
	SOURCE PATH "$DATA"
	LVS WRITE SOURCE NETLIST "$OUTPUT.0"

	LVS REPORT "lvs_cdl.rep"
	LVS REPORT MAXIMUM 100
	LVS REPORT OPTION F R S V
	MASK RESULTS DATABASE none

	SOURCE SYSTEM SPICE
	LAYOUT SYSTEM SPICE

	LVS INJECT LOGIC NO
svs_rule

if [[ -f $additionalRules ]]; then
	echo "Adding $additionalRules to cvc.svrf"
	cat $additionalRules >> $rulefile
else
	echo "Warning: missing $additionalRules"
fi

sed -e 's/[   ][      ]*/ /g' \
	-e 's/^#!/\/\/&/I' \
	-e 's/^ *LAYOUT PRIMARY/\/\/&/I' \
	-e 's/^ *LAYOUT PATH/\/\/&/I' \
	-e 's/^ *SOURCE PRIMARY/\/\/&/I' \
	-e 's/^ *SOURCE PATH/\/\/&/I' \
	-e 's/^ *LVS WRITE SOURCE NETLIST/\/\/&/I' \
	-e 's/^ *LVS REPORT/\/\/&/I' \
	-e 's/^ *MASK RESULTS DATABASE/\/\/&/I' \
	-e 's/^ *SOURCE SYSTEM/\/\/&/I' \
	-e 's/^ *LAYOUT SYSTEM/\/\/&/I' \
	-e 's/^ *LVS INJECT LOGIC/\/\/&/I' \
	-e 's/^ *LVS FILTER UNUSED/\/\/&/I' \
	-e 's/^ *LVS EXECUTE ERC/\/\/&/I' \
	-e 's/^ *LVS SUMMARY /\/\/&/I' \
	-e 's/^ *MASK SVDB DIRECTORY/\/\/&/I' $RULEFILE >> $rulefile

cat expand.list >> $rulefile

if [[ -f $OUTPUT.0 ]]; then
	mv $OUTPUT.0 $OUTPUT.0.bak
fi

which calibre &> /dev/null
if [[ $? -eq 1 ]]; then
	read -p "Run SVS and hit return..."
else
	echo "Performing SVS..."
	calibre -hier -automatch -lvs -64 $rulefile > $log
	calibreStatus=$?
	tail -15 $log
	if [[ $calibreStatus -ne 0 ]]; then
		echo "ERROR: Calibre status $calibreStatus"
		exit 1
	fi
fi

echo "Removing leading double characters and changing commented parameters ..."
# ^RR -> R
# $LDD deleted (functionality in cvc model file LDDN/LDDP)
# X*==3 -> X* (done twice to handle up to 2 occurances on same instance)
# == -> --
# $a -> a
# $SUB= -> SUB= -> $SUB=  (no change)
sed -e 's/^\(.\)\1/\1/' \
    -e 's/\$SUB=/^SUB=/' \
    -e 's/\$LDD//' \
    -e 's/\$//g' \
    -e 's/^\([^ ]*\)==[0-9]*/\1/' \
    -e 's/^\([^ ]*\)==[0-9]*/\1/' \
    -e 's/==/--/g' \
    -e 's/\$//g' \
    -e 's/\^SUB=/$SUB=/' $OUTPUT.0 | \
$BOX_FILTER > $OUTPUT

echo "Calculating cksums..."
if [[ ! -d sub_split ]] ; then
	mkdir sub_split
fi

awk '\
/^+/ { printf("\\=%s", $0); next } \
 { printf("\n%s", $0) } \
END { printf("\n") }' $OUTPUT | \
	sed -e '/^ *$/d' \
	    -e 's/\\=+/ /g' \
	    -e 's/  */ /g' | \
	csplit -s -f sub_split/sub -n 7 - "/^\.SUBCKT /" "{*}"

for sub in sub_split/sub*; do
	CIRCUIT=$(awk '/^\.SUBCKT/ {print $2; exit}' $sub)
	sort $sub > sub_split/$CIRCUIT.cdl
	rm $sub
done

DATE=${PWD##*/}

echo "# Checksum file for $PRIMARY $DATE" > $PRIMARY.cksum

cksum sub_split/* | \
	sed -e 's,sub_split/,,' -e 's,\.cdl,,' >> $PRIMARY.cksum

rm -rf sub_split

if [[ ! -z "${compress+x}" ]]; then
	gzip -f $OUTPUT
fi

#23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
