2 -- Functions to generate VHDL from FlatFunctions
7 import qualified Data.Foldable as Foldable
8 import qualified Data.List as List
9 import qualified Data.Map as Map
10 import qualified Maybe
11 import qualified Control.Monad as Monad
12 import qualified Control.Arrow as Arrow
13 import qualified Control.Monad.Trans.State as State
14 import qualified Data.Traversable as Traversable
15 import qualified Data.Monoid as Monoid
17 import qualified Data.Accessor.MonadState as MonadState
20 import qualified ForSyDe.Backend.VHDL.AST as AST
25 import qualified TyCon
26 import Outputable ( showSDoc, ppr )
32 import TranslatorTypes
38 -> [(AST.VHDLId, AST.DesignFile)]
40 createDesignFiles flatfuncmap =
41 (mkVHDLId "types", AST.DesignFile ieee_context [type_package]) :
42 map (Arrow.second $ AST.DesignFile full_context) units
45 init_session = VHDLSession Map.empty builtin_funcs
46 (units, final_session) =
47 State.runState (createLibraryUnits flatfuncmap) init_session
48 ty_decls = Map.elems (final_session ^. vsTypes)
50 AST.Library $ mkVHDLId "IEEE",
51 AST.Use $ (AST.NSimple $ mkVHDLId "IEEE.std_logic_1164") AST.:.: AST.All
54 (AST.Use $ (AST.NSimple $ mkVHDLId "work.types") AST.:.: AST.All)
56 type_package = AST.LUPackageDec $ AST.PackageDec (mkVHDLId "types") (map (AST.PDITD . snd) ty_decls)
60 -> VHDLState [(AST.VHDLId, [AST.LibraryUnit])]
62 createLibraryUnits flatfuncmap = do
63 let hsfuncs = Map.keys flatfuncmap
64 let flatfuncs = Map.elems flatfuncmap
65 entities <- Monad.zipWithM createEntity hsfuncs flatfuncs
66 archs <- Monad.zipWithM createArchitecture hsfuncs flatfuncs
69 let AST.EntityDec id _ = ent in
70 (id, [AST.LUEntity ent, AST.LUArch arch])
74 -- | Create an entity for a given function
76 HsFunction -- | The function signature
77 -> FlatFunction -- | The FlatFunction
78 -> VHDLState AST.EntityDec -- | The resulting entity
80 createEntity hsfunc flatfunc = do
81 let sigs = flat_sigs flatfunc
82 let args = flat_args flatfunc
83 let res = flat_res flatfunc
84 args' <- Traversable.traverse (Traversable.traverse (mkMap sigs)) args
85 res' <- Traversable.traverse (mkMap sigs) res
86 let ent_decl' = createEntityAST hsfunc args' res'
87 let AST.EntityDec entity_id _ = ent_decl'
88 let signature = Entity entity_id args' res'
89 modA vsSignatures (Map.insert hsfunc signature)
93 [(SignalId, SignalInfo)]
95 -> VHDLState VHDLSignalMapElement
96 -- We only need the vsTypes element from the state
97 mkMap sigmap = MonadState.lift vsTypes . (\id ->
99 info = Maybe.fromMaybe
100 (error $ "Signal not found in the name map? This should not happen!")
103 (error $ "Signal not named? This should not happen!")
107 if isPortSigUse $ sigUse info
109 type_mark <- vhdl_ty ty
110 return $ Just (mkVHDLId nm, type_mark)
115 -- | Create the VHDL AST for an entity
117 HsFunction -- | The signature of the function we're working with
118 -> [VHDLSignalMap] -- | The entity's arguments
119 -> VHDLSignalMap -- | The entity's result
120 -> AST.EntityDec -- | The entity with the ent_decl filled in as well
122 createEntityAST hsfunc args res =
123 AST.EntityDec vhdl_id ports
125 vhdl_id = mkEntityId hsfunc
126 ports = concatMap (mapToPorts AST.In) args
127 ++ mapToPorts AST.Out res
129 mapToPorts :: AST.Mode -> VHDLSignalMap -> [AST.IfaceSigDec]
131 Maybe.catMaybes $ map (mkIfaceSigDec mode) (Foldable.toList m)
132 -- Add a clk port if we have state
133 clk_port = if hasState hsfunc
135 [AST.IfaceSigDec (mkVHDLId "clk") AST.In VHDL.std_logic_ty]
139 -- | Create a port declaration
141 AST.Mode -- | The mode for the port (In / Out)
142 -> Maybe (AST.VHDLId, AST.TypeMark) -- | The id and type for the port
143 -> Maybe AST.IfaceSigDec -- | The resulting port declaration
145 mkIfaceSigDec mode (Just (id, ty)) = Just $ AST.IfaceSigDec id mode ty
146 mkIfaceSigDec _ Nothing = Nothing
148 -- | Generate a VHDL entity name for the given hsfunc
150 -- TODO: This doesn't work for functions with multiple signatures!
151 mkVHDLId $ hsFuncName hsfunc
153 -- | Create an architecture for a given function
154 createArchitecture ::
155 HsFunction -- ^ The function signature
156 -> FlatFunction -- ^ The FlatFunction
157 -> VHDLState AST.ArchBody -- ^ The architecture for this function
159 createArchitecture hsfunc flatfunc = do
160 signaturemap <- getA vsSignatures
161 let signature = Maybe.fromMaybe
162 (error $ "Generating architecture for function " ++ (prettyShow hsfunc) ++ "without signature? This should not happen!")
163 (Map.lookup hsfunc signaturemap)
164 let entity_id = ent_id signature
165 -- Create signal declarations for all internal and state signals
166 sig_dec_maybes <- mapM (mkSigDec' . snd) sigs
167 let sig_decs = Maybe.catMaybes $ sig_dec_maybes
168 -- Create concurrent statements for all signal definitions
169 let statements = zipWith (mkConcSm signaturemap sigs) defs [0..]
170 return $ AST.ArchBody (mkVHDLId "structural") (AST.NSimple entity_id) (map AST.BDISD sig_decs) (statements ++ procs')
172 sigs = flat_sigs flatfunc
173 args = flat_args flatfunc
174 res = flat_res flatfunc
175 defs = flat_defs flatfunc
176 procs = map mkStateProcSm (makeStatePairs flatfunc)
177 procs' = map AST.CSPSm procs
178 -- mkSigDec only uses vsTypes from the state
179 mkSigDec' = MonadState.lift vsTypes . mkSigDec
181 -- | Looks up all pairs of old state, new state signals, together with
182 -- the state id they represent.
183 makeStatePairs :: FlatFunction -> [(StateId, SignalInfo, SignalInfo)]
184 makeStatePairs flatfunc =
185 [(Maybe.fromJust $ oldStateId $ sigUse old_info, old_info, new_info)
186 | old_info <- map snd (flat_sigs flatfunc)
187 , new_info <- map snd (flat_sigs flatfunc)
188 -- old_info must be an old state (and, because of the next equality,
189 -- new_info must be a new state).
190 , Maybe.isJust $ oldStateId $ sigUse old_info
191 -- And the state numbers must match
192 , (oldStateId $ sigUse old_info) == (newStateId $ sigUse new_info)]
194 -- Replace the second tuple element with the corresponding SignalInfo
195 --args_states = map (Arrow.second $ signalInfo sigs) args
196 mkStateProcSm :: (StateId, SignalInfo, SignalInfo) -> AST.ProcSm
197 mkStateProcSm (num, old, new) =
198 AST.ProcSm label [clk] [statement]
200 label = mkVHDLId $ "state_" ++ (show num)
202 rising_edge = AST.NSimple $ mkVHDLId "rising_edge"
203 wform = AST.Wform [AST.WformElem (AST.PrimName $ AST.NSimple $ getSignalId new) Nothing]
204 assign = AST.SigAssign (AST.NSimple $ getSignalId old) wform
205 rising_edge_clk = AST.PrimFCall $ AST.FCall rising_edge [Nothing AST.:=>: (AST.ADName $ AST.NSimple clk)]
206 statement = AST.IfSm rising_edge_clk [assign] [] Nothing
208 mkSigDec :: SignalInfo -> TypeState (Maybe AST.SigDec)
210 let use = sigUse info in
211 if isInternalSigUse use || isStateSigUse use then do
212 type_mark <- vhdl_ty ty
213 return $ Just (AST.SigDec (getSignalId info) type_mark Nothing)
219 -- | Creates a VHDL Id from a named SignalInfo. Errors out if the SignalInfo
221 getSignalId :: SignalInfo -> AST.VHDLId
223 mkVHDLId $ Maybe.fromMaybe
224 (error $ "Unnamed signal? This should not happen!")
227 -- | Transforms a signal definition into a VHDL concurrent statement
229 SignatureMap -- ^ The interfaces of functions in the session
230 -> [(SignalId, SignalInfo)] -- ^ The signals in the current architecture
231 -> SigDef -- ^ The signal definition
232 -> Int -- ^ A number that will be unique for all
233 -- concurrent statements in the architecture.
234 -> AST.ConcSm -- ^ The corresponding VHDL component instantiation.
236 mkConcSm signatures sigs (FApp hsfunc args res) num =
238 signature = Maybe.fromMaybe
239 (error $ "Using function '" ++ (prettyShow hsfunc) ++ "' without signature? This should not happen!")
240 (Map.lookup hsfunc signatures)
241 entity_id = ent_id signature
242 label = (AST.fromVHDLId entity_id) ++ "_" ++ (show num)
243 -- Add a clk port if we have state
244 clk_port = Maybe.fromJust $ mkAssocElem (Just $ mkVHDLId "clk") "clk"
245 portmaps = mkAssocElems sigs args res signature ++ (if hasState hsfunc then [clk_port] else [])
247 AST.CSISm $ AST.CompInsSm (mkVHDLId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps)
249 mkConcSm _ sigs (UncondDef src dst) _ =
251 src_expr = vhdl_expr src
252 src_wform = AST.Wform [AST.WformElem src_expr Nothing]
253 dst_name = AST.NSimple (getSignalId $ signalInfo sigs dst)
254 assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
258 vhdl_expr (Left id) = mkIdExpr sigs id
259 vhdl_expr (Right expr) =
262 (mkIdExpr sigs id) AST.:=: (AST.PrimLit lit)
266 (mkIdExpr sigs a) AST.:=: (mkIdExpr sigs b)
268 mkConcSm _ sigs (CondDef cond true false dst) _ =
270 cond_expr = mkIdExpr sigs cond
271 true_expr = mkIdExpr sigs true
272 false_expr = mkIdExpr sigs false
273 false_wform = AST.Wform [AST.WformElem false_expr Nothing]
274 true_wform = AST.Wform [AST.WformElem true_expr Nothing]
275 whenelse = AST.WhenElse true_wform cond_expr
276 dst_name = AST.NSimple (getSignalId $ signalInfo sigs dst)
277 assign = dst_name AST.:<==: (AST.ConWforms [whenelse] false_wform Nothing)
281 -- | Turn a SignalId into a VHDL Expr
282 mkIdExpr :: [(SignalId, SignalInfo)] -> SignalId -> AST.Expr
284 let src_name = AST.NSimple (getSignalId $ signalInfo sigs id) in
285 AST.PrimName src_name
288 [(SignalId, SignalInfo)] -- | The signals in the current architecture
289 -> [SignalMap] -- | The signals that are applied to function
290 -> SignalMap -- | the signals in which to store the function result
291 -> Entity -- | The entity to map against.
292 -> [AST.AssocElem] -- | The resulting port maps
294 mkAssocElems sigmap args res entity =
295 -- Create the actual AssocElems
296 Maybe.catMaybes $ zipWith mkAssocElem ports sigs
298 -- Turn the ports and signals from a map into a flat list. This works,
299 -- since the maps must have an identical form by definition. TODO: Check
301 arg_ports = concat (map Foldable.toList (ent_args entity))
302 res_ports = Foldable.toList (ent_res entity)
303 arg_sigs = (concat (map Foldable.toList args))
304 res_sigs = Foldable.toList res
305 -- Extract the id part from the (id, type) tuple
306 ports = (map (fmap fst) (arg_ports ++ res_ports))
307 -- Translate signal numbers into names
308 sigs = (map (lookupSigName sigmap) (arg_sigs ++ res_sigs))
310 -- | Look up a signal in the signal name map
311 lookupSigName :: [(SignalId, SignalInfo)] -> SignalId -> String
312 lookupSigName sigs sig = name
314 info = Maybe.fromMaybe
315 (error $ "Unknown signal " ++ (show sig) ++ " used? This should not happen!")
317 name = Maybe.fromMaybe
318 (error $ "Unnamed signal " ++ (show sig) ++ " used? This should not happen!")
321 -- | Create an VHDL port -> signal association
322 mkAssocElem :: Maybe AST.VHDLId -> String -> Maybe AST.AssocElem
323 mkAssocElem (Just port) signal = Just $ Just port AST.:=>: (AST.ADName (AST.NSimple (mkVHDLId signal)))
324 mkAssocElem Nothing _ = Nothing
326 -- | The VHDL Bit type
327 bit_ty :: AST.TypeMark
328 bit_ty = AST.unsafeVHDLBasicId "Bit"
330 -- | The VHDL Boolean type
331 bool_ty :: AST.TypeMark
332 bool_ty = AST.unsafeVHDLBasicId "Boolean"
334 -- | The VHDL std_logic
335 std_logic_ty :: AST.TypeMark
336 std_logic_ty = AST.unsafeVHDLBasicId "std_logic"
338 -- Translate a Haskell type to a VHDL type
339 vhdl_ty :: Type.Type -> TypeState AST.TypeMark
342 let builtin_ty = do -- See if this is a tycon and lookup its name
343 (tycon, args) <- Type.splitTyConApp_maybe ty
344 let name = Name.getOccString (TyCon.tyConName tycon)
345 Map.lookup name builtin_types
346 -- If not a builtin type, try the custom types
347 let existing_ty = (fmap fst) $ Map.lookup (OrdType ty) typemap
348 case Monoid.getFirst $ Monoid.mconcat (map Monoid.First [builtin_ty, existing_ty]) of
349 -- Found a type, return it
351 -- No type yet, try to construct it
354 -- Use the Maybe Monad for failing when one of these fails
355 (tycon, args) <- Type.splitTyConApp_maybe ty
356 let name = Name.getOccString (TyCon.tyConName tycon)
358 "FSVec" -> Just $ mk_fsvec_ty ty args
360 -- Return new_ty when a new type was successfully created
362 (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty))
365 -- | Create a VHDL type belonging to a FSVec Haskell type
367 Type.Type -- ^ The Haskell type to create a VHDL type for
368 -> [Type.Type] -- ^ Type arguments to the FSVec type constructor
369 -> TypeState AST.TypeMark -- The typemark created.
371 mk_fsvec_ty ty args = do
372 -- Assume there are two type arguments
373 let [len, el_ty] = args
374 -- TODO: Find actual number
375 -- Construct the type id, but filter out dots (since these are not allowed).
376 let ty_id = mkVHDLId $ filter (/='.') ("vector_" ++ (show len))
378 let range = AST.IndexConstraint [AST.ToRange (AST.PrimLit "0") (AST.PrimLit "16")]
379 let ty_def = AST.TDA $ AST.ConsArrayDef range std_logic_ty
380 let ty_dec = AST.TypeDec ty_id ty_def
381 -- TODO: Check name uniqueness
382 State.modify (Map.insert (OrdType ty) (ty_id, ty_dec))
388 ("Bit", std_logic_ty),
389 ("Bool", bool_ty) -- TysWiredIn.boolTy
393 mkVHDLId :: String -> AST.VHDLId
395 AST.unsafeVHDLBasicId $ (strip_multiscore . strip_invalid) s
397 -- Strip invalid characters.
398 strip_invalid = filter (`elem` ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_.")
399 -- Strip multiple adjacent underscores
400 strip_multiscore = concat . map (\cs ->
406 -- | A consise representation of a (set of) ports on a builtin function
407 type PortMap = HsValueMap (String, AST.TypeMark)
408 -- | A consise representation of a builtin function
409 data BuiltIn = BuiltIn String [PortMap] PortMap
411 -- | Translate a list of concise representation of builtin functions to a
413 mkBuiltins :: [BuiltIn] -> SignatureMap
414 mkBuiltins = Map.fromList . map (\(BuiltIn name args res) ->
415 (HsFunction name (map useAsPort args) (useAsPort res),
416 Entity (VHDL.mkVHDLId name) (map toVHDLSignalMap args) (toVHDLSignalMap res))
419 builtin_hsfuncs = Map.keys builtin_funcs
420 builtin_funcs = mkBuiltins
422 BuiltIn "hwxor" [(Single ("a", VHDL.bit_ty)), (Single ("b", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)),
423 BuiltIn "hwand" [(Single ("a", VHDL.bit_ty)), (Single ("b", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)),
424 BuiltIn "hwor" [(Single ("a", VHDL.bit_ty)), (Single ("b", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)),
425 BuiltIn "hwnot" [(Single ("a", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty))
428 -- | Map a port specification of a builtin function to a VHDL Signal to put in
430 toVHDLSignalMap :: HsValueMap (String, AST.TypeMark) -> VHDLSignalMap
431 toVHDLSignalMap = fmap (\(name, ty) -> Just (mkVHDLId name, ty))
433 -- vim: set ts=8 sw=2 sts=2 expandtab: