Commit 5aea0ee9 by Zachary Snow

add write adjacent mode

parent 8eb9523d
......@@ -73,6 +73,9 @@ running `stack install`, or copy over the executable manually.
## Usage
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`.
Users may specify `include` search paths, define macros during preprocessing,
and exclude some of the conversions. Specifying `-` as an input file will read
from `stdin`.
......@@ -92,6 +95,8 @@ 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
Other:
--help Display help message
--version Print version information
......
......@@ -21,6 +21,14 @@ data Exclude
| Succinct
deriving (Show, Typeable, Data, Eq)
data Write
= Stdout
| Adjacent
deriving (Show, Typeable, Data, Eq)
instance Default Write where
def = Stdout
data Job = Job
{ files :: [FilePath]
, incdir :: [FilePath]
......@@ -29,6 +37,7 @@ data Job = Job
, skipPreprocessor :: Bool
, exclude :: [Exclude]
, verbose :: Bool
, write :: Write
} deriving (Show, Typeable, Data)
defaultJob :: Job
......@@ -47,6 +56,9 @@ defaultJob = Job
++ " or logic)")
&= groupname "Conversion"
, verbose = nam "verbose" &= help "Retain certain conversion artifacts"
, write = nam_ "write" &= name "w" &= typ "MODE"
&= help ("How to write output; default is 'stdout'; use 'adjacent' to"
++ " create a .v file next to each input")
}
&= program "sv2v"
&= summary ("sv2v " ++ giDescribe $$tGitInfoCwd)
......
......@@ -4,12 +4,15 @@
- conversion entry point
-}
import System.IO
import System.Exit
import System.Directory (doesFileExist)
import System.IO (hPrint, hPutStrLn, stderr, stdout)
import System.Exit (exitFailure, exitSuccess)
import Control.Monad (filterM, when, zipWithM_)
import Data.List (elemIndex, intercalate)
import Data.List (elemIndex)
import Job (readJob, files, exclude, incdir, define, siloed, skipPreprocessor)
import Convert (convert)
import Job (readJob, Job(..), Write(..))
import Language.SystemVerilog.AST
import Language.SystemVerilog.Parser (parseFiles)
......@@ -32,15 +35,39 @@ emptyWarnings before after =
if all null before || any (not . null) after then
return ()
else if any (any isInterface) before then
hPutStr stderr $ "Warning: Source includes an interface but output is "
++ "empty because there is no top-level module which has no ports "
++ "which are interfaces."
hPutStrLn stderr $ "Warning: Source includes an interface but output is"
++ " empty because there is no top-level module which has no ports"
++ " which are interfaces."
else if any (any isPackage) before then
hPutStr stderr $ "Warning: Source includes packages but no modules. "
++ "Please convert packages alongside the modules that use them."
hPutStrLn stderr $ "Warning: Source includes packages but no modules."
++ " Please convert packages alongside the modules that use them."
else
return ()
rewritePath :: FilePath -> IO FilePath
rewritePath path = do
when (end /= ext) $ do
hPutStrLn stderr $ "Refusing to write adjacent to " ++ show path
++ " because that path does not end in " ++ show ext
exitFailure
return $ base ++ ".v"
where
ext = ".sv"
(base, end) = splitAt (length path - length ext) path
writeOutput :: Write -> [FilePath] -> [AST] -> IO ()
writeOutput Stdout _ asts =
hPrint stdout $ concat asts
writeOutput Adjacent inPaths asts = do
outPaths <- mapM rewritePath inPaths
badPaths <- filterM doesFileExist outPaths
when (not $ null badPaths) $ do
hPutStrLn stderr $ "Refusing to write output because the following"
++ " files would be overwritten: " ++ intercalate ", " badPaths
exitFailure
let results = map (++ "\n") $ map show asts
zipWithM_ writeFile outPaths results
main :: IO ()
main = do
job <- readJob
......@@ -50,12 +77,12 @@ main = do
(skipPreprocessor job) (files job)
case result of
Left msg -> do
hPutStr stderr $ msg ++ "\n"
hPutStrLn stderr msg
exitFailure
Right asts -> do
-- convert the files
let asts' = convert (exclude job) asts
emptyWarnings asts asts'
-- print the converted files out
hPrint stdout $ concat asts'
-- write the converted files out
writeOutput (write job) (files job) asts'
exitSuccess
#!/bin/bash
validateOutput() {
stdout_len=`wc -l < $SHUNIT_TMPDIR/stdout`
assertEquals "stdout should be empty" 0 $stdout_len
stderr=`cat $SHUNIT_TMPDIR/stderr`
runErrorTest() {
runAndCapture $1.sv
assertFalse "conversion should have failed" $result
assertNull "stdout should be empty" "$stdout"
assertNotNull "stderr should not be empty" "$stderr"
line=`head -n1 $1`
line=`head -n1 $1.sv`
if [[ "$line" =~ \/\/\ pattern:\ .* ]]; then
pattern=${line:12}
if [[ ! "$stderr" =~ $pattern ]]; then
......@@ -16,11 +16,7 @@ validateOutput() {
addTest() {
test=$1
eval "test_$test() { \
$SV2V $test.sv 2> $SHUNIT_TMPDIR/stderr > $SHUNIT_TMPDIR/stdout; \
assertFalse \"conversion should have failed\" \$?; \
validateOutput $test.sv; \
}"
eval "test_$test() { runErrorTest $test; }"
suite_addTest test_$test
}
......
......@@ -131,3 +131,10 @@ runTest() {
test=$1
simpleTest "${test}.sv" "${test}.v" "${test}_tb.v"
}
runAndCapture() {
$SV2V "$@" > "$SHUNIT_TMPDIR/stdout" 2> "$SHUNIT_TMPDIR/stderr"
result=$?
stdout=`cat $SHUNIT_TMPDIR/stdout`
stderr=`cat $SHUNIT_TMPDIR/stderr`
}
module one;
logic x;
endmodule
#!/bin/bash
clearArtifacts() {
rm -f one.v two.v
}
createArtifacts() {
touch one.v two.v
}
test_prereq() {
for file in `ls *.sv`; do
assertConverts "$file"
done
}
test_default() {
runAndCapture *.sv
assertTrue "default conversion should succeed" $result
assertNotNull "stdout should not be empty" "$stdout"
assertNull "stderr should be empty" "$stderr"
}
test_stdout() {
runAndCapture --write=stdout *.sv
assertTrue "default conversion should succeed" $result
assertNotNull "stdout should not be empty" "$stdout"
assertNull "stderr should be empty" "$stderr"
}
test_adjacent() {
runAndCapture --write=stdout *.sv
expected="$stdout"
runAndCapture --write=adjacent *.sv
assertTrue "adjacent conversion should succeed" $result
assertNull "stdout should be empty" "$stdout"
assertNull "stderr should be empty" "$stderr"
actual=`cat one.v two.v`
assertEquals "adjacent output should match combined" "$expected" "$actual"
clearArtifacts
}
test_adjacent_exist() {
createArtifacts
runAndCapture --write=adjacent *.sv
clearArtifacts
assertFalse "adjacent conversion should fail" $result
assertNull "stdout should be empty" "$stdout"
assertEquals "stderr should list existing files" \
"Refusing to write output because the following files would be overwritten: one.v, two.v" \
"$stderr"
}
test_adjacent_extension() {
createArtifacts
runAndCapture --write=adjacent *.v
clearArtifacts
assertFalse "adjacent conversion should fail" $result
assertNull "stdout should be empty" "$stdout"
assertEquals "stderr should list existing files" \
"Refusing to write adjacent to \"one.v\" because that path does not end in \".sv\"" \
"$stderr"
}
source ../lib/functions.sh
. shunit2
module two;
logic x;
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment