diff --git a/src/Verismith.hs b/src/Verismith.hs index 2d54cb1..ef53d87 100644 --- a/src/Verismith.hs +++ b/src/Verismith.hs @@ -248,7 +248,10 @@ handleOpts (Parse f o s popts) = do if null warns || not s then pure () else error "Input file does not comply strictly with the Verilog 2005 standard" - maybe L.putStr L.writeFile o $ V2.genSource (Just 80) popts ast + ast' <- case V2.resolveInsts ast of + Left err -> error err + Right x -> pure x + maybe L.putStr L.writeFile o $ V2.genSource (Just 80) popts ast' handleOpts (ShuffleOpt f t o nshuffle nrename noequiv equivdir checker) = do datadir <- getDataDir verilogSrc <- T.readFile file diff --git a/src/Verismith/Config.hs b/src/Verismith/Config.hs index f91fde5..bfb1de8 100644 --- a/src/Verismith/Config.hs +++ b/src/Verismith/Config.hs @@ -415,6 +415,7 @@ data GarbageModuleOpts = GarbageModuleOpts _gmoOptionalPort :: !Double, _gmoItems :: !NumberProbability, _gmoItem :: !CategoricalProbability, + _gmoMacro :: !Double, _gmoTimeScale :: !Double, _gmoTimeMagnitude :: !CategoricalProbability, _gmoCell :: !Double, @@ -615,6 +616,7 @@ defGarbageOpts = _gmoOptionalPort = 0.5, _gmoItems = NPPoisson 0 3, _gmoItem = CPDiscrete [6, 2, 2, 3, 2, 1, 1, 1], + _gmoMacro = 0.5, _gmoTimeScale = 0.5, _gmoTimeMagnitude = uniformCP, _gmoCell = 0.5, @@ -1156,6 +1158,7 @@ garbageModuleCodec = <*> dfield _gmoOptionalPort "port_optional" <*> tfield _gmoItems "items" numProbCodec <*> tfield _gmoItem "item" catProbCodec + <*> dfield _gmoMacro "macromodule" <*> dfield _gmoTimeScale "timescale_optional" <*> tfield _gmoTimeMagnitude "timescale_magnitude" catProbCodec <*> dfield _gmoCell "cell" diff --git a/src/Verismith/Verilog2005.hs b/src/Verismith/Verilog2005.hs index 9a57a79..ea34efb 100644 --- a/src/Verismith/Verilog2005.hs +++ b/src/Verismith/Verilog2005.hs @@ -13,7 +13,8 @@ module Verismith.Verilog2005 NumberProbability, CategoricalProbability, Verilog2005 (..), - PrintingOpts (..) + PrintingOpts (..), + resolveInsts ) where @@ -22,3 +23,4 @@ import Verismith.Verilog2005.AST import Verismith.Verilog2005.Generator import Verismith.Verilog2005.Parser import Verismith.Verilog2005.PrettyPrinter +import Verismith.Verilog2005.Utils diff --git a/src/Verismith/Verilog2005/AST.hs b/src/Verismith/Verilog2005/AST.hs index 46bf6ea..f2cdd49 100644 --- a/src/Verismith/Verilog2005/AST.hs +++ b/src/Verismith/Verilog2005/AST.hs @@ -1,5 +1,5 @@ -- Module : Verismith.Verilog2005.AST --- Description : Partial Verilog 2005 AST. +-- Description : Verilog 2005 AST. -- Copyright : (c) 2023 Quentin Corradi -- License : GPL-3 -- Maintainer : q [dot] corradi22 [at] imperial [dot] ac [dot] uk @@ -190,6 +190,13 @@ data Identified t = Identified {_identIdent :: !Identifier, _identData :: !t} instance Functor Identified where fmap f (Identified i x) = Identified i $ f x +instance Foldable Identified where + foldr f acc (Identified i x) = f x acc + +instance Traversable Identified where + traverse f (Identified i x) = Identified i <$> f x + sequenceA (Identified i x) = Identified i <$> x + showHelper :: (Int -> a -> ShowS) -> Identified a -> ShowS showHelper fp (Identified i x) = showString "Identified " . shows i . showChar ' ' . fp 0 x @@ -420,7 +427,6 @@ data NumIdent | NINumber !Natural deriving (Show, Eq, Data, Generic) --- TODO? Base and 1 can be expressed as 3, not 2 though, option delay means delay 0 -- | Delay3 data Delay3 = D3Base !NumIdent @@ -650,7 +656,7 @@ data FunctionStatement | FSBlock { _fsbHeader :: !(Maybe (Identifier, [AttrIded StdBlockDecl])), _fsbPar_seq :: !Bool, - _fsbStmt :: ![AttrFStmt] + _fsbBody :: ![AttrFStmt] } deriving (Show, Eq, Data, Generic) @@ -696,7 +702,7 @@ data Statement | SBlock { _sbHeader :: !(Maybe (Identifier, [AttrIded StdBlockDecl])), _sbPar_seq :: !Bool, - _sbStmt :: ![AttrStmt] + _sbBody :: ![AttrStmt] } | SSysTaskEnable { _ssteIdent :: !ByteString, @@ -1189,9 +1195,9 @@ data ModuleItem type GenerateBlock = Identified [Attributed ModGenBlockedItem] -- | Module block --- TODO: remember whether the module is a module or macromodule because implementation dependent data ModuleBlock = ModuleBlock { _mbAttr :: !Attributes, + _mbMacro :: !Bool, _mbIdent :: !Identifier, _mbPortInter :: ![Identified [Identified (Maybe CRangeExpr)]], _mbBody :: ![ModuleItem], diff --git a/src/Verismith/Verilog2005/Generator.hs b/src/Verismith/Verilog2005/Generator.hs index 16a81fc..bdfcd24 100644 --- a/src/Verismith/Verilog2005/Generator.hs +++ b/src/Verismith/Verilog2005/Generator.hs @@ -18,6 +18,7 @@ where import Control.Applicative (liftA2, liftA3) import Data.Functor.Compose +import Data.Bifunctor (second) import Control.Lens hiding ((<.>)) import Control.Monad (join, replicateM) import Control.Monad.Reader @@ -79,7 +80,7 @@ attenuateNum d p = then NPDiscrete [(1, off)] else NPPoisson off $ p * d NPDiscrete l -> NPDiscrete $ if d == 0 then [NE.head l] else NE.map (uncurry mkdistrfor) l - NPLinearComb l -> NPLinearComb $ NE.map (\(p, np) -> (p, attenuateNum d np)) l + NPLinearComb l -> NPLinearComb $ NE.map (second $ attenuateNum d) l where mkdistrfor bw n = (bw * d ** fromIntegral n, n) @@ -936,6 +937,7 @@ garbageModuleBlock ts = do garbageIdentified $ sampleMaybe (m _gmoPortRange) garbageCRangeExpr else (\i -> Identified i [Identified i Nothing]) <$> garbageIdent ModuleBlock <$> garbageAttributes + <*> sampleBernoulli (m _gmoMacro) <*> garbageIdent <*> pure header <*> sampleN diff --git a/src/Verismith/Verilog2005/Lexer.x b/src/Verismith/Verilog2005/Lexer.x index 0b195a2..0fec194 100644 --- a/src/Verismith/Verilog2005/Lexer.x +++ b/src/Verismith/Verilog2005/Lexer.x @@ -25,9 +25,11 @@ import Numeric.Natural import GHC.Natural import Data.List.NonEmpty (NonEmpty (..)) import Data.Maybe (mapMaybe) +import Data.Bifunctor (second) import Text.Printf (printf) import Control.Monad.State.Strict import Control.Monad.Except +import Control.Monad import Control.Exception import qualified Data.ByteString as SBS import qualified Data.ByteString.Lazy as LBS @@ -281,7 +283,7 @@ to :: (SBS.ByteString -> Token) -> AlexAction to f p = mkPos p . f toa :: (SBS.ByteString -> Alex Token) -> AlexAction -toa f p s = f s >>= mkPos p +toa f p = f >=> mkPos p sc :: Int -> Alex () sc n = modify' $ \s -> s { _asStartCode = n } @@ -384,18 +386,16 @@ tableEdge s = cdcident :: AlexAction cdcident p s = case HashMap.lookup (SBS.tail s) cdMap of Just a -> a p - Nothing -> do - defs <- gets _asDefines - case HashMap.lookup s defs of - Nothing -> - alexError p $ - printf "Compiler directive %s not declared nor supported, preprocess input file" $ - show s - Just i -> - alexError p $ - printf - "User defined compiler directive replacement in not implemented, %s was encountered" - (show s) + Nothing -> gets _asDefines >>= \defs -> case HashMap.lookup s defs of + Nothing -> + alexError p $ + printf "Compiler directive %s not declared nor supported, preprocess input file" $ + show s + Just i -> + alexError p $ + printf + "User defined compiler directive replacement in not implemented, %s was encountered" + (show s) kwident :: SBS.ByteString -> Alex Token kwident s = case SBS.stripPrefix "PATHPULSE$" s of @@ -443,11 +443,11 @@ cdMap = HashMap.fromList $ : ("undefineall", \_ -> modify' (\s -> s { _asDefines = HashMap.empty }) >> scan) : ("__LINE__", \p -> mkPos p $ LitString $ packChars $ show $ _posLine p) : ("__FILE__", \p -> mkPos p $ LitString $ makeString $ show $ _posSource p) - : map (\(x, y) -> (x, \p -> y >>= mkPos p)) - ( ("timescale", sc ts0 >> return CDTimescale) - : ("resetall", modify' (\s -> s { _asDefines = HashMap.empty }) >> return CDResetall) - -- , ("pragma", >> return CDPragma) -- TODO: Another layer of hell - : map (\(x, y) -> (x, return y)) + : map (second (\y p -> y >>= mkPos p)) + ( ("timescale", sc ts0 *> pure CDTimescale) + : ("resetall", modify' (\s -> s { _asDefines = HashMap.empty }) *> pure CDResetall) + -- , ("pragma", *> pure CDPragma) -- TODO: Another layer of hell + : map (second pure) [ ("celldefine", CDCelldefine) , ("default_nettype", CDDefaultnettype) -- , ("default_decay_time", CDUnknown) @@ -485,7 +485,7 @@ linecompdir _ = do l <- scan f <- scan c <- scan - case l >>= \ll -> f >>= \ff -> c >>= \cc -> pure (ll, ff, cc) of + case (,,) <$> l <*> f <*> c of Nothing -> return Nothing Just (PosToken _ (LitDecimal l), PosToken _ (LitString s), PosToken _ (LitDecimal n)) | n < 3 -> do @@ -568,7 +568,7 @@ kwV1995 = ("default", pure KWDefault), ("defparam", pure KWDefparam), ("disable", pure KWDisable), - ("edge", sc edge >> pure KWEdge), + ("edge", sc edge *> pure KWEdge), ("else", pure KWElse), ("end", pure KWEnd), ("endcase", pure KWEndcase), @@ -576,7 +576,7 @@ kwV1995 = ("endmodule", pure KWEndmodule), ("endprimitive", pure KWEndprimitive), ("endspecify", pure KWEndspecify), - ("endtable", sc 0 >> pure KWEndtable), + ("endtable", sc 0 *> pure KWEndtable), ("endtask", pure KWEndtask), ("event", pure KWEvent), ("for", pure KWFor), @@ -633,7 +633,7 @@ kwV1995 = ("strong1", pure KWStrong1), ("supply0", pure KWSupply0), ("supply1", pure KWSupply1), - ("table", sc table >> pure KWTable), + ("table", sc table *> pure KWTable), ("task", pure KWTask), ("time", pure KWTime), ("tran", pure KWTran), diff --git a/src/Verismith/Verilog2005/Mutation.hs b/src/Verismith/Verilog2005/Mutation.hs new file mode 100644 index 0000000..bebc1be --- /dev/null +++ b/src/Verismith/Verilog2005/Mutation.hs @@ -0,0 +1,616 @@ +-- Module : Verismith.Verilog2005.Mutation +-- Description : AST mutation. +-- Copyright : (c) 2024 Quentin Corradi +-- License : GPL-3 +-- Maintainer : q [dot] corradi22 [at] imperial [dot] ac [dot] uk +-- Stability : experimental +-- Portability : POSIX + +{-# LANGUAGE RankNTypes #-} +-- {-# LANGUAGE OverloadedLists #-} + +module Verismith.Verilog2005.Mutation + ( + ) +where + +import Data.Typeable +import Data.Maybe +import Data.List.NonEmpty (NonEmpty) +import Data.Bifunctor (second) +import Data.Bitraversable (bitraverse) +import GHC.IsList +import Control.Monad +import Control.Monad.Reader +import Verismith.Utils (mkpair) +import Verismith.Verilog2005.Randomness +import Verismith.Verilog2005.AST +import Verismith.Verilog2005.Utils (fromStatement, toStatement) + +data MutationOpts = MutationOpts + { _moIdentity :: !Double + } + +data MutationStore = MutationStore + { _msMTM :: !(forall t. MutationVector (GenMinTypMax t)), + _msPrim :: !(forall i r a. MutationVector (GenPrim i r a)), + _msExpr :: !(forall i r a. MutationVector (GenExpr i r a)), + _msAttr :: !(MutationVector Attributes), + _msRangeExpr :: !(forall t. MutationVector (GenRangeExpr t)), + _msLValue :: !(forall t. MutationVector (LValue t)), + _msAssign :: !(forall t. MutationVector (Assign t)), + _msEventPrim :: !(MutationVector EventPrim), + _msDelay1 :: !(MutationVector Delay1), + _msDelay2 :: !(MutationVector Delay2), + _msDelay3 :: !(MutationVector Delay3), + _msLoopStmt :: !(MutationVector LoopStatement), + _msCasePat :: !(forall t. MutationVector (NonEmpty t)), + _msStmt :: !(MutationVector Statement), + _msGenCond :: !(MutationVector ModGenCondItem), + _msGenBlk :: !(MutationVector GenerateBlock), + _msModGenItem :: !(MutationVector ModGenBlockedItem), + _msModItem :: !(MutationVector ModuleItem), + _msPDV :: !(MutationVector PathDelayValue), + _msSpecItem :: !(MutationVector SpecifyBlockedItem), + _msModule :: !(MutationVector ModuleBlock), + _msPrimTable :: !(MutationVector PrimTable), + _msPrimitive :: !(MutationVector PrimitiveBlock), + _msV2005 :: !(MutationVector Verilog2005), + _msList :: !(forall t. IsList t => MutationVector t) + } + +type Mutator = GenM MutationStore +type PureMutation t = t -> Maybe t +type PrimMutation t = t -> Maybe (Mutator t) +type MutationVector t = [(Double, PrimMutation t)] +type Mutation t = t -> Mutator t + +-- Mutation list: +-- MTM-> if single make 3, if 3 and same merge +-- Identifier: Need to build the name hierarchy, only doable at module/Primitive/Generate/Config/function/whatever level +-- Prim-> conversion of constant to a specific representation, concat one, multconcat from concat +-- Function changes at global level +-- Expression splitting at MGI level +-- Concat reordering then fixing the references at global level +-- Expr-> ternary branch swapping, "-"-"+ -", "*1"-"", "/1"-"", "+0"-"", constant folding, +-- "*x/x"-"", plus assoc, plus commut, times commut, times assoc, "~ +1"-"-", "- -1"-"~", "un+"-"", +-- "!"-"&~", "!"-"~|", "|"-"!=0", "|~"-"~&", "~ &"-"~&", "~ |"-"~|", "! |"-"~|", "! &"-"~&", +-- "~ ^"-"~^", "! ^"-"~^", "~ ~"-"" +-- Some may be incorrect because of signedness +-- type aware rewrites? neq is |xor, "- -"-"", all rewrites in my ESA +-- GenRangeExpr-> make single, make pair, make baseoff+ and baseoff +-- Delay-> 1/B to make2, 1/B to make3, B/2/3 to make1, 1 to Base +-- SignRange: Change range and range references, change signedness and correct at callsite +-- Assignment: At Global Level, rename; if never referenced elswhere, Merge Expr; At local level, Split Expr +-- Parameter: At global level, rename, shuffle, offset the value at assign and deoffset at use +-- ParamOver (DefParam): At MGI level, change the value inside the module instantiation and put the real value in a defparam, resolve the defparam +-- (Param/Port)Assign: At global level or with enough info, change a named for a positional and the other way around +-- EventPrim-> change edge and expression accordingly +-- EventControl: at statement level, Deps <-> Expr +-- LoopStatement-> repeat-for, for-while, forever-for +-- Statement: Check ESA, if/case-loop +-- BlockDecl: At Block level, rename +-- ModGenCondItem-> If-Case comversion, If transforms, Case-transforms, check ESA +-- ModGenItem-> See ESA, gate conversion, always-initial forever, cond-loop +-- PathDelayValue-> refer to conversion table + +-- buildStore :: MutationOpts -> MutationStore +-- TODO + +mutate :: MutationVector t -> Mutation t +mutate v x = join $ sampleWeighted $ mapMaybe (traverse ($ x)) v + +mutateWith :: (MutationStore -> MutationVector t) -> Mutation t +mutateWith p x = asks (p . fst) >>= flip mutate x + +mutateList :: IsList t => Mutation t +mutateList l = fromList <$> mutateWith _msList (toList l) + +mutateGMTM :: Mutation t -> Mutation (GenMinTypMax t) +mutateGMTM f = mutateWith _msMTM >=> \x -> case x of + MTMSingle e -> MTMSingle <$> f e + MTMFull em et eM -> MTMFull <$> f em <*> f et <*> f eM + +mutateCMTM :: Mutation CMinTypMax +mutateCMTM = mutateGMTM mutateCExpr + +mutateMTM :: Mutation MinTypMax +mutateMTM = mutateGMTM mutateExpr + +mutatePrim :: Mutation i -> Mutation r -> Mutation a -> Mutation (GenPrim i r a) +mutatePrim fi fr fa = mutateWith _msPrim >=> \x -> case x of + PrimIdent i r -> PrimIdent <$> fi i <*> fr r + PrimConcat c -> PrimConcat <$> mapM mExpr c + PrimMultConcat m c -> + PrimMultConcat <$> mutateGExpr pure (traverse mutateCRE) fa m <*> mapM mExpr c + PrimFun i a args -> PrimFun <$> fi i <*> fa a <*> mapM mExpr args + PrimSysFun i args -> PrimSysFun i <$> mapM mExpr args + PrimMinTypMax m -> PrimMinTypMax <$> mutateGMTM mExpr m + _ -> pure x + where mExpr = mutateGExpr fi fr fa + +mutateHI :: Mutation HierIdent +mutateHI (HierIdent p i) = flip HierIdent i <$> mapM (traverse $ traverse mutateCExpr) p + +mutateGDR :: Mutation e -> Mutation (GenDimRange e) +mutateGDR f (GenDimRange d r) = GenDimRange <$> mapM f d <*> mutateGRE f r + +mutateDR :: Mutation DimRange +mutateDR = mutateGDR mutateExpr + +mutateCDR :: Mutation CDimRange +mutateCDR = mutateGDR mutateCExpr + +mutateGExpr :: Mutation i -> Mutation r -> Mutation a -> Mutation (GenExpr i r a) +mutateGExpr fi fr fa = mutateWith _msExpr >=> \x -> case x of + ExprPrim p -> ExprPrim <$> mPrim p + ExprUnOp op a p -> ExprUnOp op <$> fa a <*> mPrim p + ExprBinOp l op a r -> flip ExprBinOp op <$> mExpr l <*> fa a <*> mExpr r + ExprCond c a t f -> ExprCond <$> mExpr c <*> fa a <*> mExpr t <*> mExpr f + where + mExpr = mutateGExpr fi fr fa + mPrim = mutatePrim fi fr fa + +mutateCExpr :: Mutation CExpr +mutateCExpr (CExpr e) = CExpr <$> mutateGExpr pure (traverse mutateCRE) mutateAttr e + +mutateExpr :: Mutation Expr +mutateExpr (Expr e) = Expr <$> mutateGExpr mutateHI (traverse mutateDR) mutateAttr e + +mutateAttr :: Mutation Attributes +mutateAttr = mutateWith _msAttr >=> mutateList >=> mapM (mapM mAttr) + where + mAttr (Attribute i v) = Attribute i <$> traverse (mutateGExpr pure (traverse mutateCRE) pure) v + +mutateAttributed :: Mutation t -> Mutation (Attributed t) +mutateAttributed f (Attributed a x) = Attributed <$> mutateAttr a <*> f x + +mutateAttrIded :: Mutation t -> Mutation (AttrIded t) +mutateAttrIded f (AttrIded a i x) = flip AttrIded i <$> mutateAttr a <*> f x + +mutateR2 :: Mutation Range2 +mutateR2 (Range2 m l) = Range2 <$> mutateCExpr m <*> mutateCExpr l + +mutateGRE :: Mutation e -> Mutation (GenRangeExpr e) +mutateGRE f = mutateWith _msRangeExpr >=> \x -> case x of + GRESingle e -> GRESingle <$> f e + GREPair r2 -> GREPair <$> mutateR2 r2 + GREBaseOff b mp o -> flip GREBaseOff mp <$> f b <*> mutateCExpr o + +mutateRE :: Mutation RangeExpr +mutateRE = mutateGRE mutateExpr + +mutateCRE :: Mutation CRangeExpr +mutateCRE = mutateGRE mutateCExpr + +mutateD3 :: Mutation Delay3 +mutateD3 = mutateWith _msDelay3 >=> \x -> case x of + D31 m -> D31 <$> mutateMTM m + D32 r f -> D32 <$> mutateMTM r <*> mutateMTM f + D33 r f h -> D33 <$> mutateMTM r <*> mutateMTM f <*> mutateMTM h + _ -> pure x + +mutateD2 :: Mutation Delay2 +mutateD2 = mutateWith _msDelay2 >=> \x -> case x of + D21 m -> D21 <$> mutateMTM m + D22 r f -> D22 <$> mutateMTM r <*> mutateMTM f + _ -> pure x + +mutateD1 :: Mutation Delay1 +mutateD1 = mutateWith _msDelay1 >=> \x -> case x of + D11 m -> D11 <$> mutateMTM m + _ -> pure x + +mutateSR :: Mutation SignRange +mutateSR (SignRange sn r) = SignRange sn <$> traverse mutateR2 r + +mutateST :: Mutation SpecTerm +mutateST (SpecTerm i r) = SpecTerm i <$> traverse mutateCRE r + +mutateCT :: Mutation (ComType t) +mutateCT x = case x of + CTConcrete e sr -> CTConcrete e <$> mutateSR sr + _ -> pure x + +mutateLV :: Mutation dr -> Mutation (LValue dr) +mutateLV f = mutateWith _msLValue >=> \x -> case x of + LVSingle hi dr -> LVSingle <$> mutateHI hi <*> traverse f dr + LVConcat l -> LVConcat <$> mapM (mutateLV f) l + +mutateNLV :: Mutation NetLValue +mutateNLV = mutateLV mutateCDR + +mutateVLV :: Mutation VarLValue +mutateVLV = mutateLV mutateDR + +mutateAss :: Mutation dr -> Mutation (Assign dr) +mutateAss f = mutateWith _msAssign >=> \(Assign lv e) -> Assign <$> mutateLV f lv <*> mutateExpr e + +mutateNAss :: Mutation NetAssign +mutateNAss = mutateAss mutateCDR + +mutateVAss :: Mutation VarAssign +mutateVAss = mutateAss mutateDR + +mutateParam :: Mutation Parameter +mutateParam (Parameter t v) = Parameter <$> mutateCT t <*> mutateCMTM v + +mutatePO :: Mutation ParamOver +mutatePO (ParamOver hi v) = ParamOver <$> mutateHI hi <*> mutateCMTM v + +mutateParamAss :: Mutation ParamAssign +mutateParamAss x = case x of + ParamPositional l -> ParamPositional <$> mapM mutateExpr l + ParamNamed l -> ParamNamed <$> mapM (traverse $ traverse mutateMTM) l + +mutatePortAss :: Mutation PortAssign +mutatePortAss x = case x of + PortNamed l -> PortNamed <$> mapM (mutateAttrIded $ traverse mutateExpr) l + PortPositional l -> PortPositional <$> mapM (mutateAttributed $ traverse mutateExpr) l + +mutateEP :: Mutation EventPrim +mutateEP = mutateWith _msEventPrim >=> \(EventPrim p e) -> EventPrim p <$> mutateExpr e + +mutateEC :: Mutation EventControl +mutateEC x = case x of + ECIdent hi -> ECIdent <$> mutateHI hi + ECExpr l -> fmap ECExpr $ mapM mutateEP l >>= mutateList + _ -> pure x + +mutateDEC :: Mutation DelayEventControl +mutateDEC x = case x of + DECDelay d -> DECDelay <$> mutateD1 d + DECEvent ec -> DECEvent <$> mutateEC ec + DECRepeat e ec -> DECRepeat <$> mutateExpr e <*> mutateEC ec + +mutatePCA :: Mutation ProcContAssign +mutatePCA x = case x of + PCAAssign va -> PCAAssign <$> mutateVAss va + PCADeassign vlv -> PCADeassign <$> mutateVLV vlv + PCAForce vana -> PCAForce <$> bitraverse mutateVAss mutateNAss vana + PCARelease vlvnlv -> PCARelease <$> bitraverse mutateVLV mutateNLV vlvnlv + +mutateLS :: Mutation LoopStatement +mutateLS = mutateWith _msLoopStmt >=> \x -> case x of + LSRepeat e -> LSRepeat <$> mutateExpr e + LSWhile e -> LSWhile <$> mutateExpr e + LSFor vi c vu -> LSFor <$> mutateVAss vi <*> mutateExpr c <*> mutateVAss vu + _ -> pure x + +mutateFStmt :: Mutation FunctionStatement +mutateFStmt x = do + y <- maybe x id . fromStatement <$> mutateWith _msStmt (toStatement x) + case y of + FSBlockAssign va -> FSBlockAssign <$> mutateVAss va + FSCase zox e b d -> + FSCase zox <$> mutateExpr e + <*> ( mapM + ( \(FCaseItem pat v) -> + FCaseItem <$> (mapM mutateExpr pat >>= mutateList) <*> mutateMFStmt v + ) + b + >>= mutateList + ) + <*> mutateMFStmt d + FSIf c t f -> FSIf <$> mutateExpr c <*> mutateMFStmt t <*> mutateMFStmt f + FSDisable hi -> FSDisable <$> mutateHI hi + FSLoop ls b -> FSLoop <$> mutateLS ls <*> mutateAFStmt b + FSBlock h ps b -> + flip FSBlock ps <$> traverse (traverse $ mapM (mutateAttrIded mutateSBD) >=> mutateList) h + <*> mapM mutateAFStmt b + where + mutateAFStmt = mutateAttributed mutateFStmt + mutateMFStmt = mutateAttributed $ traverse mutateFStmt + +mutateStmt :: Mutation Statement +mutateStmt = mutateWith _msStmt >=> \x -> case x of + SBlockAssign b ass dec -> SBlockAssign b <$> mutateVAss ass <*> traverse mutateDEC dec + SCase zox e b d -> + SCase zox <$> mutateExpr e + <*> ( mapM + ( \(CaseItem pat v) -> + CaseItem <$> (mapM mutateExpr pat >>= mutateList) <*> mutateMStmt v + ) + b + >>= mutateList + ) + <*> mutateMStmt d + SIf c t f -> SIf <$> mutateExpr c <*> mutateMStmt t <*> mutateMStmt f + SDisable hi -> SDisable <$> mutateHI hi + SEventTrigger hi e -> SEventTrigger <$> mutateHI hi <*> mapM mutateExpr e + SLoop ls b -> SLoop <$> mutateLS ls <*> mutateAStmt b + SProcContAssign pca -> SProcContAssign <$> mutatePCA pca + SProcTimingControl tec s -> + SProcTimingControl <$> bitraverse mutateD1 mutateEC tec <*> mutateMStmt s + SBlock h ps b -> + flip SBlock ps <$> traverse (traverse $ mapM (mutateAttrIded mutateSBD) >=> mutateList) h + <*> mapM mutateAStmt b + SSysTaskEnable i args -> SSysTaskEnable i <$> mapM (traverse mutateExpr) args + STaskEnable hi args -> STaskEnable <$> mutateHI hi <*> mapM mutateExpr args + SWait e s -> SWait <$> mutateExpr e <*> mutateMStmt s + +mutateAStmt :: Mutation AttrStmt +mutateAStmt = mutateAttributed mutateStmt + +mutateMStmt :: Mutation MybStmt +mutateMStmt = mutateAttributed $ traverse mutateStmt + +mutateNP :: Mutation NetProp +mutateNP (NetProp sn v d) = NetProp sn <$> traverse (traverse mutateR2) v <*> traverse mutateD3 d + +mutateND :: Mutation NetDecl +mutateND (NetDecl i r2) = NetDecl i <$> mapM mutateR2 r2 + +mutateNI :: Mutation NetInit +mutateNI (NetInit i e) = NetInit i <$> mutateExpr e + +mutateBD :: (forall x. Mutation x -> Mutation (f x)) -> Mutation t -> Mutation (BlockDecl f t) +mutateBD ff ft x = case x of + BDReg sr d -> BDReg <$> mutateSR sr <*> ff ft d + BDInt d -> BDInt <$> ff ft d + BDReal d -> BDReal <$> ff ft d + BDTime d -> BDTime <$> ff ft d + BDRealTime d -> BDRealTime <$> ff ft d + BDEvent d -> BDEvent <$> ff (mapM mutateR2) d + BDLocalParam ct v -> BDLocalParam <$> mutateCT ct <*> ff mutateCMTM v + +mutateSBD :: Mutation StdBlockDecl +mutateSBD x = case x of + SBDBlockDecl bd -> SBDBlockDecl <$> mutateBD traverse (mapM mutateR2) bd + SBDParameter p -> SBDParameter <$> mutateParam p + +mutateTFBD :: Mutation (TFBlockDecl t) +mutateTFBD x = case x of + TFBDStd sbd -> TFBDStd <$> mutateSBD sbd + TFBDPort d t -> TFBDPort d <$> mutateCT t + +mutateGCI :: Mutation GenCaseItem +mutateGCI (GenCaseItem pat v) = + GenCaseItem <$> (mapM mutateCExpr pat >>= mutateList) <*> mutateGCB v + +mutateMGCI :: Mutation ModGenCondItem +mutateMGCI = mutateWith _msGenCond >=> \x -> case x of + MGCIIf c t f -> MGCIIf <$> mutateCExpr c <*> mutateGCB t <*> mutateGCB f + MGCICase e b d -> MGCICase <$> mutateCExpr e <*> (mapM mutateGCI b >>= mutateList) <*> mutateGCB d + +mutateGCB :: Mutation GenerateCondBlock +mutateGCB x = case x of + GCBBlock b -> GCBBlock <$> mutateGB b + GCBConditional c -> GCBConditional <$> mutateAttributed mutateMGCI c + _ -> pure x + +mutateInstanceName :: Mutation InstanceName +mutateInstanceName (InstanceName i r2) = InstanceName i <$> traverse mutateR2 r2 + +mutateGICMos :: Mutation GICMos +mutateGICMos (GICMos i lv inp nc pc) = + GICMos <$> traverse mutateInstanceName i + <*> mutateNLV lv + <*> mutateExpr inp + <*> mutateExpr nc + <*> mutateExpr pc + +mutateGIEnable :: Mutation GIEnable +mutateGIEnable (GIEnable i lv inp en) = + GIEnable <$> traverse mutateInstanceName i <*> mutateNLV lv <*> mutateExpr inp <*> mutateExpr en + +mutateGIMos :: Mutation GIMos +mutateGIMos (GIMos i lv inp en) = + GIMos <$> traverse mutateInstanceName i <*> mutateNLV lv <*> mutateExpr inp <*> mutateExpr en + +mutateGINIn :: Mutation GINIn +mutateGINIn (GINIn i lv inp) = + GINIn <$> traverse mutateInstanceName i <*> mutateNLV lv <*> (mapM mutateExpr inp >>= mutateList) + +mutateGINOut :: Mutation GINOut +mutateGINOut (GINOut i lv inp) = + GINOut <$> traverse mutateInstanceName i <*> (mapM mutateNLV lv >>= mutateList) <*> mutateExpr inp + +mutateGIPassEn :: Mutation GIPassEn +mutateGIPassEn (GIPassEn i lhs rhs en) = + GIPassEn <$> traverse mutateInstanceName i <*> mutateNLV lhs <*> mutateNLV rhs <*> mutateExpr en + +mutateGIPass :: Mutation GIPass +mutateGIPass (GIPass i lhs rhs) = + GIPass <$> traverse mutateInstanceName i <*> mutateNLV lhs <*> mutateNLV rhs + +mutateGIPull :: Mutation GIPull +mutateGIPull (GIPull i lv) = GIPull <$> traverse mutateInstanceName i <*> mutateNLV lv + +mutateUDPInst :: Mutation UDPInst +mutateUDPInst (UDPInst i lv args) = + UDPInst <$> traverse mutateInstanceName i <*> mutateNLV lv <*> mapM mutateExpr args + +mutateModInst :: Mutation ModInst +mutateModInst (ModInst i ports) = ModInst <$> mutateInstanceName i <*> mutatePortAss ports + +mutateUknInst :: Mutation UknInst +mutateUknInst (UknInst i a0 args) = + UknInst <$> mutateInstanceName i <*> mutateNLV a0 <*> mapM mutateExpr args + +mutateMGI :: Mutation ModGenBlockedItem +mutateMGI = mutateWith _msModGenItem >=> \x -> case x of + MGINetInit nt ds np ni -> MGINetInit nt ds <$> mutateNP np <*> traverse mutateNI ni + MGINetDecl nt np nd -> MGINetDecl nt <$> mutateNP np <*> traverse mutateND nd + MGITriD ds np ni -> MGITriD ds <$> mutateNP np <*> traverse mutateNI ni + MGITriC cs np nd -> MGITriC cs <$> mutateNP np <*> traverse mutateND nd + MGIBlockDecl bd -> + MGIBlockDecl <$> mutateBD traverse (bitraverse (mapM mutateR2) mutateCExpr) bd + MGITask a i d b -> + MGITask a i <$> (mapM (mutateAttrIded mutateTFBD) d >>= mutateList) <*> mutateMStmt b + MGIFunc a t i d b -> + flip (MGIFunc a) i <$> traverse mutateCT t + <*> (mapM (mutateAttrIded mutateTFBD) d >>= mutateList) + <*> mutateFStmt b + MGIDefParam po -> MGIDefParam <$> traverse mutatePO po + MGIContAss ds d3 na -> MGIContAss ds <$> traverse mutateD3 d3 <*> traverse mutateNAss na + MGICMos r d3 i -> MGICMos r <$> traverse mutateD3 d3 <*> traverse mutateGICMos i + MGIEnable r b ds d3 i -> MGIEnable r b ds <$> traverse mutateD3 d3 <*> traverse mutateGIEnable i + MGIMos r np d3 i -> MGIMos r np <$> traverse mutateD3 d3 <*> traverse mutateGIMos i + MGINIn nin n ds d2 i -> MGINIn nin n ds <$> traverse mutateD2 d2 <*> traverse mutateGINIn i + MGINOut r ds d2 i -> MGINOut r ds <$> traverse mutateD2 d2 <*> traverse mutateGINOut i + MGIPassEn r b d2 i -> MGIPassEn r b <$> traverse mutateD2 d2 <*> traverse mutateGIPassEn i + MGIPass r i -> MGIPass r <$> traverse mutateGIPass i + MGIPull ud ds i -> MGIPull ud ds <$> traverse mutateGIPull i + MGIUDPInst kind ds d2 i -> + MGIUDPInst kind ds <$> traverse mutateD2 d2 <*> traverse mutateUDPInst i + MGIModInst kind params i -> + MGIModInst kind <$> mutateParamAss params <*> traverse mutateModInst i + MGIUnknownInst kind params i -> + MGIUnknownInst kind + <$> traverse (bitraverse mutateExpr $ bitraverse mutateExpr mutateExpr) params + <*> traverse mutateUknInst i + MGIInitial s -> MGIInitial <$> mutateAStmt s + MGIAlways s -> MGIAlways <$> mutateAStmt s + MGILoopGen ii iv c ui uv b -> + MGILoopGen ii <$> mutateCExpr iv + <*> mutateCExpr c + <*> pure ui + <*> mutateCExpr uv + <*> mutateGB b + MGICondItem ci -> MGICondItem <$> mutateMGCI ci + _ -> pure x + +mutateTCE :: Mutation TimingCheckEvent +mutateTCE (TimingCheckEvent ec st tcc) = + TimingCheckEvent ec <$> mutateST st <*> traverse (traverse mutateExpr) tcc + +mutateCTCE :: Mutation ControlledTimingCheckEvent +mutateCTCE (ControlledTimingCheckEvent ec st tcc) = + ControlledTimingCheckEvent ec <$> mutateST st <*> traverse (traverse mutateExpr) tcc + +mutateSTCA :: Mutation STCArgs +mutateSTCA (STCArgs de re tcl n) = + STCArgs <$> mutateTCE de <*> mutateTCE re <*> mutateExpr tcl <*> pure n + +mutateSTCAA :: Mutation STCAddArgs +mutateSTCAA (STCAddArgs tcl sc ctc dr dd) = + STCAddArgs <$> mutateExpr tcl + <*> traverse mutateMTM sc + <*> traverse mutateMTM ctc + <*> traverse (traverse $ traverse mutateCMTM) dr + <*> traverse (traverse $ traverse mutateCMTM) dd + +mutateMPC :: Mutation ModulePathCondition +mutateMPC x = case x of + MPCCond e -> MPCCond <$> mutateGExpr pure pure mutateAttr e + _ -> pure x + +mutateSP :: Mutation SpecPath +mutateSP x = case x of + SPParallel inp outp -> SPParallel <$> mutateST inp <*> mutateST outp + SPFull inp outp -> + SPFull <$> (mapM mutateST inp >>= mutateList) <*> (mapM mutateST outp >>= mutateList) + +mutatePDV :: Mutation PathDelayValue +mutatePDV = mutateWith _msPDV >=> \x -> case x of + PDV1 x -> PDV1 <$> mutateCMTM x + PDV2 r f -> PDV2 <$> mutateCMTM r <*> mutateCMTM f + PDV3 r f z -> PDV3 <$> mutateCMTM r <*> mutateCMTM f <*> mutateCMTM z + PDV6 t01 t10 t0z tz1 t1z tz0 -> + PDV6 <$> mutateCMTM t01 + <*> mutateCMTM t10 + <*> mutateCMTM t0z + <*> mutateCMTM tz1 + <*> mutateCMTM t1z + <*> mutateCMTM tz0 + PDV12 t01 t10 t0z tz1 t1z tz0 t0x tx1 t1x tx0 txz tzx -> + PDV12 <$> mutateCMTM t01 + <*> mutateCMTM t10 + <*> mutateCMTM t0z + <*> mutateCMTM tz1 + <*> mutateCMTM t1z + <*> mutateCMTM tz0 + <*> mutateCMTM t0x + <*> mutateCMTM tx1 + <*> mutateCMTM t1x + <*> mutateCMTM tx0 + <*> mutateCMTM txz + <*> mutateCMTM tzx + +mutateSI :: Mutation SpecifyBlockedItem +mutateSI = mutateWith _msSpecItem >=> \x -> case x of + SISpecParam r2 spd -> SISpecParam <$> traverse mutateR2 r2 <*> traverse mutateSPD spd + SIPulsestyleOnevent st -> SIPulsestyleOnevent <$> traverse mutateST st + SIPulsestyleOndetect st -> SIPulsestyleOndetect <$> traverse mutateST st + SIShowcancelled st -> SIShowcancelled <$> traverse mutateST st + SINoshowcancelled st -> SINoshowcancelled <$> traverse mutateST st + SIPathDeclaration mpc con pol eds v -> + SIPathDeclaration <$> mutateMPC mpc + <*> mutateSP con + <*> pure pol + <*> traverse (bitraverse mutateExpr pure) eds + <*> mutatePDV v + SISetup a -> SISetup <$> mutateSTCA a + SIHold a -> SIHold <$> mutateSTCA a + SISetupHold a aa -> SISetupHold <$> mutateSTCA a <*> mutateSTCAA aa + SIRecovery a -> SIRecovery <$> mutateSTCA a + SIRemoval a -> SIRemoval <$> mutateSTCA a + SIRecrem a aa -> SIRecrem <$> mutateSTCA a <*> mutateSTCAA aa + SISkew a -> SISkew <$> mutateSTCA a + SITimeSkew a eb ra -> + SITimeSkew <$> mutateSTCA a <*> traverse mutateCExpr eb <*> traverse mutateCExpr ra + SIFullSkew a tcl eb ra -> + SIFullSkew <$> mutateSTCA a + <*> mutateExpr tcl + <*> traverse mutateCExpr eb + <*> traverse mutateCExpr ra + SIPeriod ctce tcl n -> SIPeriod <$> mutateCTCE ctce <*> mutateExpr tcl <*> pure n + SIWidth ctce tcl t n -> + SIWidth <$> mutateCTCE ctce <*> mutateExpr tcl <*> traverse mutateCExpr t <*> pure n + SINoChange re de se ee n -> + SINoChange <$> mutateTCE re <*> mutateTCE de <*> mutateMTM se <*> mutateMTM ee <*> pure n + +mutateSPD :: Mutation SpecParamDecl +mutateSPD x = case x of + SPDAssign i v -> SPDAssign i <$> mutateCMTM v + SPDPathPulse io rej err -> + SPDPathPulse <$> traverse (bitraverse mutateST mutateST) io + <*> mutateCMTM rej + <*> mutateCMTM err + +mutateMI :: Mutation ModuleItem +mutateMI x = do + y <- mutateWith _msModItem x + case y of + MIMGI mgi -> MIMGI <$> mutateAttributed mutateMGI mgi + MIPort p -> MIPort <$> mutateAttrIded (traverse mutateSR) p + MIParameter p -> MIParameter <$> mutateAttrIded mutateParam p + MIGenReg l -> MIGenReg <$> mapM (mutateAttributed mutateMGI) l + MISpecParam a r2 spd -> + MISpecParam <$> mutateAttr a <*> traverse mutateR2 r2 <*> mutateSPD spd + MISpecBlock l -> fmap MISpecBlock $ mapM mutateSI l >>= mutateList + +mutateGB :: Mutation GenerateBlock +mutateGB = mutateWith _msGenBlk >=> traverse (mapM $ mutateAttributed mutateMGI) + +mutateMB :: Mutation ModuleBlock +mutateMB = mutateWith _msModule >=> \(ModuleBlock a b i pi mi ts c p dnt) -> + (\a pi mi -> ModuleBlock a b i pi mi ts c p dnt) <$> mutateAttr a + <*> mapM (traverse $ mapM $ traverse $ traverse mutateCRE) pi + <*> mapM mutateMI mi + +mutatePT :: Mutation PrimTable +mutatePT = mutateWith _msPrimTable >=> \x -> case x of + CombTable l -> CombTable <$> mutateList l + SeqTable i l -> SeqTable i <$> mutateList l + +mutatePP :: Mutation PrimPort +mutatePP x = case x of + PPOutReg e -> PPOutReg <$> traverse mutateCExpr e + _ -> pure x + +mutatePB :: Mutation PrimitiveBlock +mutatePB = mutateWith _msPrimitive >=> \(PrimitiveBlock a i outp inp pd b) -> + (\a b c -> PrimitiveBlock a i outp inp b c) <$> mutateAttr a + <*> mapM (mutateAttrIded mutatePP) pd + <*> mutatePT b + +mutateCB :: Mutation ConfigBlock +mutateCB (ConfigBlock i de b dft) = fmap (flip (ConfigBlock i de) dft) $ mapM pure b >>= mutateList + +mutateV2005 :: Mutation Verilog2005 +mutateV2005 = mutateWith _msV2005 >=> \(Verilog2005 m p c) -> + Verilog2005 <$> mapM mutateMB m + <*> (mapM mutatePB p >>= mutateList) + <*> (mapM mutateCB c >>= mutateList) diff --git a/src/Verismith/Verilog2005/Parser.hs b/src/Verismith/Verilog2005/Parser.hs index 60e4b14..952cfdb 100644 --- a/src/Verismith/Verilog2005/Parser.hs +++ b/src/Verismith/Verilog2005/Parser.hs @@ -12,7 +12,7 @@ module Verismith.Verilog2005.Parser ) where -import Control.Applicative (liftA2) +import Control.Applicative (liftA2, (<**>)) import Control.Lens hiding ((<|)) import Data.Functor.Compose import Control.Monad (join) @@ -74,7 +74,7 @@ type LAPBranch a = [APBranch a] -- | An error that is not merged with other errors and expected tokens hardfail :: String -> Parser a hardfail m = - mkPT $ \s -> return $ Consumed $ return $ Error $ newErrorMessage (Message m) (statePos s) + mkPT $ pure . Consumed . pure . Error . newErrorMessage (Message m) . statePos -- | Warning formatting warn :: SourcePos -> String -> Parser () @@ -99,6 +99,10 @@ nextPos pos _ ptl = case ptl of PosToken (Position l c (PSLine f _) :| _) _ : _ -> newPos f (fromEnum l) (fromEnum c) [] -> pos +-- | Pass an argument before joining +joinWith :: Monad m => m (a -> m b) -> a -> m b +joinWith mf x = mf >>= \f -> f x + -- | Parse exactly one token and produce a value producePrim :: (Token -> Maybe a) -> Parser a producePrim f = tokenPrim show nextPos (f . _ptToken) @@ -123,7 +127,7 @@ fproduce f = producePrim f <* anywherecompdir lproduce :: LProduce a -> Parser a lproduce l = fproduce (\t -> IntMap.lookup (getConsIndex t) $ mkActionMap l) - `labels` map (\(d, _) -> show d) l + `labels` map (show . fst) l -- | Maps a function on the data given by branching on a Token without data maplproduce :: (a -> b) -> LProduce a -> LProduce b @@ -155,7 +159,7 @@ lbranch = join . lproduce -- | Parse attributes then branches on the next token using a LABranch labranch :: LABranch a -> Parser a -labranch l = attributes >>= \a -> lproduce l >>= \p -> p a +labranch l = join $ attributes <**> lproduce l -- | Maps a function on the data given by a branching with attributes maplbranch :: (a -> b) -> LBranch a -> LBranch b @@ -225,21 +229,17 @@ wempty s p = do -- | Comma separated list potentially ended by a comma to be lenient xcsl :: String -> Parser a -> Parser [a] -xcsl s p = do - x <- optionMaybe p - case x of - Nothing -> pure [] - Just h -> do - pos <- getPosition - b <- optConsume SymComma - if b - then do - t <- xcsl s p - if null t - then warn pos (printf "Extraneous comma at the end of %s is not correct Verilog" s) - else pure () - return $ h : t - else return [h] +xcsl s p = (optionMaybe p >>=) $ maybe (pure []) $ \h -> do + pos <- getPosition + b <- optConsume SymComma + if b + then do + t <- xcsl s p + if null t + then warn pos (printf "Extraneous comma at the end of %s is not correct Verilog" s) + else pure () + return $ h : t + else return [h] -- | Comma separated list potentially ended by a comma to be lenient xcsl1 :: String -> Parser a -> Parser (NonEmpty a) @@ -259,20 +259,18 @@ wxcsl m = wempty m . xcsl m -- | Safe parsing comma separated list with at least 1 elements scsl1 :: Bool -> Parser a -> (a -> Parser b) -> Parser (NonEmpty b) -scsl1 safety d p = do - h <- d >>= p - t <- many $ ((if safety then try else id) $ consume SymComma *> d) >>= p - return $ h :| t +scsl1 safety d p = + liftA2 (:|) (d >>= p) $ many $ ((if safety then try else id) $ consume SymComma *> d) >>= p -- | Safe parsing of several elements of type B then of type C -- | when B and C start with a common part of type A smanythen :: Parser a -> (a -> Parser b) -> (a -> Parser c) -> Parser ([b], [c]) -smanythen pa pb pc = do - h <- optionMaybe $ pa >>= \a -> Left <$> pb a <|> Right <$> pc a - case h of - Nothing -> return ([], []) - Just (Left hb) -> first (hb :) <$> smanythen pa pb pc - Just (Right hc) -> (,) [] . (hc :) <$> many (pa >>= pc) +smanythen pa pb pc = + (optionMaybe (pa >>= \a -> Left <$> pb a <|> Right <$> pc a) >>=) $ + maybe (pure ([], [])) $ + either + (\hb -> first (hb :) <$> smanythen pa pb pc) + (\hc -> (,) [] . (hc :) <$> many (pa >>= pc)) -- | Parenthesised comma separated list pcsl :: Parser a -> Parser [a] @@ -773,7 +771,7 @@ stmtBlock kind pos = do ms <- optionMaybe $ consume SymColon *> ident (decl, body) <- smanythen attributes - (\a -> lproduce stdBlockDecl >>= \p -> NE.toList <$> p a) + (fmap NE.toList . joinWith (lproduce stdBlockDecl)) (\a -> Attributed a <$> statement) let d = concat decl h <- case (d, ms) of @@ -932,9 +930,9 @@ taskFun zeroarg arglb = do parens $ ww "function ports" $ concat <$> csl (NE.toList <$> labranch (arglb True)) consume SymSemi let dp = case l of - Nothing -> maplaproduce (\p -> p <* consume SymSemi) (arglb False) ++ sbd + Nothing -> maplaproduce (<* consume SymSemi) (arglb False) ++ sbd Just _ -> sbd - (d, b) <- smanythen attributes (\a -> lproduce dp >>= \p -> NE.toList <$> p a) trOptStmt + (d, b) <- smanythen attributes (fmap NE.toList . joinWith (lproduce dp)) trOptStmt ww "function declarations" $ pure d case b of [x] -> pure () @@ -1213,8 +1211,8 @@ modudpinstance what = do args <- parens $ do a <- attributes do { - x <- namePort a; - PortNamed . (x :) <$> commathen (xcsl "port connections" $ attributes >>= namePort) + x <- namePort a; + PortNamed . (x :) <$> commathen (xcsl "port connections" $ attributes >>= namePort) } <|> (ordPort a >>= \x -> PortPositional . (x :) <$> commathen (csl $ attributes >>= ordPort)) let argl = case args of @@ -1318,7 +1316,7 @@ genSingle :: Parser [Attributed ModGenBlockedItem] genSingle = do a <- attributes pos <- getPosition - b <- (lproduce comModGenItem >>= \p -> p pos) <|> modudpInst + b <- joinWith (lproduce comModGenItem) pos <|> modudpInst return $ Attributed a <$> toList (toMGBlockedItem b) genCondBlock :: Parser GenerateCondBlock @@ -1647,8 +1645,8 @@ npmodItem = ] -- | Module -parseModule :: LocalCompDir -> Attributes -> Parser Verilog2005 -parseModule (LocalCompDir ts cl pull dnt) a = do +parseModule :: Bool -> LocalCompDir -> Attributes -> Parser Verilog2005 +parseModule b (LocalCompDir ts cl pull dnt) a = do s <- lenientIdent params <- option [] $ do consume SymPound @@ -1661,7 +1659,7 @@ parseModule (LocalCompDir ts cl pull dnt) a = do Nothing -> many $ parseItem MIMGI $ maplaproduce (const . fmap fst) (portDecl dnt False) ++ npmodItem Just pd -> (pd :) <$> many (parseItem MIMGI npmodItem) - return mempty {_vModule = [ModuleBlock a s pi (concat mi) ts cl pull dnt]} + return mempty {_vModule = [ModuleBlock a b s pi (concat mi) ts cl pull dnt]} where -- Fully specified port declaration list fullPort = @@ -1869,8 +1867,8 @@ topDecl = st <- getState fpbranch $ \p t -> case t of KWPrimitive -> Just $ udp a <* closeConsume p KWPrimitive KWEndprimitive - KWModule -> Just $ parseModule st a <* closeConsume p KWModule KWEndmodule - KWMacromodule -> Just $ parseModule st a <* closeConsume p KWMacromodule KWEndmodule + KWModule -> Just $ parseModule False st a <* closeConsume p KWModule KWEndmodule + KWMacromodule -> Just $ parseModule True st a <* closeConsume p KWMacromodule KWEndmodule KWConfig | null a -> Just $ config <* closeConsume p KWConfig KWEndconfig _ -> Nothing diff --git a/src/Verismith/Verilog2005/PrettyPrinter.hs b/src/Verismith/Verilog2005/PrettyPrinter.hs index abbb1a0..b5d1fbd 100644 --- a/src/Verismith/Verilog2005/PrettyPrinter.hs +++ b/src/Verismith/Verilog2005/PrettyPrinter.hs @@ -321,9 +321,9 @@ prettyGExpr ppid ppr ppa l e = case e of ll <- (<=> viaShow op) <$> psexpr p el da <- ppa a case compare l p of - LT -> padj pp r >>= \rr -> mkid $ ng $ par $ ll <+> (da rr) - EQ -> first (\rr -> ll <+> (da rr)) <$> pp r - GT -> first (\rr -> ng $ ll <+> (da rr)) <$> pp r + LT -> padj pp r >>= mkid . ng . par . (ll <+>) . (da ) + EQ -> first ((ll <+>) . (da )) <$> pp r + GT -> first (ng . (ll <+>) . (da )) <$> pp r ExprCond ec a et ef -> do dc <- psexpr 11 ec dt <- psexpr 12 et @@ -472,9 +472,7 @@ prettyEdgeDesc x = do else if x == V.fromList [False, False, True, True, True, False] then pure "negedge" - else - (\x -> group $ "edge" <=> brk x) - <$> csl mempty mempty (pure . raw) (V.ifoldr (pED zx) [] x) + else group . ("edge" <=>) . brk <$> csl mempty mempty (pure . raw) (V.ifoldr (pED zx) [] x) where pED zx i b = if b @@ -995,7 +993,7 @@ prettyPathDecl p pol eds = do po = maybe mempty (\p -> if p then "+" else "-") pol -- edge sensitive path polarity isn't at the same place as non edge sensitive noedge = eds == Nothing - fne = if noedge then uncurry (<>) else \x -> fst x <> newline + fne = if noedge then uncurry (<>) else (<> newline) . fst prettySpecifyItem :: SpecifySingleItem -> Print prettySpecifyItem x = @@ -1165,8 +1163,8 @@ prettyPortInter = _ -> cslid (lbrace <> softspace) rbrace pst l >>= mkid prettyModuleBlock :: LocalCompDir -> ModuleBlock -> Reader PrintingOpts (Doc, LocalCompDir) -prettyModuleBlock (LocalCompDir ts c p dn) (ModuleBlock a i pi b mts mc mp mdn) = do - head <- fpadj (group . ("module" <=>)) prettyIdent i +prettyModuleBlock (LocalCompDir ts c p dn) (ModuleBlock a mm i pi b mts mc mp mdn) = do + head <- fpadj (group . ((if mm then "macromodule" else "module") <=>)) prettyIdent i ports <- prettyPortInter pi header <- prettyItem a $ head <> gpar ports body <- prettyModuleItems b diff --git a/src/Verismith/Verilog2005/Randomness.hs b/src/Verismith/Verilog2005/Randomness.hs index fa49409..627b222 100644 --- a/src/Verismith/Verilog2005/Randomness.hs +++ b/src/Verismith/Verilog2005/Randomness.hs @@ -8,7 +8,8 @@ {-# LANGUAGE ScopedTypeVariables #-} module Verismith.Verilog2005.Randomness - ( sampleCategoricalProbability, + ( shuffle, + sampleCategoricalProbability, sampleNumberProbability, sampleIn, sampleInString, @@ -34,7 +35,7 @@ module Verismith.Verilog2005.Randomness where import Control.Applicative (liftA2) -import Control.Monad (join, replicateM) +import Control.Monad (join, replicateM, forM_) import Control.Monad.Reader import qualified Data.ByteString as B import Data.List @@ -42,6 +43,9 @@ import Data.List.NonEmpty (NonEmpty (..), toList) import qualified Data.List.NonEmpty as NE import Control.Monad.Primitive (PrimMonad, PrimState, RealWorld) import Data.Word +import Data.Bifunctor (first, second) +import qualified Data.Vector.Unboxed as VU +import qualified Data.Vector.Unboxed.Mutable as VM import System.Random.MWC.Probability import Verismith.Config (CategoricalProbability (..), NumberProbability (..), uniformCP) import Verismith.Utils (nonEmpty, foldrMap1) @@ -61,14 +65,20 @@ uniq f m = nonEmpty [] $ toList . foldrMap1 (:|[]) (\e (x :| a) -> if f x == f e then (m x e) :| a else e :| x : a) . NE.sortWith f - clean :: Int -> [(Double, Int)] -> [(Double, Int)] clean t = - map (\(x, y) -> (max 0 x, y)) + map (first $ max 0) . uniq snd (\(x1, y1) (x2, y2) -> (x1 + x2, y1)) . filter ((<= t) . snd) +shuffle :: (PrimMonad m, VM.Unbox x) => Gen (PrimState m) -> [x] -> m [x] +shuffle gen l = do + let n = length l - 1 + v <- VU.thaw $ VU.fromList l + forM_ [0..n] $ \i -> sample (uniformR (i, n)) gen >>= VM.swap v i + VU.toList <$> VU.unsafeFreeze v + sampleCategoricalProbability :: PrimMonad m => Int -> Gen (PrimState m) -> CategoricalProbability -> m Int sampleCategoricalProbability t gen d = case d of @@ -83,7 +93,7 @@ sampleCategoricalProbability t gen d = case d of uw = fromIntegral (t + 1 - length ll) * b in nonEmpty (pure Nothing) - (flip sample gen . discrete . ((uw, Nothing) :) . map (\(x, y) -> (x, Just y)) . toList) + (flip sample gen . discrete . ((uw, Nothing) :) . map (second Just) . toList) ll >>= maybe (avoid (map snd ll) <$> sample (uniformR (0, t - length ll)) gen) pure @@ -199,7 +209,7 @@ sampleFiltered p t l = do CPBiasedUniform l' b -> let ll' = deleteFirstOrdered snd id (clean t l') ll uw = fromIntegral (t - length ll - length ll') * b - in sample (discrete $ (uw, Nothing) : map (\(x, y) -> (x, Just y)) ll') gen + in sample (discrete $ (uw, Nothing) : map (second Just) ll') gen >>= maybe ( avoid (merge ll $ map snd ll') <$> sample (uniformR (0, t - length ll - length ll')) gen diff --git a/src/Verismith/Verilog2005/Utils.hs b/src/Verismith/Verilog2005/Utils.hs index fdb0bd9..b8163c3 100644 --- a/src/Verismith/Verilog2005/Utils.hs +++ b/src/Verismith/Verilog2005/Utils.hs @@ -33,16 +33,21 @@ module Verismith.Verilog2005.Utils fromMGBlockedItem1, fromMGBlockedItem_add, fromMGBlockedItem, + resolveInsts ) where +import Control.Lens ((%~)) +import Data.Data.Lens (biplate) import Numeric.Natural import Text.Printf (printf) import Data.Functor.Compose import Data.Functor.Identity +import Data.Function (on, (&)) import qualified Data.ByteString as BS import Data.ByteString.Internal (c2w, packChars) import qualified Data.HashSet as HS +import qualified Data.HashMap.Strict as HashMap import Data.List.NonEmpty (NonEmpty (..), (<|), toList) import qualified Data.List.NonEmpty as NE import Verismith.Verilog2005.Lexer (VerilogVersion (..), isIdentSimple) @@ -450,3 +455,45 @@ fromMGBlockedItem_add x y = case (x, y) of fromMGBlockedItem :: [Attributed ModGenBlockedItem] -> [Attributed ModGenSingleItem] fromMGBlockedItem = nonEmpty [] $ toList . regroup (fmap fromMGBlockedItem1) (addAttributed fromMGBlockedItem_add) + +-- | Resolves Module and Primitive instantiation if possible +-- | Also checks there are no duplicate toplevel elements +resolveInsts :: Verilog2005 -> Either String Verilog2005 +resolveInsts v = do + nm <- + foldr + ( \m h -> + h >>= + let Identifier k = _mbIdent m + in HashMap.alterF (maybe (Right $ Just True) $ const $ Left $ duperr k) k + ) + (Right HashMap.empty) + (_vModule v) + nm <- + foldr + (\p h -> + h >>= + let Identifier k = _pbIdent p + in HashMap.alterF (maybe (Right $ Just False) $ const $ Left $ duperr k) k + ) + (Right nm) + (_vPrimitive v) + return $ v & biplate %~ \mgi -> case mgi of + MGIUnknownInst k@(Identifier i) param (Identity (UknInst n lv args)) -> + case HashMap.lookup i nm of + Nothing -> mgi + Just False -> + MGIUDPInst k dsDefault (either (D21 . MTMSingle) (uncurry $ on D22 MTMSingle) <$> param) $ + Identity $ UDPInst (Just n) lv args + Just True -> + MGIModInst + k + ( ParamPositional $ + case param of Nothing -> []; Just (Right (e0, e1)) -> [e0, e1]; Just (Left e) -> [e] + ) + ( Identity $ + ModInst n $ + PortPositional $ map (Attributed [] . Just) $ netlv2expr lv : NE.toList args + ) + _ -> mgi + where duperr = printf "module or primitive %s defined more than once" . show diff --git a/verismith.cabal b/verismith.cabal index fb165ea..1f34691 100644 --- a/verismith.cabal +++ b/verismith.cabal @@ -85,6 +85,7 @@ library , Verismith.Verilog2005.Parser , Verismith.Verilog2005.Randomness , Verismith.Verilog2005.Generator + , Verismith.Verilog2005.Mutation build-depends: array >=0.5 && <0.6 , base >=4.7 && <5 , binary >= 0.8.5.1 && <0.9