Skip to content

Commit

Permalink
Fix linking to find VPI files in the Verilog path
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
quark17 committed Jul 17, 2023
1 parent 7367f6c commit 44b6026
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 36 deletions.
7 changes: 7 additions & 0 deletions src/comp/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ data ErrMsg =
| EMissingUserFile String [String]
| EUnrecognizedCmdLineText String
| EUnknownVerilogSim String [String] Bool
| EMissingVPIWrapperFile String Bool

-- ABin (.ba) file issues
| WExtraABinFiles [String]
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions src/comp/VPIWrappers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 =
Expand Down
58 changes: 35 additions & 23 deletions src/comp/bsc.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -34,15 +36,16 @@ 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,
hSuffix, cSuffix, cxxSuffix, cppSuffix, ccSuffix,
objSuffix, useSuffix,
genFileName, createEncodedFullFilePath,
getFullFilePath, getRelativeFilePath)
import FileIOUtil(writeFileCatch, readFileMaybe, removeFileCatch)
import FileIOUtil(writeFileCatch, readFileMaybe, removeFileCatch,
readFilePath)
import TopUtils
import SystemCheck(doSystemCheck)
import BuildSystem
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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 ||
Expand All @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion testsuite/bsc.options/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
57 changes: 47 additions & 10 deletions testsuite/bsc.options/options.exp
Original file line number Diff line number Diff line change
Expand Up @@ -127,32 +127,69 @@ 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
# found in multiple directories. However, it can also occur if
# 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}

###########
#
Expand Down

0 comments on commit 44b6026

Please sign in to comment.