From 44b6026d28a24a3ca7c3930b3eb3d9244abac794 Mon Sep 17 00:00:00 2001 From: Julie Schwartz Date: Mon, 17 Jul 2023 23:49:27 +1200 Subject: [PATCH] Fix linking to find VPI files in the Verilog path Previously, the linking stage assumed that VPI wrapper files were in the vdir or (if no vdir) the current directory (where BSC is invoked). This probably explains why the compile stage had been changed to put the VPI wrappers in the current directory (see previous commit, which reverts that change). BSC needs to support linking where VPI wrappers are found in various directories -- both because of the change to the compile stage (to put the VPI wrappers in the various source directories) but also because the files may not have been compiled with the same vdir. Specificaly, users will want to compile files into a library, that can be used with multiple designs; those files should be able to sit in their own directory tree. If the library contains imported C functions, then VPI wrapper files will be in the directory tree, and the BSC link stage will need to be able to find them. Now that the compile stage is putting VPI wrapper files in the same location with Verilog files, the linking stage can use the Verilog search path to find them. This makes that change and adds tests. --- src/comp/Error.hs | 7 ++++ src/comp/VPIWrappers.hs | 6 ++-- src/comp/bsc.hs | 58 +++++++++++++++++++------------ testsuite/bsc.options/Makefile | 2 +- testsuite/bsc.options/options.exp | 57 ++++++++++++++++++++++++------ 5 files changed, 94 insertions(+), 36 deletions(-) diff --git a/src/comp/Error.hs b/src/comp/Error.hs index 048a11cfc..5d820ee9a 100644 --- a/src/comp/Error.hs +++ b/src/comp/Error.hs @@ -1118,6 +1118,7 @@ data ErrMsg = | EMissingUserFile String [String] | EUnrecognizedCmdLineText String | EUnknownVerilogSim String [String] Bool + | EMissingVPIWrapperFile String Bool -- ABin (.ba) file issues | WExtraABinFiles [String] @@ -4416,6 +4417,12 @@ getErrorText (WNonDemotableErrors tags) = in s2par ("Cannot demote the following error" ++ s ++ ":") $$ nest 2 (sepList (map text tags) comma)) +getErrorText (EMissingVPIWrapperFile fname is_dpi) = + (System 95, empty, + let ifctype = if is_dpi then "DPI" else "VPI" + in s2par ("Cannot find the " ++ ifctype ++ " file " ++ ishow fname ++ + " in the Verilog search path.")) + -- Runtime errors getErrorText (EMutuallyExclusiveRulesFire r1 r2) = (Runtime 1, empty, diff --git a/src/comp/VPIWrappers.hs b/src/comp/VPIWrappers.hs index 73c0230c0..a76d6bc1b 100644 --- a/src/comp/VPIWrappers.hs +++ b/src/comp/VPIWrappers.hs @@ -300,8 +300,8 @@ mkVPIRegisterBody name has_return stores_handles = genVPIRegistrationArray :: ErrorHandle -> Flags -> String -> [String] -> [ForeignFunction] -> - IO () -genVPIRegistrationArray _ _ _ _ [] = return () + IO [String] +genVPIRegistrationArray _ _ _ _ [] = return [] genVPIRegistrationArray errh flags prefix blurb ffs = do let -- generate the registration array file name c_filename = mkVPIArrayCName (vdir flags) prefix @@ -316,6 +316,8 @@ genVPIRegistrationArray errh flags prefix blurb ffs = writeFileCatch errh c_filename c_contents -- report the file to the user with relative path unless (quiet flags) $ putStrLnF $ "VPI registration array file created: " ++ c_filename_rel + -- return the file name + return [c_filename] mkVPIRegistrationArray :: Flags -> String -> [ForeignFunction] -> Bool -> CCFragment mkVPIRegistrationArray flags prefix ffs with_fn = diff --git a/src/comp/bsc.hs b/src/comp/bsc.hs index 07877e769..a442240e3 100644 --- a/src/comp/bsc.hs +++ b/src/comp/bsc.hs @@ -7,6 +7,7 @@ import System.Environment(getArgs, getProgName) import System.Process(runInteractiveProcess, waitForProcess) import System.Process(system) import System.Exit(ExitCode(ExitFailure, ExitSuccess)) +import System.FilePath(takeDirectory) import System.IO(hFlush, stdout, hPutStr, stderr, hGetContents, hClose, hSetBuffering, BufferMode(LineBuffering)) import System.IO(hSetEncoding, latin1) import System.Posix.Files(fileMode, unionFileModes, ownerExecuteMode, groupExecuteMode, setFileMode, getFileStatus, fileAccess) @@ -16,7 +17,7 @@ import Data.Char(isSpace, toLower, ord) import Data.List(intersect, nub, partition, intersperse, sort, isPrefixOf, isSuffixOf, unzip5, intercalate) import Data.Time.Clock.POSIX(getPOSIXTime) -import Data.Maybe(isJust, isNothing {-, fromMaybe-}) +import Data.Maybe(isJust, isNothing) import Numeric(showOct) import Control.Monad(when, unless, filterM, liftM, foldM) @@ -25,6 +26,7 @@ import Control.Concurrent(forkIO) import Control.Concurrent.MVar(newEmptyMVar, putMVar, takeMVar) import qualified Control.Exception as CE import qualified Data.Map as M +import qualified Data.Set as S import ListMap(lookupWithDefault) import SCC(scc) @@ -34,7 +36,7 @@ import ParseOp import PFPrint import Util(headOrErr, fromJustOrErr, joinByFst, quote) import FileNameUtil(baseName, hasDotSuf, dropSuf, dirName, mangleFileName, - mkAName, mkVName, mkVPICName, mkVPIArrayCName, + mkAName, mkVName, mkVPICName, mkNameWithoutSuffix, mkSoName, mkObjName, mkMakeName, bscSrcSuffix, bseSrcSuffix, binSuffix, @@ -42,7 +44,8 @@ import FileNameUtil(baseName, hasDotSuf, dropSuf, dirName, mangleFileName, objSuffix, useSuffix, genFileName, createEncodedFullFilePath, getFullFilePath, getRelativeFilePath) -import FileIOUtil(writeFileCatch, readFileMaybe, removeFileCatch) +import FileIOUtil(writeFileCatch, readFileMaybe, removeFileCatch, + readFilePath) import TopUtils import SystemCheck(doSystemCheck) import BuildSystem @@ -1531,12 +1534,13 @@ cmdCompileBluesimCFile flags cName = do return (cmd, oName, msg) -- returns the name of the object file created -compileVPICFile :: ErrorHandle -> Flags -> String -> IO String -compileVPICFile errh flags cName = do +compileVPICFile :: ErrorHandle -> Flags -> [String] -> String -> IO String +compileVPICFile errh flags incdirs cName = do let oName = mkObjName Nothing "" (dropSuf cName) -- show is used for quoting let incflags = map (("-I"++) . show) (cIncPath flags) ++ - ["-I" ++ show (bluespecDir flags) ++ "/VPI"] + ["-I" ++ show (bluespecDir flags) ++ "/VPI"] ++ + map (\d -> "-I" ++ d) incdirs switches = incflags ++ [ "-fPIC" , "-c" @@ -2083,13 +2087,14 @@ vGenFFuncs :: ErrorHandle -> Flags -> TimeInfo -> String -> IO (TimeInfo, [String]) vGenFFuncs errh flags t prefix cfilenames_unique [] = return (t,[]) vGenFFuncs errh flags t prefix cfilenames_unique ffuncs = do - t <- - if (useDPI flags) then return t + (t, vpiarray_filenames) <- + if (useDPI flags) then return (t, []) else do -- generate the vpi_startup_array file blurb <- mkGenFileHeader flags - genVPIRegistrationArray errh flags prefix blurb ffuncs - timestampStr flags "generate VPI registration array" t + filenames <- genVPIRegistrationArray errh flags prefix blurb ffuncs + t <- timestampStr flags "generate VPI registration array" t + return (t, filenames) -- compile user-supplied C files let (cfiles1, ofiles1) = partition (\f -> hasDotSuf cSuffix f || @@ -2101,23 +2106,30 @@ vGenFFuncs errh flags t prefix cfilenames_unique ffuncs = do ofiles2 <- mapM (compileUserCFile errh flags True) cfiles1 t <- timestampStr flags "compile user-provided C files" t -{- - -- XXX If any of BSC's pre-compiled .ba libraries has a VPI wrapper - -- XXX that goes along with it, they would need to included here? - do let to = fromMaybe "." (vdir flags) - mapM_ (\src -> do let dst = to ++ "/" ++ (baseName src) - copyFileCatch errh src dst) - vpi_wrapper_c_h_files --} - (t, ofiles3) <- if (useDPI flags) then return (t, []) else do -- compile all necessary vpi wrapper files - let mkVPIFileName s = mkVPICName (vdir flags) prefix s - vpifiles = map (mkVPIFileName . getIdString . ff_name) ffuncs ++ - [ mkVPIArrayCName (vdir flags) prefix ] - files <- mapM (compileVPICFile errh flags) vpifiles + + -- first, find the VPI wrapper files in the vsearch path + let findVPIWrapperFile ffunc = do + let ffunc_name = getIdString (ff_name ffunc) + vpiwrapper_filename = mkVPICName Nothing "" ffunc_name + mfile <- readFilePath errh noPosition False vpiwrapper_filename (vPath flags) + case mfile of + Nothing -> bsError errh [(noPosition, EMissingVPIWrapperFile vpiwrapper_filename False)] + Just (_, filename) -> return filename + vpiwrapper_filenames <- mapM findVPIWrapperFile ffuncs + + -- collect the directories of the VPI wrapper files + -- to use as a search path for header files when compiling + -- the VPI registration array file + let vpidirs = S.toList (S.fromList (map takeDirectory vpiwrapper_filenames)) + + -- include the vpi registration array file + wrapper_files <- mapM (compileVPICFile errh flags []) vpiwrapper_filenames + array_files <- mapM (compileVPICFile errh flags vpidirs) vpiarray_filenames + let files = wrapper_files ++ array_files t <- timestampStr flags "compile VPI wrapper files" t return (t, files) diff --git a/testsuite/bsc.options/Makefile b/testsuite/bsc.options/Makefile index 6d5cfc7cb..11d93938b 100644 --- a/testsuite/bsc.options/Makefile +++ b/testsuite/bsc.options/Makefile @@ -3,7 +3,7 @@ CONFDIR = $(realpath ..) DONTKEEPFILES = *.post-m4 *.post-m4-stage1 \ - simfiles bfiles vfiles incfiles srcfiles \ + simfiles bfiles vfiles incfiles srcfiles vfiles_link \ SplitIfNested.bs.expandif.atsexpand.expected \ NoSplitIfNested.bs.expandif.atsexpand.expected \ NoSplitIfNested.bs.noexpandif.atsexpand.expected \ diff --git a/testsuite/bsc.options/options.exp b/testsuite/bsc.options/options.exp index 7c779286f..f6494b274 100644 --- a/testsuite/bsc.options/options.exp +++ b/testsuite/bsc.options/options.exp @@ -127,8 +127,12 @@ files_exist { simfiles/mkDummyModule.cxx \ ########### # -# Test that vpi_wrapper_* files are written to vdir -# or (if no vdir) to the same directory where the source file sits +# Test that the compile stage writes 'vpi_wrapper_*' files to vdir +# or (if no vdir) to the same directory where the source file sits. +# +# And test that the linking step can find VPI wrapper files +# by looking through the Verilog search path, to successfully +# compile the wrappers and to compile the registration array. # # The directory of the source file is not the current directory # (where BSC was invoked from) when -u is used to compile files @@ -136,23 +140,56 @@ files_exist { simfiles/mkDummyModule.cxx \ # the source file given on the command line include a directory # (which is what we will test here). +# --- +# Test compile without vdir + +nukedir srcfiles +erase_many {vpi_*.{c,h,o}} + +# Set up the source file in a directory +mkdir srcfiles +copy GCD.bsv srcfiles + +compile_verilog_pass srcfiles/GCD.bsv {} {-p srcfiles:+} +files_exist {srcfiles/vpi_wrapper_my_time.h srcfiles/vpi_wrapper_my_time.c} + +# --- +# Test compile with vdir + +nukedir srcfiles +nukedir vfiles +erase_many {vpi_*.{c,h,o}} + # Set up the source file in a directory mkdir srcfiles copy GCD.bsv srcfiles -# Remove vpi_wrapper files, so we can test they are generated -erase_many {vfiles/vpi_wrapper*} +# Create the vdir +mkdir vfiles -# Test with vdir compile_verilog_pass srcfiles/GCD.bsv {} {-vdir vfiles -p srcfiles:+} files_exist {vfiles/vpi_wrapper_my_time.h vfiles/vpi_wrapper_my_time.c} -# Remove vpi_wrapper files, so we can test they are generated -erase_many {vpi_wrapper*} +# The above will have placed vpi wrappers in 'vfiles/' +# so now we test that linking can find it, +# both with or without its own other vdir -# Test without vdir -compile_verilog_pass srcfiles/GCD.bsv {} {-p srcfiles:+} -files_exist {srcfiles/vpi_wrapper_my_time.h srcfiles/vpi_wrapper_my_time.c} +# --- +# Test link with vdir + +nukedir vfiles_link +mkdir vfiles_link + +link_verilog_pass {srcfiles/my_time.ba} {sysGCD} {-vsearch vfiles:+ -vdir vfiles_link} +files_exist {vfiles/vpi_wrapper_my_time.o vfiles_link/vpi_startup_array.o} + +# --- +# Test link without vdir + +erase_many {vfiles/vpi_*.o vpi_*.{c,h,o}} + +link_verilog_pass {srcfiles/my_time.ba} {sysGCD} {-vsearch vfiles:+} +files_exist {vfiles/vpi_wrapper_my_time.o vpi_startup_array.o} ########### #