diff options
Diffstat (limited to 'src/Test/VeriFuzz/Verilog/Mutate.hs')
-rw-r--r-- | src/Test/VeriFuzz/Verilog/Mutate.hs | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/Test/VeriFuzz/Verilog/Mutate.hs b/src/Test/VeriFuzz/Verilog/Mutate.hs new file mode 100644 index 0000000..b903ec9 --- /dev/null +++ b/src/Test/VeriFuzz/Verilog/Mutate.hs @@ -0,0 +1,80 @@ +{-| +Module : Test.VeriFuzz.Verilog.Mutation +Description : Functions to mutate the Verilog AST. +Copyright : (c) Yann Herklotz Grave 2018 +License : GPL-3 +Maintainer : ymherklotz@gmail.com +Stability : experimental +Portability : POSIX + +Functions to mutate the Verilog AST from "Test.VeriFuzz.Verilog.AST" to generate +more random patterns, such as nesting wires instead of creating new ones. +-} + +module Test.VeriFuzz.Verilog.Mutate where + +import Control.Lens +import Data.Maybe (catMaybes, fromMaybe) +import Test.VeriFuzz.Internal.Gen +import Test.VeriFuzz.Internal.Shared +import Test.VeriFuzz.Verilog.AST + +-- | Return if the 'Identifier' is in a 'ModDecl'. +inPort :: Identifier -> ModDecl -> Bool +inPort id mod = any (\a -> a ^. portName == id) $ mod ^. modPorts + +-- | Find the last assignment of a specific wire/reg to an expression, and +-- returns that expression. +findAssign :: Identifier -> [ModItem] -> Maybe Expression +findAssign id items = + safe last . catMaybes $ isAssign <$> items + where + isAssign (ModCA (ContAssign val expr)) + | val == id = Just $ expr + | otherwise = Nothing + isAssign _ = Nothing + +-- | Transforms an expression by replacing an Identifier with an +-- expression. This is used inside 'transformOf' and 'traverseExpr' to replace +-- the 'Identifier' recursively. +idTrans :: Identifier -> Expression -> Expression -> Expression +idTrans i expr (PrimExpr (PrimId id)) + | id == i = expr + | otherwise = (PrimExpr (PrimId id)) +idTrans _ _ e = e + +-- | Replaces the identifier recursively in an expression. +replace :: Identifier -> Expression -> Expression -> Expression +replace = (transformOf traverseExpr .) . idTrans + +-- | Nest expressions for a specific 'Identifier'. If the 'Identifier' is not found, +-- the AST is not changed. +-- +-- This could be improved by instead of only using the last assignment to the +-- wire that one finds, to use the assignment to the wire before the current +-- expression. This would require a different approach though. +nestId :: Identifier -> ModDecl -> ModDecl +nestId id mod + | not $ inPort id mod = + let expr = fromMaybe def . findAssign id $ mod ^. moduleItems + in mod & get %~ replace id expr + | otherwise = mod + where + get = moduleItems . traverse . _ModCA . contAssignExpr + def = PrimExpr $ PrimId id + +-- | Replaces an identifier by a expression in all the module declaration. +nestSource :: Identifier -> VerilogSrc -> VerilogSrc +nestSource id src = + src & getVerilogSrc . traverse . getDescription %~ nestId id + +-- | Nest variables in the format @w[0-9]*@ up to a certain number. +nestUpTo :: Int -> VerilogSrc -> VerilogSrc +nestUpTo i src = + foldl (flip nestSource) src $ Identifier . fromNode <$> [1..i] + +-- | Add a Module Instantiation using 'ModInst' from the first module passed to +-- it to the body of the second module. +instantiateMod :: ModDecl -> ModDecl -> ModDecl +instantiateMod mod main = + main |