Language/Atom/Verify.hs

module Language.Atom.Verify (verify) where

import Data.Char
import Data.Int
import Data.List
import Data.Ratio
import Data.Word
import System.Process

import Language.Atom.Elaboration
import Language.Atom.Expressions

verify :: Int -> [[[Rule]]] -> [UV] -> (String, UE) -> IO Bool
verify depth rules uvs (name, assert) = do
 putStrLn $ "Checking assertion " ++ name ++ "..."
 verify
 
 where
 verify | assert == ubool True = return True
 | assert == ubool False = putStrLn ("Assertion failed trivially.") >> return False
 | otherwise = do
 --putStrLn yices
 --putStrLn "***********************************************"
 out <- readProcess "yices" ["-e"] yices
 case parseYices out of
 S "unsat" : _ -> return True
 S "sat" : vars' -> do
 let vars = map (parseVar uvs) vars'
 putStrLn ("Assertion failed. See counter example: " ++ name ++ ".vcd")
 writeFile (name ++ ".vcd") $ vcd uvs vars
 return False
 _ -> error "Unexpected results from yices."
 
 assertUE :: Int -> String
 assertUE step = "(assert (not " ++ f ++ "))\n"
 where
 f = case assert of
 UVRef uv -> uvName step uv
 _ -> error "expressions not supported assertions yet"

 asserts = concatMap assertUE [0..depth]
 yices = initialize uvs ++ concatMap (transition rules uvs) [1..depth] ++ asserts ++ "(check)"

yicesType :: Type -> String
yicesType t = case t of
 Bool -> "bool"
 Int8 -> "(bitvector 8)"
 Int16 -> "(bitvector 16)"
 Int32 -> "(bitvector 32)"
 Int64 -> "(bitvector 64)"
 Word8 -> "(bitvector 8)"
 Word16 -> "(bitvector 16)"
 Word32 -> "(bitvector 32)"
 Word64 -> "(bitvector 64)"
 Float -> "real"
 Double -> "real"

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 Group = G [Group] | S String deriving Show

parseYices :: String -> [Group]
parseYices = groups . tokens

groups :: [String] -> [Group]
groups [] = []
groups ("(":a) = G (groups x) : groups y where (x, y) = split 0 [] a
groups (a:b) = S a : groups b

split :: Int -> [String] -> [String] -> ([String], [String])
split 0 a (")":b) = (reverse a, b)
split n a ("(":b) = split (n + 1) ("(" : a) b
split n a (")":b) = split (n - 1) (")" : a) b
split n a (b:c) = split n (b:a) c
split _ _ [] = error "Verify.split"

tokens :: String -> [String]
tokens [] = []
tokens (a:b) | isSpace a = tokens b
tokens ('(':b) = "(" : tokens b
tokens (')':b) = ")" : tokens b
tokens a = tokens' "" a

tokens' :: String -> String -> [String]
tokens' a [] = [reverse a]
tokens' a c@(b:_) | isSpace b || elem b "()" = reverse a : tokens c
tokens' a (b:c) = tokens' (b:a) c

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]
-}

AltStyle によって変換されたページ (->オリジナル) /