mirror of https://github.com/zachjs/sv2v.git
add write adjacent mode
This commit is contained in:
parent
8eb9523d06
commit
5aea0ee95e
|
|
@ -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
|
||||
|
|
|
|||
12
src/Job.hs
12
src/Job.hs
|
|
@ -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)
|
||||
|
|
|
|||
51
src/sv2v.hs
51
src/sv2v.hs
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#!/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`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
*.v
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
module one;
|
||||
logic x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#!/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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
module two;
|
||||
logic x;
|
||||
endmodule
|
||||
Loading…
Reference in New Issue