aboutsummaryrefslogtreecommitdiffstats
path: root/src/Verismith/OptParser.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Verismith/OptParser.hs')
-rw-r--r--src/Verismith/OptParser.hs262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/Verismith/OptParser.hs b/src/Verismith/OptParser.hs
new file mode 100644
index 0000000..a475e9a
--- /dev/null
+++ b/src/Verismith/OptParser.hs
@@ -0,0 +1,262 @@
+module Verismith.OptParser
+ ( OptTool (..)
+ , Opts (..)
+ , opts
+ )
+where
+
+import Control.Applicative ((<|>))
+import Data.Text (Text)
+import qualified Data.Text as T
+import Options.Applicative (Mod (..), OptionFields (..), Parser (..),
+ ParserInfo (..), ReadM (..), (<**>))
+import qualified Options.Applicative as Opt
+import Prelude hiding (FilePath (..))
+import Shelly (FilePath (..), fromText)
+import Verismith.Config (SynthDescription (..), versionInfo)
+
+data OptTool = TYosys
+ | TXST
+ | TIcarus
+
+instance Show OptTool where
+ show TYosys = "yosys"
+ show TXST = "xst"
+ show TIcarus = "icarus"
+
+data Opts = Fuzz { fuzzOutput :: {-# UNPACK #-} !Text
+ , fuzzConfigFile :: !(Maybe FilePath)
+ , fuzzForced :: !Bool
+ , fuzzKeepAll :: !Bool
+ , fuzzNum :: {-# UNPACK #-} !Int
+ , fuzzNoSim :: !Bool
+ , fuzzNoEquiv :: !Bool
+ , fuzzNoReduction :: !Bool
+ }
+ | Generate { generateFilename :: !(Maybe FilePath)
+ , generateConfigFile :: !(Maybe FilePath)
+ }
+ | Parse { parseFilename :: {-# UNPACK #-} !FilePath
+ }
+ | Reduce { reduceFilename :: {-# UNPACK #-} !FilePath
+ , reduceTop :: {-# UNPACK #-} !Text
+ , reduceScript :: !(Maybe FilePath)
+ , reduceSynthesiserDesc :: ![SynthDescription]
+ , reduceRerun :: !Bool
+ }
+ | ConfigOpt { configOptWriteConfig :: !(Maybe FilePath)
+ , configOptConfigFile :: !(Maybe FilePath)
+ , configOptDoRandomise :: !Bool
+ }
+
+textOption :: Mod OptionFields String -> Parser Text
+textOption = fmap T.pack . Opt.strOption
+
+optReader :: (String -> Maybe a) -> ReadM a
+optReader f = Opt.eitherReader $ \arg -> case f arg of
+ Just a -> Right a
+ Nothing -> Left $ "Cannot parse option: " <> arg
+
+parseSynth :: String -> Maybe OptTool
+parseSynth val | val == "yosys" = Just TYosys
+ | val == "xst" = Just TXST
+ | otherwise = Nothing
+
+parseSynthDesc :: String -> Maybe SynthDescription
+parseSynthDesc val
+ | val == "yosys" = Just $ SynthDescription "yosys" Nothing Nothing Nothing
+ | val == "vivado" = Just $ SynthDescription "vivado" Nothing Nothing Nothing
+ | val == "xst" = Just $ SynthDescription "xst" Nothing Nothing Nothing
+ | val == "quartus" = Just
+ $ SynthDescription "quartus" Nothing Nothing Nothing
+ | val == "identity" = Just
+ $ SynthDescription "identity" Nothing Nothing Nothing
+ | otherwise = Nothing
+
+parseSim :: String -> Maybe OptTool
+parseSim val | val == "icarus" = Just TIcarus
+ | otherwise = Nothing
+
+fuzzOpts :: Parser Opts
+fuzzOpts =
+ Fuzz
+ <$> textOption
+ ( Opt.long "output"
+ <> Opt.short 'o'
+ <> Opt.metavar "DIR"
+ <> Opt.help "Output directory that the fuzz run takes place in."
+ <> Opt.showDefault
+ <> Opt.value "output")
+ <*> ( Opt.optional
+ . Opt.strOption
+ $ Opt.long "config"
+ <> Opt.short 'c'
+ <> Opt.metavar "FILE"
+ <> Opt.help "Config file for the current fuzz run.")
+ <*> (Opt.switch $ Opt.long "force" <> Opt.short 'f' <> Opt.help
+ "Overwrite the specified directory.")
+ <*> (Opt.switch $ Opt.long "keep" <> Opt.short 'k' <> Opt.help
+ "Keep all the directories.")
+ <*> ( Opt.option Opt.auto
+ $ Opt.long "num"
+ <> Opt.short 'n'
+ <> Opt.help "The number of fuzz runs that should be performed."
+ <> Opt.showDefault
+ <> Opt.value 1
+ <> Opt.metavar "INT")
+ <*> (Opt.switch $ Opt.long "no-sim" <> Opt.help
+ "Do not run simulation on the output netlist.")
+ <*> (Opt.switch $ Opt.long "no-equiv" <> Opt.help
+ "Do not run an equivalence check on the output netlist.")
+ <*> (Opt.switch $ Opt.long "no-reduction" <> Opt.help
+ "Do not run reduction on a failed testcase.")
+
+genOpts :: Parser Opts
+genOpts =
+ Generate
+ <$> ( Opt.optional
+ . Opt.strOption
+ $ Opt.long "output"
+ <> Opt.short 'o'
+ <> Opt.metavar "FILE"
+ <> Opt.help "Output to a verilog file instead."
+ )
+ <*> ( Opt.optional
+ . Opt.strOption
+ $ Opt.long "config"
+ <> Opt.short 'c'
+ <> Opt.metavar "FILE"
+ <> Opt.help "Config file for the generation run."
+ )
+
+parseOpts :: Parser Opts
+parseOpts = Parse . fromText . T.pack <$> Opt.strArgument
+ (Opt.metavar "FILE" <> Opt.help "Verilog input file.")
+
+reduceOpts :: Parser Opts
+reduceOpts =
+ Reduce
+ . fromText
+ . T.pack
+ <$> Opt.strArgument (Opt.metavar "FILE" <> Opt.help "Verilog input file.")
+ <*> textOption
+ ( Opt.short 't'
+ <> Opt.long "top"
+ <> Opt.metavar "TOP"
+ <> Opt.help "Name of top level module."
+ <> Opt.showDefault
+ <> Opt.value "top"
+ )
+ <*> ( Opt.optional
+ . Opt.strOption
+ $ Opt.long "script"
+ <> Opt.metavar "SCRIPT"
+ <> Opt.help
+ "Script that determines if the current file is interesting, which is determined by the script returning 0."
+ )
+ <*> ( Opt.many
+ . Opt.option (optReader parseSynthDesc)
+ $ Opt.short 's'
+ <> Opt.long "synth"
+ <> Opt.metavar "SYNTH"
+ <> Opt.help "Specify synthesiser to use."
+ )
+ <*> ( Opt.switch
+ $ Opt.short 'r'
+ <> Opt.long "rerun"
+ <> Opt.help
+ "Only rerun the current synthesis file with all the synthesisers."
+ )
+
+configOpts :: Parser Opts
+configOpts =
+ ConfigOpt
+ <$> ( Opt.optional
+ . Opt.strOption
+ $ Opt.long "output"
+ <> Opt.short 'o'
+ <> Opt.metavar "FILE"
+ <> Opt.help "Output to a TOML Config file."
+ )
+ <*> ( Opt.optional
+ . Opt.strOption
+ $ Opt.long "config"
+ <> Opt.short 'c'
+ <> Opt.metavar "FILE"
+ <> Opt.help "Config file for the current fuzz run."
+ )
+ <*> ( Opt.switch
+ $ Opt.long "randomise"
+ <> Opt.short 'r'
+ <> Opt.help
+ "Randomise the given default config, or the default config by randomly switchin on and off options."
+ )
+
+argparse :: Parser Opts
+argparse =
+ Opt.hsubparser
+ ( Opt.command
+ "fuzz"
+ (Opt.info
+ fuzzOpts
+ (Opt.progDesc
+ "Run fuzzing on the specified simulators and synthesisers."
+ )
+ )
+ <> Opt.metavar "fuzz"
+ )
+ <|> Opt.hsubparser
+ ( Opt.command
+ "generate"
+ (Opt.info
+ genOpts
+ (Opt.progDesc "Generate a random Verilog program.")
+ )
+ <> Opt.metavar "generate"
+ )
+ <|> Opt.hsubparser
+ ( Opt.command
+ "parse"
+ (Opt.info
+ parseOpts
+ (Opt.progDesc
+ "Parse a verilog file and output a pretty printed version."
+ )
+ )
+ <> Opt.metavar "parse"
+ )
+ <|> Opt.hsubparser
+ ( Opt.command
+ "reduce"
+ (Opt.info
+ reduceOpts
+ (Opt.progDesc
+ "Reduce a Verilog file by rerunning the fuzzer on the file."
+ )
+ )
+ <> Opt.metavar "reduce"
+ )
+ <|> Opt.hsubparser
+ ( Opt.command
+ "config"
+ (Opt.info
+ configOpts
+ (Opt.progDesc
+ "Print the current configuration of the fuzzer."
+ )
+ )
+ <> Opt.metavar "config"
+ )
+
+version :: Parser (a -> a)
+version = Opt.infoOption versionInfo $ mconcat
+ [Opt.long "version", Opt.short 'v', Opt.help "Show version information.", Opt.hidden]
+
+opts :: ParserInfo Opts
+opts = Opt.info
+ (argparse <**> Opt.helper <**> version)
+ ( Opt.fullDesc
+ <> Opt.progDesc "Fuzz different simulators and synthesisers."
+ <> Opt.header
+ "Verismith - A hardware simulator and synthesiser Verilog fuzzer."
+ )