From c1a832419a28ac074cbccbeb7060afd22c36d033 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Tue, 9 Apr 2019 17:00:35 +0100 Subject: Add generation of parameters and constant expressions --- src/VeriFuzz/Verilog/Arbitrary.hs | 2 ++ src/VeriFuzz/Verilog/CodeGen.hs | 26 ++++++++----------- src/VeriFuzz/Verilog/Gen.hs | 54 ++++++++++++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/VeriFuzz/Verilog/Arbitrary.hs b/src/VeriFuzz/Verilog/Arbitrary.hs index aed548b..6655309 100644 --- a/src/VeriFuzz/Verilog/Arbitrary.hs +++ b/src/VeriFuzz/Verilog/Arbitrary.hs @@ -17,6 +17,8 @@ module VeriFuzz.Verilog.Arbitrary , arb , genPositive , exprWithContext + , listOf1 + , listOf ) where diff --git a/src/VeriFuzz/Verilog/CodeGen.hs b/src/VeriFuzz/Verilog/CodeGen.hs index 8f16b23..0ac548a 100644 --- a/src/VeriFuzz/Verilog/CodeGen.hs +++ b/src/VeriFuzz/Verilog/CodeGen.hs @@ -21,16 +21,15 @@ module VeriFuzz.Verilog.CodeGen ) where -import Control.Lens (view, (^.)) -import Data.Foldable (fold) -import Data.List.NonEmpty (NonEmpty (..), toList) -import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Text.IO as T -import Numeric (showHex) +import Control.Lens (view, (^.)) +import Data.Foldable (fold) +import Data.List.NonEmpty (NonEmpty (..), toList) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.IO as T +import Numeric (showHex) import VeriFuzz.Internal import VeriFuzz.Sim.Internal -import VeriFuzz.Verilog.Arbitrary import VeriFuzz.Verilog.AST -- | 'Source' class which determines that source code is able to be generated @@ -60,7 +59,7 @@ moduleDecl (ModDecl i outP inP items ps) = modI = fold $ moduleItem <$> items outIn = outP ++ inP params [] = "" - params (p:pps) = "#(\n" <> paramList (p :| pps) <> "\n)\n" + params (p:pps) = "\n#(\n" <> paramList (p :| pps) <> "\n)\n" -- | Generates a parameter list. Can only be called with a 'NonEmpty' list. paramList :: NonEmpty Parameter -> Text @@ -303,13 +302,10 @@ instance Source ModDecl where instance Source Verilog where genSource = verilogSrc +instance Source SourceInfo where + genSource (SourceInfo _ src) = genSource src + newtype GenVerilog a = GenVerilog { unGenVerilog :: a } instance (Source a) => Show (GenVerilog a) where show = T.unpack . genSource . unGenVerilog - -instance (Arb a) => Arb (GenVerilog a) where - arb = GenVerilog <$> arb - -instance Source SourceInfo where - genSource (SourceInfo _ src) = genSource src diff --git a/src/VeriFuzz/Verilog/Gen.hs b/src/VeriFuzz/Verilog/Gen.hs index 6f50f19..ae72b9f 100644 --- a/src/VeriFuzz/Verilog/Gen.hs +++ b/src/VeriFuzz/Verilog/Gen.hs @@ -28,6 +28,7 @@ import Data.Foldable (fold) import qualified Data.Text as T import Hedgehog (Gen) import qualified Hedgehog.Gen as Hog +import qualified Hedgehog.Range as Hog import VeriFuzz.Config import VeriFuzz.Internal import VeriFuzz.Verilog.Arbitrary @@ -36,6 +37,7 @@ import VeriFuzz.Verilog.Internal import VeriFuzz.Verilog.Mutate data Context = Context { _variables :: [Port] + , _parameters :: [Parameter] , _nameCounter :: Int , _stmntDepth :: Int } @@ -89,6 +91,11 @@ some f = do amount <- gen genPositive replicateM amount f +many :: StateGen a -> StateGen [a] +many f = do + amount <- gen $ Hog.int (Hog.linear 0 10) + replicateM amount f + makeIdentifier :: T.Text -> StateGen Identifier makeIdentifier prefix = do context <- get @@ -151,10 +158,11 @@ statement :: StateGen Statement statement = do prob <- askProbability cont <- get + let defProb i = prob ^. probStmnt . i Hog.frequency - [ (prob ^. probBlock , BlockAssign <$> assignment) - , (prob ^. probNonBlock , NonBlockAssign <$> assignment) - , (onDepth cont (prob ^. probCond), conditional) + [ (defProb probStmntBlock , BlockAssign <$> assignment) + , (defProb probStmntNonBlock , NonBlockAssign <$> assignment) + , (onDepth cont (defProb probStmntCond), conditional) ] where onDepth c n = if c ^. stmntDepth > 0 then n else 0 @@ -167,9 +175,10 @@ always = do modItem :: StateGen ModItem modItem = do prob <- askProbability + let defProb i = prob ^. probModItem . i Hog.frequency - [ (prob ^. probAssign, ModCA <$> contAssign) - , (prob ^. probAlways, always) + [ (defProb probModItemAssign, ModCA <$> contAssign) + , (defProb probModItemAlways, always) ] moduleName :: Maybe Identifier -> StateGen Identifier @@ -184,6 +193,37 @@ initialBlock = do where makeAssign p = NonBlockAssign $ Assign (lvalFromPort p) Nothing 0 +constExprWithContext :: [Parameter] -> ProbExpr -> Hog.Size -> Gen ConstExpr +constExprWithContext ps prob size + | size == 0 = Hog.frequency + [ (prob ^. probExprNum, ConstNum <$> genPositive <*> arb) + , (if null ps then 0 else prob ^. probExprId, ParamId . view paramIdent <$> Hog.element ps) + ] + | size > 0 = Hog.frequency + [ (prob ^. probExprNum, ConstNum <$> genPositive <*> arb) + , (if null ps then 0 else prob ^. probExprId, ParamId . view paramIdent <$> Hog.element ps) + , (prob ^. probExprUnOp, ConstUnOp <$> arb <*> subexpr 2) + , (prob ^. probExprBinOp, ConstBinOp <$> subexpr 2 <*> arb <*> subexpr 2) + , (prob ^. probExprCond, ConstCond <$> subexpr 3 <*> subexpr 3 <*> subexpr 3) + , (prob ^. probExprConcat, ConstConcat <$> listOf1 (subexpr 8)) + ] + | otherwise = constExprWithContext ps prob 0 + where subexpr y = constExprWithContext ps prob $ size `div` y + +constExpr :: StateGen ConstExpr +constExpr = do + prob <- askProbability + context <- get + gen . Hog.sized $ constExprWithContext (context ^. parameters) (prob ^. probExpr) + +parameter :: StateGen Parameter +parameter = do + ident <- makeIdentifier "param" + cexpr <- constExpr + let param = Parameter ident cexpr + parameters %= (param :) + return $ param + -- | Generates a module definition randomly. It always has one output port which -- is set to @y@. The size of @y@ is the total combination of all the locally -- defined wires, so that it correctly reflects the internal state of the @@ -200,7 +240,7 @@ moduleDef top = do let clock = Port Wire False 1 "clk" let yport = Port Wire False size "y" let comb = combineAssigns_ yport local - return . declareMod local $ ModDecl name [yport] (clock:portList) (initBlock : mi <> [comb]) [] + declareMod local . ModDecl name [yport] (clock:portList) (initBlock : mi <> [comb]) <$> many parameter -- | Procedural generation method for random Verilog. Uses internal 'Reader' and -- 'State' to keep track of the current Verilog code structure. @@ -209,5 +249,5 @@ procedural config = Verilog . (: []) <$> Hog.resize num (runReaderT (evalStateT (moduleDef (Just "top")) context) config) where - context = Context [] 0 $ config ^. configProperty . propDepth + context = Context [] [] 0 $ config ^. configProperty . propDepth num = fromIntegral $ config ^. configProperty . propSize -- cgit