1# ==============================================================================
2#  Authors:
3#    Patrick Lehmann
4#
5#	 Bash Script:
6#	   This is a Bash resource file for sourcing.
7#
8#  Description:
9#	   Provide Bash procedures to easily use GHDL in Bash scripts.
10#
11# ==============================================================================
12#  Copyright (C) 2017-2021 Patrick Lehmann - Boetzingen, Germany
13#  Copyright (C) 2015-2016 Patrick Lehmann - Dresden, Germany
14#
15#  This program is free software: you can redistribute it and/or modify
16#  it under the terms of the GNU General Public License as published by
17#  the Free Software Foundation, either version 2 of the License, or
18#  (at your option) any later version.
19#
20#  This program is distributed in the hope that it will be useful,
21#  but WITHOUT ANY WARRANTY; without even the implied warranty of
22#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23#  GNU General Public License for more details.
24#
25#  You should have received a copy of the GNU General Public License
26#  along with this program.  If not, see <gnu.org/licenses>.
27# ==============================================================================
28
29
30# set bash options
31set -o pipefail
32
33if [[ -n "$GHDL" ]]; then
34	if [[ ! -f "$GHDL" ]]; then
35		echo 1>&2 -e "${COLORED_ERROR} Found GHDL environment variable, but '$GHDL' is not a file.${ANSI_NOCOLOR}"
36		exit 1
37	elif [[ ! -x "$GHDL" ]]; then
38		echo 1>&2 -e "${COLORED_ERROR} Found GHDL environment variable, but '$GHDL' is not executable.${ANSI_NOCOLOR}"
39		exit 1
40	fi
41else	# fall back to GHDL found via PATH
42	GHDL=$(which ghdl 2>/dev/null)
43	if [[ $? -ne 0 ]]; then
44		echo 1>&2 -e "${COLORED_ERROR} GHDL not found in PATH.${ANSI_NOCOLOR}"
45		echo 1>&2 -e "  Use adv. options '--ghdl' to set the GHDL binary directory."
46		exit 1
47	fi
48fi
49
50Analyze_Filter=filter.analyze.sh
51Analyze_Parameters=(
52	--mb-comments
53)
54
55VERBOSE=${VERBOSE:-0}
56DEBUG=${DEBUG:-0}
57CONTINUE_ON_ERROR=${CONTINUE_ON_ERROR:-0}
58
59test $VERBOSE -eq 1 && echo -e "  Declaring Bash procedures for GHDL..."
60
61test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure SetupDirectories( <Index> <Name> )${ANSI_NOCOLOR}"
62# SetupDirectories
63# -> $Index
64# -> $Name
65# <= $SourceDirectory
66# <= $DestinationDirectory
67SetupDirectories() {
68	local Index=$1
69	local Name=$2
70
71	declare -n Settings="${Index}_Settings"
72
73	# source directory
74	# ----------------------
75	# If a command line argument ('--source') was passed in, use it, else use the default value
76	# from config.sh
77	if [[ ! -z "$SrcDir" ]]; then
78		SourceDirectory=${SrcDir%/}										# remove trailing slashes
79	elif [[ ! -z "$EnvSourceDir" ]]; then
80		SourceDirectory=$EnvSourceDir									# fall back to environment variable
81	elif [[ ! -z "${Settings[InstallationDirectory]}" ]]; then
82		SourceDirectory=${Settings[InstallationDirectory]}/${Settings[SourceDirectory]}	# fall back to value from config.sh
83	fi
84	# output directory
85	# ----------------------
86	# If a command line argument ('--output') was passed in, use it, else use the default value
87	# from config.sh
88	if [[ ! -z "$DestDir" ]]; then
89		DestinationDirectory=${DestDir%/}												# remove trailing slashes
90	else
91		DestinationDirectory=${Settings[DestinationDirectory]}	# fall back to value from config.sh
92	fi
93
94	if [[ -z $SourceDirectory || -z $DestinationDirectory ]]; then
95		echo 1>&2 -e "${COLORED_ERROR} $Name is not configured in '$ScriptDir/config.sh'.${ANSI_NOCOLOR}"
96		echo 1>&2 -e "  Use adv. options '--source' and '--output' or configure 'config.sh'."
97		exit 1
98	elif [[ ! -d $SourceDirectory ]]; then
99		echo 1>&2 -e "${COLORED_ERROR} Path '$SourceDirectory' does not exist.${ANSI_NOCOLOR}"
100		exit 1
101	fi
102
103	# Resolve paths to an absolute paths
104	test greadlink --version > /dev/null 2>&1 && READLINK=greadlink || READLINK=readlink
105	SourceDirectory=$($READLINK -f $SourceDirectory)
106	if [[ ! "$DestinationDirectory" = /* ]]; then
107		DestinationDirectory="$WorkingDir/$DestinationDirectory"
108	fi
109}
110
111test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure CreateDestinationDirectory( undocumented )${ANSI_NOCOLOR}"
112# CreateDestinationDirectory
113# -> undocumented
114CreateDestinationDirectory() {
115	if [ -d "$DestinationDirectory" ]; then
116		echo -e "${COLORED_WARNING} Vendor directory '$DestinationDirectory' already exists.${ANSI_NOCOLOR}"
117	elif [ -f "$DestinationDirectory" ]; then
118		echo 1>&2 -e "${COLORED_ERROR} Vendor directory '$DestinationDirectory' already exists as a file.${ANSI_NOCOLOR}"
119		exit 1
120	else
121		echo -e "Creating vendor directory: '$DestinationDirectory'.${ANSI_NOCOLOR}"
122		mkdir -p "$DestinationDirectory"
123	fi
124}
125
126test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure GHDLSetup( <VHDLStandard> )${ANSI_NOCOLOR}"
127# GHDLSetup
128# -> $VHDLStandard
129# <= $VHDLVersion
130# <= $VHDLStandard
131# <= $VHDLFlavor
132GHDLSetup() {
133	if [ $1 -eq 93 ]; then
134		VHDLVersion="v93"
135		VHDLStandard="93c"
136		VHDLFlavor="synopsys"
137	elif [ $1 -eq 2008 ]; then
138		VHDLVersion="v08"
139		VHDLStandard="08"
140		VHDLFlavor="synopsys"
141	fi
142}
143
144test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure CreateVHDLLibrary( <StructName> <LibraryName> <LibraryPath> <VHDLVersion> <Files[*]> )${ANSI_NOCOLOR}"
145# CreateLibraryStruct
146# -> $StructName
147# -> $LibraryName
148# -> $LibraryPath
149# -> $VHDLVersion
150# -> $Files[*]
151CreateLibraryStruct() {
152	local StructName=$1; shift
153
154	declare -g "${StructName}_LibraryName"=$1; shift
155	declare -g "${StructName}_LibraryPath"=$1; shift
156	declare -g "${StructName}_VHDLVersion"=$1; shift
157
158	declare -n FilesRef="${StructName}_Files"
159	FilesRef=( "$*" )
160}
161
162test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure DeleteLibraryStruct( <StructName> )${ANSI_NOCOLOR}"
163# DeleteLibraryStruct
164# -> $StructName
165DeleteLibraryStruct() {
166	local StructName=$1
167
168	unset "${StructName}_VHDLVersion"
169	unset "${StructName}_LibraryName"
170	unset "${StructName}_LibraryPath"
171	unset "${StructName}_Files"
172}
173
174test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure PrintLibraryStruct( <StructName> )${ANSI_NOCOLOR}"
175# PrintLibraryStruct
176# -> $StructName
177PrintLibraryStruct() {
178	local StructName=$1
179	local Indentation=${2:-"    "}
180
181	local LibraryName="${StructName}_LibraryName"; local LibraryName=${!LibraryName}
182	local Files="${StructName}_Files[*]";          local Files=${!Files}
183
184	echo -e "$Indentation${ANSI_DARK_GRAY}VHDL Library name: $LibraryName${ANSI_NOCOLOR}"
185	for File in ${Files[*]}; do
186		echo -e "$Indentation  ${ANSI_DARK_GRAY}$File${ANSI_NOCOLOR}"
187	done
188}
189
190
191declare -A GHDLLibraryMapping
192
193test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure CreateVHDLLibrary( <LibraryName> <DirectoryName> <VHDLVersion> )${ANSI_NOCOLOR}"
194# CreateVHDLLibrary
195# -> $LibraryName
196# -> $DirectoryName
197# -> $VHDLVersion
198CreateVHDLLibrary() {
199	local LibraryName=$1
200	local DirectoryName=$2
201	local VHDLVersion=${3:-"v08"}
202
203	echo -e "${ANSI_YELLOW}Creating VHDL Library '$LibraryName'...${ANSI_NOCOLOR}"
204
205	test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}mkdir -p \"$DirectoryName/$VHDLVersion\"${ANSI_NOCOLOR}"
206	mkdir -p "$DirectoryName/$VHDLVersion"
207
208	LibraryDir="$(pwd)/$DirectoryName/$VHDLVersion"
209	test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}Mapping library $LibraryName to '$LibraryDir'.${ANSI_NOCOLOR}"
210	GHDLLibraryMapping[$LibraryName]=$LibraryDir
211}
212
213test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure AnalyzeVHDL( <LibraryName> <SourceDirectory> <LibraryPath> <File> )${ANSI_NOCOLOR}"
214# AnalyzeVHDL
215# -> $LibraryName
216# -> $SourceDirectory
217# -> $LibraryPath
218# -> $File
219AnalyzeVHDL() {
220	local LibraryName=$1
221	local SourceDirectory=$2
222	local LibraryPath=$3
223	local File=$4
224
225	local DestinationDirectory=${GHDLLibraryMapping[$LibraryName]}
226
227	if [[ $DEBUG -eq 1 ]]; then
228		local Parameters=(
229			-v
230		)
231		local Filter_Parameters=(
232			-d
233		)
234		local Filter_Indent="      "
235	elif [[ $VERBOSE -eq 1 ]]; then
236		local Parameters=()
237		local Filter_Parameters=(
238			-v
239		)
240		local Filter_Indent="    "
241	else
242		local Parameters=()
243		local Filter_Parameters=()
244		local Filter_Indent="  "
245	fi
246
247	local SourceFile="$SourceDirectory/$LibraryPath/$File"
248
249	if [[ ! -f "$SourceFile" ]]; then
250		echo 1>&2 -e "${COLORED_ERROR} Source file '$SourceFile' not found.${ANSI_NOCOLOR}"
251		test $CONTINUE_ON_ERROR -eq 0 && exit 1
252	fi
253
254	if [[ $FILTERING -eq 0 ]]; then
255		test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}$GHDL -a ${Analyze_Parameters[*]} ${Parameters[*]} --work=$LibraryName \"$SourceFile\"${ANSI_NOCOLOR}"
256		$GHDL -a "${Analyze_Parameters[@]}" "${Parameters[@]}" --work=$LibraryName --workdir=$DestinationDirectory "$SourceFile"
257		ExitCode=$?
258		if [[ $ExitCode -ne 0 ]]; then
259			echo 1>&2 -e "$Filter_Indent${COLORED_ERROR} While analyzing '$File'. ExitCode: $ExitCode${ANSI_NOCOLOR}"
260			test $CONTINUE_ON_ERROR -eq 0 && exit 1
261		fi
262	 else
263		 test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}$GHDL -a ${Analyze_Parameters[*]} ${Parameters[*]} --work=$LibraryName \"$SourceFile\" 2>&1 | \\\\${ANSI_NOCOLOR}"
264		 test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}$ScriptDir/$Analyze_Filter ${Filter_Parameters[*]} -i \"$Filter_Indent\"${ANSI_NOCOLOR}"
265		 $GHDL -a "${Analyze_Parameters[@]}" "${Parameters[@]}" --work=$LibraryName "$SourceFile" 2>&1 | $ScriptDir/$Analyze_Filter "${Filter_Parameters[@]}" -i "$Filter_Indent"
266		 local PiplineStatus=("${PIPESTATUS[@]}")
267		 if [[ ${PiplineStatus[0]}  -ne 0 ]]; then
268			 echo 1>&2 -e "$Filter_Indent${COLORED_ERROR} While analyzing '$File'. ExitCode: ${PiplineStatus[0]}${ANSI_NOCOLOR}"
269			 test $CONTINUE_ON_ERROR -eq 0 && exit 1
270		 elif [[ ${PiplineStatus[1]}  -ne 0 ]]; then
271			 case $(( ${PiplineStatus[1]} % 4 )) in
272				 # TODO: implement CONTINUE_ON_ERROR in cases ...
273				 3) echo 1>&2 -e "$Filter_Indent${ANSI_RED}Fatal errors detected by filtering script. ExitCode: ${PiplineStatus[1]}${ANSI_NOCOLOR}"; exit 1 ;;
274				 2) echo 1>&2 -e "$Filter_Indent${ANSI_RED}Errors detected by filtering script. ExitCode: ${PiplineStatus[1]}${ANSI_NOCOLOR}"; exit 1 ;;
275				 1) echo 1>&2 -e "$Filter_Indent${ANSI_YELLOW}Warnings detected by filtering script.${ANSI_NOCOLOR}" ;;
276				 0) test $DEBUG -eq 1 && echo 1>&2 -e "$Filter_Indent${ANSI_YELLOW}Warnings detected by filtering script.${ANSI_NOCOLOR}" ;;
277			 esac
278		 fi
279	fi
280}
281
282
283test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure AnalyzeLibrary( <LibraryName> <SourceDirectory> <LibraryPath> <Files[*]> )${ANSI_NOCOLOR}"
284# AnalyzeLibrary
285# -> LibraryName
286# -> SourceDirectory
287# -> LibraryPath
288# -> Files[*]
289AnalyzeLibrary() {
290	local LibraryName=$1;     shift
291	local SourceDirectory=$1; shift
292	local LibraryPath=$1;     shift
293	local Files=$@
294
295	echo -e "${ANSI_YELLOW}Analyzing files into library '$LibraryName'...${ANSI_NOCOLOR}"
296
297	for File in $Files; do
298		test $VERBOSE -eq 1 && echo -e "${ANSI_CYAN}  Analyzing '$File'${ANSI_NOCOLOR}"
299
300		AnalyzeVHDL $LibraryName "$SourceDirectory" "$LibraryPath" "$File"
301	done
302}
303
304test $DEBUG -eq 1 && echo -e "    ${ANSI_DARK_GRAY}procedure Compile( <SourceDirectory> <Libraries> )${ANSI_NOCOLOR}"
305# Compile
306# -> SourceDirectory
307# -> VHDLLibraries
308Compile() {
309	local SourceDirectory=$1
310	local VHDLLibraries=$2
311
312	for VHDLLibrary in $VHDLLibraries; do
313		local LibraryName="${VHDLLibrary}_LibraryName"; local LibraryName=${!LibraryName}
314		local LibraryPath="${VHDLLibrary}_LibraryPath"; local LibraryPath=${!LibraryPath}
315		local VHDLVersion="${VHDLLibrary}_VHDLVersion"; local VHDLVersion=${!VHDLVersion}
316		local Files="${VHDLLibrary}_Files[*]";          local Files=${!Files}
317
318		echo -e "${ANSI_LIGHT_CYAN}Analyzing library '$LibraryName'...${ANSI_NOCOLOR}"
319
320		CreateVHDLLibrary $LibraryName $LibraryName $VHDLVersion
321		AnalyzeLibrary $LibraryName "$SourceDirectory" "$LibraryPath" "$Files"
322	done
323}
324