module Language.Atom.Verification ( Model , model -- , verify -- , kInduction -- , boundedModelChecking , test ) where import Data.Char () import Data.Function () import Data.Int () import Data.List () import Data.Ratio () import Data.Word () import Math.SMT.Yices.Pipe import Math.SMT.Yices.Syntax import System.Process () import Language.Atom.Elaboration () import Language.Atom.Expressions import Language.Atom.Scheduling -- | A model of a scheduled program for model checking. data Model = Model --{ transition :: Int -> [Name] -> ([CmdY], [CmdY]) --, names :: [(Name, Int)] --, --} -- | Create a model from a scheduled program. model :: Schedule -> [UV] -> [UA] -> Model model _ _ _ = Model -- | A list of assertions captured by a model. --assertions :: Model -> [Name] -- | Bounded model checking starting from the initial state. --boundedModelChecking :: Model -> Int -> Name -> IO (Maybe Witness) -- | K-induction model checking given a min and a max k-depth. --kInduction :: Model -> Int -> Int -> Name -> IO () test :: IO () test = do print test result <- runY test print result where test = [ DEFINE ("a", VarT "int") Nothing , DEFINE ("b", VarT "int") Nothing , ASSERT (VarE "a" := VarE "b") -- , ASSERT (YNe (YVar "a") (YVar "b")) ] -- | Runs a Yices program. Returns a list of variable values if satisfiable. runY :: [CmdY] -> IO ResY runY a = do p <- createYicesPipe "yices" [] runCmdsY p a r <- checkY p exitY p return r {- yType :: Type -> YT yType t = case t of Bool -> YBool Int8 -> YInt Int16 -> YInt Int32 -> YInt Int64 -> YInt Word8 -> YNat Word16 -> YNat Word32 -> YNat Word64 -> YNat Float -> YReal Double -> YReal -} {- vars :: [UV] -> Int -> String vars uvs step = concatMap (var step) uvs where var :: Int -> UV -> String var step uv = "(define " ++ uvName step uv ++ "::" ++ yicesType (uvType uv) ++ ")\n" uvName :: Int -> UV -> String uvName step (UV i _ _) = "v" ++ show i ++ "_" ++ show step initialize :: [UV] -> String initialize uvs = vars uvs 0 ++ concatMap initialize uvs where initialize :: UV -> String initialize uv@(UV _ _ (Local c)) = "(assert (= " ++ uvName 0 uv ++ " " ++ const c ++ "))\n" initialize (UV _ _ (External _)) = "" const :: Const -> String const c = case c of CBool c -> if c then "true" else "false" CInt8 c -> "0b" ++ bits 8 (fromIntegral c) CInt16 c -> "0b" ++ bits 16 (fromIntegral c) CInt32 c -> "0b" ++ bits 32 (fromIntegral c) CInt64 c -> "0b" ++ bits 64 (fromIntegral c) CWord8 c -> "0b" ++ bits 8 (fromIntegral c) CWord16 c -> "0b" ++ bits 16 (fromIntegral c) CWord32 c -> "0b" ++ bits 32 (fromIntegral c) CWord64 c -> "0b" ++ bits 64 (fromIntegral c) CFloat c -> "(/ " ++ show (numerator $ toRational c) ++ " " ++ show (denominator $ toRational c) ++ ")" CDouble c -> "(/ " ++ show (numerator $ toRational c) ++ " " ++ show (denominator $ toRational c) ++ ")" bits :: Int -> Word64 -> String bits 0 _ = "" bits n a = bits (n - 1) (div a 2) ++ show (mod a 2) -- Time 0 to 1 is step 1. transition :: [[[Rule]]] -> [UV] -> Int -> String transition _ {-schedule-} uvs step = vars uvs step ++ transition where transition = "; transition " ++ show (step - 1) ++ " to " ++ show step ++ "\n" --XXX getUV :: [UV] -> Int -> UV getUV [] _ = error "Verify.getUV" getUV (uv@(UV i _ _):_) j | i == j = uv getUV (_:a) i = getUV a i parseVar :: [UV] -> Group -> (Int, UV, String) parseVar uvs (G [S "=", S name, value]) = (t, getUV uvs i, parseValue value) where (i', t') = break (== '_') $ tail name i = read i' t = read $ tail t' parseVar _ g = error $ "Verify.parseVar: " ++ show g parseValue :: Group -> String parseValue (S ('0':'b':a)) = "b" ++ a ++ " " parseValue (S "true") = "1" parseValue (S "false") = "0" parseValue (S v) = "r" ++ v ++ " " parseValue (G [S "/", S n, S d]) = "r" ++ show (fromRational (read n % read d)) ++ " " parseValue a = error $ "Verify.parseValue: " ++ show a data Heirarchy = Variable UV | Module String [Heirarchy] vcd :: [UV] -> [(Int, UV, String)] -> String vcd uvs signals' = header ++ samples ++ end where signals = sortBy (\ (a,_,_) (b,_,_) -> compare a b) signals' header = "$timescale\n 1 ms\n$end\n" ++ concatMap decl (heirarchy 0 uvs) ++ "$enddefinitions $end\n" (lastTime, _, _) = last signals end = "#" ++ show (lastTime + 1) ++ "\n" decl :: Heirarchy -> String decl (Module name subs) = "$scope module " ++ name ++ " $end\n" ++ concatMap decl subs ++ "$upscope $end\n" decl (Variable uv) = declVar uv declVar :: UV -> String declVar uv@(UV i n _) = case uvType uv of Bool -> "$var wire 1 " ++ code ++ " " ++ name ++ " $end\n" Int8 -> "$var integer 8 " ++ code ++ " " ++ name ++ " $end\n" Int16 -> "$var integer 16 " ++ code ++ " " ++ name ++ " $end\n" Int32 -> "$var integer 32 " ++ code ++ " " ++ name ++ " $end\n" Int64 -> "$var integer 64 " ++ code ++ " " ++ name ++ " $end\n" Word8 -> "$var wire 8 " ++ code ++ " " ++ name ++ " $end\n" Word16 -> "$var wire 16 " ++ code ++ " " ++ name ++ " $end\n" Word32 -> "$var wire 32 " ++ code ++ " " ++ name ++ " $end\n" Word64 -> "$var wire 64 " ++ code ++ " " ++ name ++ " $end\n" Float -> "$var real 32 " ++ code ++ " " ++ name ++ " $end\n" Double -> "$var real 64 " ++ code ++ " " ++ name ++ " $end\n" where code = vcdCode i name = reverse $ takeWhile (/= '.') $ reverse n samples = concatMap sample signals sample (t, (UV i _ _), v) = "#" ++ show t ++ "\n" ++ v ++ vcdCode i ++ "\n" heirarchy :: Int -> [UV] -> [Heirarchy] heirarchy _ [] = [] heirarchy depth uvs = heirarchy' depth notvars ++ map Variable vars where isVar :: UV -> Bool isVar uv = length (path depth uv) == 1 (vars, notvars) = partition isVar uvs heirarchy' :: Int -> [UV] -> [Heirarchy] heirarchy' _ [] = [] heirarchy' depth uvs@(a:_) = Module n (heirarchy (depth + 1) yes) : heirarchy' depth no where n = head $ path depth a isMod uv = n == head (path depth uv) (yes, no) = partition isMod uvs path :: Int -> UV -> [String] path depth (UV _ n _) = drop depth $ words $ map (\ c -> if c == '.' then ' ' else c) n vcdCode :: Int -> String vcdCode i | i < 94 = [chr (33 + mod i 94)] vcdCode i = vcdCode (div i 94) ++ [chr (33 + mod i 94)] {- bitString :: Int -> String bitString n = if null bits then "0" else bits where bit :: Int -> Char bit i = if testBit n i then '1' else '0' bits = dropWhile (== '0') $ map bit $ reverse [0..31] -} -}