packages feed

Wired-0.1: Lava/Internal.hs

module Lava.Internal
  ( module Lava.Model
  , module Lava.Patterns
  , module Lava.Loop
  , module Lava.Port
  , module Lava.Interpret
  , input
  , inputList
  , cell
  , label
  , toLava2000
  , simulateSeq
  , simulate
  , verify
  , depth
  , fanout
  , size
  ) where



import Control.Monad
import qualified Data.Foldable as Fold
import qualified Data.Map as Map

import Data.Hardware.Internal
import Lava.Model
import Lava.Patterns
import Lava.Loop
import Lava.Port
import Lava.Interpret

import qualified Lava2000 as L
import qualified Lava2000.Ref as L



input :: forall lib m p . (MonadLava lib m, PortFixed p Signal) => Name -> m p
input nm = liftM fromListFP $ replicateM (lengthFP (T::TypeOf p)) (inputSig nm)
  -- Declare a primary input

inputList :: (MonadLava lib m, PortFixed p Signal) => Int -> Name -> m [p]
inputList n nm = replicateM n $ input nm



cell
    :: forall m lib pi po
     . ( MonadLava lib m
       , PortFixed pi Signal
       , PortFixed po Signal
       , CellLibrary lib
       )
    => lib -> pi -> m po

cell cid pi = liftM fromListFP $ cellList cid ins
  where
    ins = Fold.toList $ port pi
  -- Declare a cell



label :: (MonadLava lib m, PortStruct p Signal t) => Tag -> p -> m p
label tag = mapPortM (labelSig tag)
  -- Declare a label; only side-effect important.



toLava2000
    :: ( CellLibrary lib
       , PortStruct pli (L.Signal Bool) ti
       , PortStruct psi Signal          ti
       , PortStruct pso Signal          to
       , PortStruct plo (L.Signal Bool) to
       )
    => (psi -> Lava lib pso)
    -> (pli -> plo)

toLava2000 circ = fst . interpretFunc lava2000Interp circ



simulateSeq
    :: ( CellLibrary lib
       , PortStruct pni Int    ti
       , PortStruct psi Signal ti
       , PortStruct pso Signal to
       , PortStruct pno Int    to
       )
    => (psi -> Lava lib pso)
    -> ([pni] -> [pno])

simulateSeq circ
    = map (unport . fmap sigToInt)
    . L.simulateSeq circP
    . map (fmap intToSig . port)
  where
    circP = fst . interpretFuncP lava2000Interp (liftM port . circ . unport)

    intToSig 0 = L.low
    intToSig 1 = L.high
    intToSig _ = error "Only values 0 and 1 allowed"

    sigToInt (L.Signal (L.Symbol r)) = case L.deref r of
        L.Bool False -> 0
        L.Bool True  -> 1



simulate
    :: ( CellLibrary lib
       , PortStruct pni Int    ti
       , PortStruct psi Signal ti
       , PortStruct pso Signal to
       , PortStruct pno Int    to
       )
    => (psi -> Lava lib pso)
    -> (pni -> pno)

simulate circ = head . simulateSeq circ . return



verify
    :: forall lib ps
     . (CellLibrary lib, PortFixed ps Signal)
    => (ps -> Lava lib Signal) -> IO ()

verify circ = L.smv (L.forAll (L.list n) circP) >> return ()
  where
    n = lengthFP (T::TypeOf ps)

    circP = toLava2000 (circ . fromListFP)



depth :: (CellLibrary lib, PortStruct ps Signal t, PortStruct pd Int t) =>
    Lava lib ps -> (pd, InterpDesignDB lib Int)
depth circ
    | hasLoopDB True db = error "depth: Combinational feedback loop"
    | otherwise         = pd_idb
  where
    pd_idb@(_,(db,_)) = interpret depthInterp circ

fanout :: CellLibrary lib => Lava lib a -> InterpDesignDB lib Int
fanout circ = (db, fmap length $ fanoutDB db)
  where
    (_,db) = runLava circ

size :: CellLibrary lib => Lava lib p -> Int
size = length . Map.toList . cellDB . snd . runLava