1 module FlattenTypes where
4 import Data.Traversable
5 import qualified Data.Foldable as Foldable
6 import qualified Control.Monad.State as State
13 -- | A signal identifier
16 -- | A map of a Haskell value to signal ids
17 type SignalMap = HsValueMap SignalId
19 -- | A state identifier
22 -- | How is a given (single) value in a function's type (ie, argument or
23 -- return value) used?
25 Port -- ^ Use it as a port (input or output)
26 | State StateId -- ^ Use it as state (input or output). The int is used to
27 -- match input state to output state.
28 | HighOrder { -- ^ Use it as a high order function input
29 hoName :: String, -- ^ Which function is passed in?
30 hoArgs :: [HsUseMap] -- ^ Which arguments are already applied? This
31 -- ^ map should only contain Port and other
34 deriving (Show, Eq, Ord)
36 -- | Is this HsValueUse a state use?
37 isStateUse :: HsValueUse -> Bool
38 isStateUse (State _) = True
41 -- | A map from a Haskell value to the use of each single value
42 type HsUseMap = HsValueMap HsValueUse
44 -- | Builds a HsUseMap with the same structure has the given HsValueMap in
45 -- which all the Single elements are marked as State, with increasing state
47 useAsState :: HsValueMap a -> HsUseMap
51 -- Traverse the existing map, resulting in a function that maps an initial
52 -- state number to the final state number and the new map
53 PassState f = traverse asState map
54 -- Run this function to get the new map
56 -- This function maps each element to a State with a unique number, by
57 -- incrementing the state count.
58 asState x = PassState (\s -> (s+1, State s))
60 -- | Builds a HsUseMap with the same structure has the given HsValueMap in
61 -- which all the Single elements are marked as Port.
62 useAsPort :: HsValueMap a -> HsUseMap
63 useAsPort map = fmap (\x -> Port) map
65 -- | A Haskell function with a specific signature. The signature defines what
66 -- use the arguments and return value of the function get.
67 data HsFunction = HsFunction {
69 hsFuncArgs :: [HsUseMap],
71 } deriving (Show, Eq, Ord)
73 hasState :: HsFunction -> Bool
75 any (Foldable.any isStateUse) (hsFuncArgs hsfunc)
76 || Foldable.any isStateUse (hsFuncRes hsfunc)
78 -- | Something that defines a signal
80 -- | A flattened function application
82 appFunc :: HsFunction,
83 appArgs :: [SignalMap],
86 -- | A conditional signal definition
93 -- | Unconditional signal definition
95 defSrc :: Either SignalId SignalExpr,
99 -- | Is the given SigDef a FApp?
100 is_FApp :: SigDef -> Bool
101 is_FApp d = case d of
105 -- | An expression on signals
107 EqLit SignalId String -- ^ Is the given signal equal to the given (VHDL) literal
108 | Literal String -- ^ A literal value
109 | Eq SignalId SignalId -- ^ A comparison between to signals
112 -- Returns the function used by the given SigDef, if any
113 usedHsFunc :: SigDef -> Maybe HsFunction
114 usedHsFunc (FApp hsfunc _ _) = Just hsfunc
115 usedHsFunc _ = Nothing
117 -- | How is a given signal used in the resulting VHDL?
119 SigPortIn -- | Use as an input port
120 | SigPortOut -- | Use as an input port
121 | SigInternal -- | Use as an internal signal
122 | SigStateOld StateId -- | Use as the current internal state
123 | SigStateNew StateId -- | Use as the new internal state
124 | SigSubState -- | Do not use, state variable is used in a subcircuit
126 -- | Is this a port signal use?
127 isPortSigUse :: SigUse -> Bool
128 isPortSigUse SigPortIn = True
129 isPortSigUse SigPortOut = True
130 isPortSigUse _ = False
132 -- | Is this a state signal use? Returns false for substate.
133 isStateSigUse :: SigUse -> Bool
134 isStateSigUse (SigStateOld _) = True
135 isStateSigUse (SigStateNew _) = True
136 isStateSigUse _ = False
138 -- | Is this an internal signal use?
139 isInternalSigUse :: SigUse -> Bool
140 isInternalSigUse SigInternal = True
141 isInternalSigUse _ = False
143 -- | Information on a signal definition
144 data SignalInfo = SignalInfo {
145 sigName :: Maybe String,
148 nameHints :: [String]
151 -- | A flattened function
152 data FlatFunction = FlatFunction {
153 flat_args :: [SignalMap],
154 flat_res :: SignalMap,
155 flat_defs :: [SigDef],
156 flat_sigs :: [(SignalId, SignalInfo)]
159 -- | Lookup a given signal id in a signal map, and return the associated
160 -- SignalInfo. Errors out if the signal was not found.
161 signalInfo :: [(SignalId, SignalInfo)] -> SignalId -> SignalInfo
162 signalInfo sigs id = Maybe.fromJust $ lookup id sigs
164 -- | A list of binds in effect at a particular point of evaluation
166 CoreBndr, -- ^ The bind name
167 BindValue -- ^ The value bound to it
171 Either -- ^ The bind value which is either
175 HsValueUse, -- ^ or a HighOrder function
176 [SignalId] -- ^ With these signals already applied to it
179 -- | The state during the flattening of a single function
180 type FlattenState = State.State ([SigDef], [(SignalId, SignalInfo)], SignalId)
182 -- | Add an application to the current FlattenState
183 addDef :: SigDef -> FlattenState ()
185 (defs, sigs, n) <- State.get
186 State.put (d:defs, sigs, n)
188 -- | Generates a new signal id, which is unique within the current flattening.
189 genSignalId :: SigUse -> Type.Type -> FlattenState SignalId
190 genSignalId use ty = do
191 (defs, sigs, n) <- State.get
192 -- Generate a new numbered but unnamed signal
193 let s = (n, SignalInfo Nothing use ty [])
194 State.put (defs, s:sigs, n+1)
197 -- | Add a name hint to the given signal
198 addNameHint :: String -> SignalId -> FlattenState ()
199 addNameHint hint id = do
200 info <- getSignalInfo id
201 let hints = nameHints info
206 let hints' = (hint:hints)
207 setSignalInfo id (info {nameHints = hints'})
209 -- | Returns the SignalInfo for the given signal. Errors if the signal is not
210 -- known in the session.
211 getSignalInfo :: SignalId -> FlattenState SignalInfo
212 getSignalInfo id = do
213 (defs, sigs, n) <- State.get
214 return $ signalInfo sigs id
216 setSignalInfo :: SignalId -> SignalInfo -> FlattenState ()
217 setSignalInfo id' info' = do
218 (defs, sigs, n) <- State.get
219 let sigs' = map (\(id, info) -> (id, if id == id' then info' else info)) sigs
220 State.put (defs, sigs', n)
222 -- vim: set ts=8 sw=2 sts=2 expandtab: