sv2v/Language/Verilog/Simulator.hs

172 lines
6.3 KiB
Haskell
Raw Normal View History

module Language.Verilog.Simulator
( Simulator
, SimCommand (..)
, SimResponse (..)
, simulator
) where
import Control.Monad (when)
import Data.Array.IO
import Data.Bits
import Data.IORef
import Data.Monoid
import System.IO
import Data.VCD hiding (Var, step)
import qualified Data.VCD as VCD
import Data.BitVec
import Language.Verilog.Netlist
--check msg = putStrLn msg >> hFlush stdout
-- | A Simulator executes 'SimCommand's.
type Simulator = SimCommand -> IO (Maybe SimResponse)
-- | Simulation commands.
data SimCommand
= Init (Maybe FilePath)
| Step
| GetSignalId Path
| GetSignal NetId
| Close
-- | Simulation responses.
data SimResponse
= Id NetId -- ^ Response to GetSignalId.
| Value BitVec -- ^ Response to GetSignal.
-- | Builds a 'Simulator' given a 'Netlist'.
simulator :: Netlist BlackBoxInit -> IO Simulator
simulator netlist' = do
let netlist = sortTopo netlist'
memory <- memory netlist
vcd <- newIORef Nothing
sample <- newIORef $ return ()
step <- newIORef $ return ()
return $ \ cmd -> case cmd of
Init file -> initialize netlist memory vcd file sample step
Step -> readIORef step >>= id >> return Nothing
GetSignalId path -> return $ getSignalId netlist path
GetSignal id -> readArray memory id >>= return . Just . Value
Close -> close vcd sample step >> return Nothing
getSignalId :: Netlist BlackBoxInit -> Path -> Maybe SimResponse
getSignalId netlist path = case lookup path paths' of
Nothing -> Nothing
Just i -> Just $ Id i
where
paths = [ (paths, id) | Reg id _ paths _ <- netlist ] ++ [ (paths, id) | Var id _ paths _ <- netlist ]
paths' = [ (path, id) | (paths, id) <- paths, path <- paths ]
type Memory = IOArray Int BitVec
memory :: Netlist BlackBoxInit -> IO Memory
memory netlist
| null netlist = error "Empty netlist, nothing to simulate."
| otherwise = newArray (0, maximum ids) 0
where
ids = concatMap f netlist
f a = case a of
Var a _ _ _ -> [a]
Reg a _ _ _ -> [a]
BBox _ _ _ -> []
initialize :: Netlist BlackBoxInit -> Memory -> IORef (Maybe VCDHandle) -> Maybe FilePath -> IORef (IO ()) -> IORef (IO ()) -> IO (Maybe SimResponse)
initialize netlist memory vcd file sample step = do
close vcd sample step
mapM_ (initializeNet memory) netlist
case file of
Nothing -> return ()
Just file -> do
h <- openFile file WriteMode
vcd' <- newVCD h S
writeIORef vcd $ Just vcd'
writeIORef sample $ VCD.step vcd' 1
mapM_ (f memory vcd' sample) netlist
netlist <- mapM initializeBBox netlist
initializeStep netlist memory sample step
return Nothing
where
f :: Memory -> VCDHandle -> IORef (IO ()) -> Net BlackBoxInit -> IO ()
f memory vcd sample a = case a of
BBox _ _ _ -> return ()
_ -> mapM_ (\ signal -> do
sample' <- var vcd signal $ bitVec width 0
modifyIORef sample (>> (readArray memory i >>= sample'))
) signals
where
(i, width, signals) = case a of
Reg i w p _ -> (i, w, p)
Var i w p _ -> (i, w, p)
BBox _ _ _ -> undefined
initializeNet :: Memory -> Net BlackBoxInit -> IO ()
initializeNet memory a = case a of
Var i w _ _ -> writeArray memory i $ bitVec w 0
Reg i w _ _ -> writeArray memory i $ bitVec w 0
BBox _ _ _ -> return ()
initializeBBox :: Net BlackBoxInit -> IO (Net BlackBoxStep)
initializeBBox a = case a of
Var a b c d -> return $ Var a b c d
Reg a b c d -> return $ Reg a b c d
BBox i o init -> init >>= return . BBox i o
initializeStep :: Netlist BlackBoxStep -> Memory -> IORef (IO ()) -> IORef (IO ()) -> IO ()
initializeStep netlist memory sample step = do
let steps = map stepNet netlist
writeIORef step $ do
sequence_ steps
readIORef sample >>= id
where
read = readArray memory
write' = writeMemory memory
stepNet :: Net BlackBoxStep -> IO ()
stepNet a = case a of
BBox inputs outputs f -> do
outs <- mapM read inputs >>= f
sequence_ [ write' a b | (a, b) <- zip outputs outs ]
Reg q _ _ d -> read d >>= write' q
Var i _ _ expr -> case expr of
AInput -> return ()
AVar a -> read a >>= write
AConst a -> write a
ASelect a b c -> do { a <- read a; b <- read b; c <- read c; write $ select a (b, c) }
ABWNot a -> read a >>= write . complement
ABWAnd a b -> do { a <- read a; b <- read b; write $ a .&. b }
ABWXor a b -> do { a <- read a; b <- read b; write $ a `xor` b }
ABWOr a b -> do { a <- read a; b <- read b; write $ a .|. b }
AMul a b -> do { a <- read a; b <- read b; write $ a * b }
AAdd a b -> do { a <- read a; b <- read b; write $ a + b }
ASub a b -> do { a <- read a; b <- read b; write $ a - b }
AShiftL a b -> do { a <- read a; b <- read b; write $ shiftL a $ fromIntegral $ value b }
AShiftR a b -> do { a <- read a; b <- read b; write $ shiftR a $ fromIntegral $ value b }
AEq a b -> do { a <- read a; b <- read b; write $ bitVec 1 (if value a == value b then 1 else 0) }
ANe a b -> do { a <- read a; b <- read b; write $ bitVec 1 (if value a /= value b then 1 else 0) }
ALt a b -> do { a <- read a; b <- read b; write $ bitVec 1 (if value a < value b then 1 else 0) }
ALe a b -> do { a <- read a; b <- read b; write $ bitVec 1 (if value a <= value b then 1 else 0) }
AGt a b -> do { a <- read a; b <- read b; write $ bitVec 1 (if value a > value b then 1 else 0) }
AGe a b -> do { a <- read a; b <- read b; write $ bitVec 1 (if value a >= value b then 1 else 0) }
AMux a b c -> do { a <- read a; b <- read b; c <- read c; write (if value a /= 0 then b else c) }
AConcat a b -> do { a <- read a; b <- read b; write $ mappend a b }
where
write = write' i
writeMemory :: Memory -> Int -> BitVec -> IO ()
writeMemory memory i a = do
b <- readArray memory i
when (width b /= width a) $ error $ "Memory update with different bit-vector width: index: " ++ show i ++ " old: " ++ show b ++ " new: " ++ show a
writeArray memory i a
close :: IORef (Maybe VCDHandle) -> IORef (IO ()) -> IORef (IO ()) -> IO ()
close vcd sample step = do
vcd' <- readIORef vcd
case vcd' of
Nothing -> return ()
Just vcd -> hClose $ handle vcd
writeIORef vcd $ Nothing
writeIORef sample $ return ()
writeIORef step $ return ()