From 404385b00f45fa553184757718028e213448768d Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 16 Jun 2021 17:05:53 -0400 Subject: [PATCH] allow arbitrary .v output file using -w/--write --- README.md | 8 +++++--- src/Job.hs | 42 +++++++++++++++++++++++++++++++----------- src/sv2v.hs | 3 +-- test/write/run.sh | 24 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index be5ad22..a48020f 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,8 @@ running `stack install`, or copy over the executable manually. sv2v takes in a list of files and prints the converted Verilog to `stdout`. Using `--write=adjacent` will create a converted `.v` for every `.sv` input file -rather than printing to `stdout`. +rather than printing to `stdout`. `--write`/`-w` can also be used to specify a +path to a `.v` output file. Users may specify `include` search paths, define macros during preprocessing, and exclude some of the conversions. Specifying `-` as an input file will read @@ -95,8 +96,9 @@ Conversion: -E --exclude=CONV Exclude a particular conversion (always, assert, interface, or logic) -v --verbose Retain certain conversion artifacts - -w --write=MODE How to write output; default is 'stdout'; use - 'adjacent' to create a .v file next to each input + -w --write=MODE/FILE How to write output; default is 'stdout'; use + 'adjacent' to create a .v file next to each input; + use a path ending in .v to write to a file Other: --help Display help message --version Print version information diff --git a/src/Job.hs b/src/Job.hs index 6d577e1..53908d6 100644 --- a/src/Job.hs +++ b/src/Job.hs @@ -8,12 +8,15 @@ module Job where +import Data.Char (toLower) +import Data.List (isPrefixOf, isSuffixOf) import Data.Version (showVersion) import GitHash (giDescribe, tGitInfoCwdTry) import qualified Paths_sv2v (version) import System.IO (stderr, hPutStr) import System.Console.CmdArgs import System.Environment (getArgs, withArgs) +import System.Exit (exitFailure) data Exclude = Always @@ -26,12 +29,9 @@ data Exclude data Write = Stdout | Adjacent - | File + | File FilePath deriving (Show, Typeable, Data, Eq) -instance Default Write where - def = Stdout - data Job = Job { files :: [FilePath] , incdir :: [FilePath] @@ -41,6 +41,7 @@ data Job = Job , exclude :: [Exclude] , verbose :: Bool , write :: Write + , writeRaw :: String } deriving (Show, Typeable, Data) version :: String @@ -65,10 +66,11 @@ defaultJob = Job ++ " or logic)") &= groupname "Conversion" , verbose = nam "verbose" &= help "Retain certain conversion artifacts" - , write = nam_ "write" &= name "w" &= typ "MODE" + , write = Stdout &= ignore -- parsed from the flexible flag below + , writeRaw = "s" &= name "write" &= name "w" &= explicit &= typ "MODE/FILE" &= help ("How to write output; default is 'stdout'; use 'adjacent' to" - ++ " create a .v file next to each input; use 'file' to create a" - ++ " sv2v_output.v file") + ++ " create a .v file next to each input; use a path ending in .v" + ++ " to write to a file") } &= program "sv2v" &= summary ("sv2v " ++ version) @@ -83,6 +85,18 @@ defaultJob = Job nam xs = nam_ xs &= name [head xs] nam_ xs = def &= name xs &= explicit +parseWrite :: String -> IO Write +parseWrite w | w `matches` "stdout" = return Stdout +parseWrite w | w `matches` "adjacent" = return Adjacent +parseWrite w | ".v" `isSuffixOf` w = return $ File w +parseWrite w | otherwise = do + hPutStr stderr $ "invalid --write " ++ show w + ++ ", expected stdout, adjacent, or a path ending in .v" + exitFailure + +matches :: String -> String -> Bool +matches = isPrefixOf . map toLower + type DeprecationPhase = [String] -> IO [String] flagRename :: String -> String -> DeprecationPhase @@ -108,7 +122,13 @@ readJob = do >>= flagRename "-i" "-I" >>= flagRename "-d" "-D" >>= flagRename "-e" "-E" - job <- withArgs (strs') $ cmdArgs defaultJob - return $ if verbose job - then job { exclude = Succinct : exclude job } - else job + withArgs strs' $ cmdArgs defaultJob + >>= setWrite . setSuccinct + where + setWrite :: Job -> IO Job + setWrite job = do + w <- parseWrite $ writeRaw job + return $ job { write = w } + setSuccinct :: Job -> Job + setSuccinct job | verbose job = job { exclude = Succinct : exclude job } + setSuccinct job | otherwise = job diff --git a/src/sv2v.hs b/src/sv2v.hs index 43ff3e1..20db5e7 100644 --- a/src/sv2v.hs +++ b/src/sv2v.hs @@ -64,9 +64,8 @@ writeOutput _ [] [] = hPutStrLn stderr "Warning: No input files specified (try `sv2v --help`)" writeOutput Stdout _ asts = hPrint stdout $ concat asts -writeOutput File _ asts = +writeOutput (File f) _ asts = writeFile f $ show $ concat asts - where f = "sv2v_output.v" writeOutput Adjacent inPaths asts = do outPaths <- mapM rewritePath inPaths badPaths <- filterM doesFileExist outPaths diff --git a/test/write/run.sh b/test/write/run.sh index 1bcad88..518b0b0 100755 --- a/test/write/run.sh +++ b/test/write/run.sh @@ -66,6 +66,30 @@ test_adjacent_extension() { "$stderr" } +test_file() { + runAndCapture --write=stdout *.sv + expected="$stdout" + + rm -f out.v + runAndCapture --write=out.v *.sv + assertTrue "file conversion should succeed" $result + assertNull "stdout should be empty" "$stdout" + assertNull "stderr should be empty" "$stderr" + + actual=`cat out.v` + assertEquals "file output should match combined" "$expected" "$actual" + clearArtifacts +} + +test_unknown() { + runAndCapture --write=unknown *.sv + assertFalse "unknown write mode should fail" $result + assertNull "stdout should be empty" "$stdout" + assertEquals "stderr should list valid write modes" \ + "invalid --write \"unknown\", expected stdout, adjacent, or a path ending in .v" \ + "$stderr" +} + source ../lib/functions.sh . shunit2