{-# LANGUAGE NamedFieldPuns #-} import System.Exit (exitFailure) import Data.Bits import System.Console.GetOpt import Text.Read (readMaybe) import System.Environment (getArgs) import Data.List (intersperse) import Data.Maybe (isNothing) import Numeric (readHex) import Control.Exception (throw) import Data.Array data CacheMap = DirectMapping | FullAssociative deriving (Show, Eq) data CacheOrg = Unified | Split deriving (Show, Eq) data Config = Config { mapping :: CacheMap , organization :: CacheOrg , size :: Int , file :: String , blockSize :: Int } deriving (Show) data CacheStats = CacheStats { hits :: Int , misses :: Int } deriving (Show) instance Semigroup CacheStats where c1 <> c2 = CacheStats { hits = (hits c1) + (hits c2) , misses = (misses c1) + (misses c2) } instance Monoid CacheStats where mempty = CacheStats { hits = 0 , misses = 0 } data MemoryAccess = Instruction Int | Data Int deriving (Show, Eq) address :: MemoryAccess -> Int address (Instruction a) = a address (Data a) = a data Flag = FlagMapping (Either String CacheMap) | FlagOrganization (Either String CacheOrg ) | FlagSize (Either String Int) | FlagFile String | FlagHelp deriving (Show, Eq) -- class Cache a e where -- contains :: a -> e -> Bool -- insert :: a -> e -> a -- newtype DirectMappedCache m = DirectMappedCache m -- newtype FullAssociativeCache m = FullAssociativeCache m -- instance Cache (DirectMappedCache Array) Int where -- contains cache value = undefined -- insert cache value = undefined -- instance Cache (FullAssociativeCache Array) Int where -- contains cache value = undefined -- insert cache value = undefined options :: [OptDescr Flag] options = [ Option ['m'] ["mapping"] m "Type of cache mapping" , Option ['o'] ["organization"] o "Type of cache organization" , Option ['s'] ["size"] s "Cache size" , Option ['f'] ["file"] f "File with memory dump" , Option ['h', '?'] ["help"] (NoArg FlagHelp) "Show usage" ] where fm :: String -> Either String CacheMap fm "DM" = Right DirectMapping fm "FA" = Right FullAssociative fm x = Left $ "No such cache mapping: " ++ x m = ReqArg (FlagMapping . fm) "DM|FA" fo :: String -> Either String CacheOrg fo "UC" = Right Unified fo "SC" = Right Split fo x = Left $ "No such cache organization: " ++ x o = ReqArg (FlagOrganization . fo) "UC|SC" isPowerOf2 n = n .&. (n - 1) == 0 fs :: String -> Either String Int fs x = case readMaybe x of Nothing -> Left $ "Cannot parse cache size: " ++ x Just i -> if isPowerOf2 i then Right i else Left $ x ++ " is not a power of 2" s = ReqArg (FlagSize . fs) "KB (number which is a power of 2)" f = ReqArg FlagFile "FILE" handleArgs :: IO (Either String Config) handleArgs = do argList <- getArgs let args = getOpt RequireOrder options argList -- TODO: Print Flag Left sides return $ case args of (_,_,errs@(_:_)) -> Left $ concat errs ++ usageInfo "" options (FlagMapping (Right m):FlagOrganization (Right o):FlagSize (Right s):FlagFile f:_,[],[]) -> Right $ Config { mapping = m , organization = o , size = s , file = f , blockSize = 64 } _ -> Left $ usageInfo "aaaaa" options parseFile :: String -> Either String [MemoryAccess] parseFile = mapM lineToInstr . lines where lineToInstr :: String -> Either String MemoryAccess lineToInstr s = do (i,d) <- case words s of i:d:_ -> Right (i, d) _ -> Left $ "Cannot parse line: " ++ s n <- case readHex d of [(n,"")] -> Right n _ -> Left $ "Cannot parse line: " ++ s case i of "I" -> Right $ Instruction n "D" -> Right $ Data n _ -> Left $ "Cannot parse line: " ++ s mask :: Int -> Int -> Int -> Int mask digits offset n = shift (2^digits - 1) offset .&. n directMappingSimulation :: Config -> [MemoryAccess] -> t2 -> CacheStats -> CacheStats directMappingSimulation c [] cache stats = stats directMappingSimulation c (m:ms) cache stats = let numberOfBlocks = (size c) `div` (blockSize c) bitsForOffset = finiteBitSize $ blockSize c bitsForIndex = finiteBitSize $ numberOfBlocks bitsForTag = 32 - bitsForIndex - bitsForOffset index = mask bitsForIndex bitsForOffset $ address m tag = mask bitsForTag (bitsForIndex + bitsForOffset) $ address m contains = undefined newCache = if contains m cache then cache else newStats = if contains m cache then stats { hits = hits stats + 1 } else stats { misses = misses stats + 1 } in directMappingSimulation c ms newCache newStats fullAssociativeSimulation :: Config -> [MemoryAccess] -> t2 -> Int -> CacheStats -> CacheStats fullAssociativeSimulation c [] cache i stats = stats fullAssociativeSimulation c (m:ms) cache i stats = let tag = mask (32 - (finiteBitSize $ blockSize c)) (finiteBitSize $ blockSize c) $ address m contains = undefined newCache = undefined newStats = if contains m cache i then stats { hits = hits stats + 1 } else stats { misses = misses stats + 1 } in fullAssociativeSimulation c ms newCache (i + 1 `mod` (blockSize c)) newStats -- f :: [MemoryAccess] -> Writer CacheStats [MemoryAccess] -- f accessesLeft = x -- where -- head x simulateCache :: Config -> [MemoryAccess] -> CacheStats simulateCache c m = CacheStats {hits=1, misses=2} printStats :: CacheStats -> IO () printStats = print main :: IO () main = do config <- handleArgs config' <- case config of Left err -> putStrLn err >> exitFailure Right cfg -> return cfg fileContent <- readFile $ file config' print $ parseFile fileContent case parseFile fileContent of Left err -> putStrLn err >> exitFailure Right memory -> printStats $ simulateCache config' memory