signals-0.2.0.1: src/Signal/Compiler/Channels.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Signal.Compiler.Channels
( Identified(..)
, Identifiers
, Kind
, Scope (..)
, Ident (..)
, Channel (..)
, Channels(..)
, fromLinks
, opposite
)
where
import Signal.Core (S(..), Symbol)
import Signal.Core.Witness
import Signal.Compiler.Linker
import Control.Arrow (second)
import Control.Monad
import Control.Monad.Identity (Identity)
import Control.Monad.State (State)
import Control.Monad.Reader (Reader)
import qualified Control.Monad.Identity as CMI
import qualified Control.Monad.State as CMS
import qualified Control.Monad.Reader as CMR
import Data.Maybe (fromJust)
import Data.Typeable
import Data.Hashable
import Data.Ref
import Data.Ref.Map (Map, Entry, Name)
import qualified Data.Ref.Map as RMap
import qualified Data.IntMap as IMap
import Language.VHDL (Identifier)
import Language.Embedded.VHDL (Kind)
import qualified Language.VHDL as VHDL
import qualified Language.Embedded.VHDL as HDL
import Prelude hiding (Left, Right)
--------------------------------------------------------------------------------
-- * Compiler constructs
--------------------------------------------------------------------------------
-- I'm fairly certain that a number of these transformations (i.e,
-- keys -> links -> ...) can be done in a signle traversal. They are kept
-- seperate for now since I keep changing the implementation.
-- | Physical name representing a wire
data Identified a where
Identified :: Identifier -> Identified (S sym i a)
-- | Distributed identifiers
type Identifiers a = Distributed Identified a
--------------------------------------------------------------------------------
-- ** Nodes with Identifiers as keys
-- | Different kinds of scopes available
data Scope = Header | Global | Local
-- | Ident represents a wire with a set of names, kind and scope
data Ident (i :: (* -> *) -> * -> *) (a :: *) where
Ident :: Witness i a => Identifiers (S Symbol i a) -> Kind -> Scope -> Ident i a
-- | A channel is a linked node where names have been reified as well.
data Channel (i :: (* -> *) -> * -> *) (a :: *) where
Channel :: S Ident i a -> Ident i a -> Channel i (S Symbol i a)
-- | Short-hand for a mapping over channels
type Channels i = Map (Channel i)
--------------------------------------------------------------------------------
-- ** Channel construction
type Mapping = IMap.IntMap Identifier
type Rm = Reader Mapping
-- *** I make use of an ugly hack: a port variable is really a port input signal
-- This is due `declare` further down not taking a mode as input.
fromLinks :: Links i -> Channels i
fromLinks links = RMap.hmap (translate (fromList links)) links
where
translate :: Mapping -> Linked i a -> Channel i a
translate m (Linked node link) =
let out@(Ident i k s) = identify link
in case node of
Var d -> Channel (Var d) (Ident i k Header)
Repeat c -> Channel (Repeat c) (out)
Map f s -> Channel (Map f $ identify s) (out)
Delay d s -> Channel (Delay d $ identify s) (Ident i HDL.Signal Global)
Mux s cs ->
let inp = identify s
inps = fmap (second identify) cs
in Channel (Mux inp inps) out
where
identify :: forall i a. Link i a -> Ident i a
identify (Link names) = Ident (dist (witness :: Wit i a) names) HDL.Variable Local
where
dist :: Wit i x -> Names (S Symbol i x) -> Identifiers (S Symbol i x)
dist (WE) (Named name) = Identified $ fromJust $ IMap.lookup (hash name) m
dist (WP l r) (u, v) = (dist l u, dist r v)
--------------------------------------------------------------------------------
-- | Short-hand for state used in `fromList`
type Sm = State (Int, Mapping)
-- | Generates a mapping from name to identifier for each entry
fromList :: Links i -> Mapping
fromList ls = snd $ CMS.execState (mapM_ add $ RMap.elems ls) (0, IMap.empty)
where
add :: forall i. Entry (Linked i) -> Sm (){-
add (RMap.Entry _ (Linked (Delay {}) (Link name :: Link i (Identity a))))
= next name >>= insert name . opposite-}
add (RMap.Entry _ (Linked _ (Link names :: Link i a)))
= dist (witness :: Wit i a) names
where
dist :: Wit i x -> Names (S Symbol i x) -> Sm ()
dist (WE) (name) = next name >>= insert name
dist (WP l r) (u, v) = dist l u >> dist r v
-- | Generate a unique identifier
next :: Names (S Symbol i (Identity x)) -> Sm Identifier
next (Named name) = do
(i, m) <- CMS.get
CMS.put (i + 1, m)
return $ VHDL.Ident ('v' : show i)
-- | ...
insert :: Names (S Symbol i (Identity x)) -> Identifier -> Sm ()
insert (Named name) i = CMS.modify (second (IMap.insert (hash name) i))
-- | Every delay has an `opposite` which is used in the combinatorial process
opposite :: Identifier -> Identifier
opposite (VHDL.Ident i) = VHDL.Ident $ i ++ "_in"
--------------------------------------------------------------------------------
-- | Usefulness refers to whether we should generate code for the node or not
useful :: RMap.Entry (Linked i) -> Bool
useful (RMap.Entry name (Linked node link)) =
case node of
Var {} -> True
Repeat {} -> True
Map {} -> True
Delay {} -> True
Mux {} -> True
_ -> False
--------------------------------------------------------------------------------