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
18 import Text.Regex.Posix
22 import qualified ForSyDe.Backend.VHDL.AST as AST
28 import qualified OccName
30 import qualified TyCon
31 import qualified DataCon
32 import qualified CoreSubst
33 import Outputable ( showSDoc, ppr )
39 import TranslatorTypes
45 import GlobalNameTable
48 [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)]
49 -> [(AST.VHDLId, AST.DesignFile)]
51 createDesignFiles binds =
52 (mkVHDLBasicId "types", AST.DesignFile ieee_context [type_package]) :
53 map (Arrow.second $ AST.DesignFile full_context) units
56 init_session = VHDLSession Map.empty Map.empty builtin_funcs globalNameTable
57 (units, final_session) =
58 State.runState (createLibraryUnits binds) init_session
59 ty_decls = map (uncurry AST.TypeDec) $ Map.elems (final_session ^. vsTypes)
61 AST.Library $ mkVHDLBasicId "IEEE",
62 mkUseAll ["IEEE", "std_logic_1164"],
63 mkUseAll ["IEEE", "numeric_std"]
66 mkUseAll ["work", "types"]
68 type_package = AST.LUPackageDec $ AST.PackageDec (mkVHDLBasicId "types") (map AST.PDITD ty_decls)
70 -- Create a use foo.bar.all statement. Takes a list of components in the used
71 -- name. Must contain at least two components
72 mkUseAll :: [String] -> AST.ContextItem
74 AST.Use $ from AST.:.: AST.All
76 base_prefix = (AST.NSimple $ mkVHDLBasicId $ head ss)
77 from = foldl select base_prefix (tail ss)
78 select prefix s = AST.NSelected $ prefix AST.:.: (AST.SSimple $ mkVHDLBasicId s)
81 [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)]
82 -> VHDLState [(AST.VHDLId, [AST.LibraryUnit])]
84 createLibraryUnits binds = do
85 entities <- Monad.mapM createEntity binds
86 archs <- Monad.mapM createArchitecture binds
89 let AST.EntityDec id _ = ent in
90 (id, [AST.LUEntity ent, AST.LUArch arch])
94 -- | Create an entity for a given function
96 (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- | The function
97 -> VHDLState AST.EntityDec -- | The resulting entity
99 createEntity (fname, expr) = do
100 -- Strip off lambda's, these will be arguments
101 let (args, letexpr) = CoreSyn.collectBinders expr
102 args' <- Monad.mapM mkMap args
103 -- There must be a let at top level
104 let (CoreSyn.Let binds (CoreSyn.Var res)) = letexpr
106 let ent_decl' = createEntityAST fname args' res'
107 let AST.EntityDec entity_id _ = ent_decl'
108 let signature = Entity entity_id args' res'
109 modA vsSignatures (Map.insert (bndrToString fname) signature)
113 --[(SignalId, SignalInfo)]
115 -> VHDLState VHDLSignalMapElement
116 -- We only need the vsTypes element from the state
119 --info = Maybe.fromMaybe
120 -- (error $ "Signal not found in the name map? This should not happen!")
121 -- (lookup id sigmap)
122 -- Assume the bndr has a valid VHDL id already
123 id = bndrToVHDLId bndr
124 ty = Var.varType bndr
126 if True -- isPortSigUse $ sigUse info
128 type_mark <- vhdl_ty ty
129 return $ Just (id, type_mark)
134 -- | Create the VHDL AST for an entity
136 CoreSyn.CoreBndr -- | The name of the function
137 -> [VHDLSignalMapElement] -- | The entity's arguments
138 -> VHDLSignalMapElement -- | The entity's result
139 -> AST.EntityDec -- | The entity with the ent_decl filled in as well
141 createEntityAST name args res =
142 AST.EntityDec vhdl_id ports
144 -- Create a basic Id, since VHDL doesn't grok filenames with extended Ids.
145 vhdl_id = mkVHDLBasicId $ bndrToString name
146 ports = Maybe.catMaybes $
147 map (mkIfaceSigDec AST.In) args
148 ++ [mkIfaceSigDec AST.Out res]
150 -- Add a clk port if we have state
151 clk_port = if True -- hasState hsfunc
153 Just $ AST.IfaceSigDec (mkVHDLExtId "clk") AST.In VHDL.std_logic_ty
157 -- | Create a port declaration
159 AST.Mode -- | The mode for the port (In / Out)
160 -> Maybe (AST.VHDLId, AST.TypeMark) -- | The id and type for the port
161 -> Maybe AST.IfaceSigDec -- | The resulting port declaration
163 mkIfaceSigDec mode (Just (id, ty)) = Just $ AST.IfaceSigDec id mode ty
164 mkIfaceSigDec _ Nothing = Nothing
166 -- | Generate a VHDL entity name for the given hsfunc
168 -- TODO: This doesn't work for functions with multiple signatures!
169 -- Use a Basic Id, since using extended id's for entities throws off
170 -- precision and causes problems when generating filenames.
171 mkVHDLBasicId $ hsFuncName hsfunc
173 -- | Create an architecture for a given function
174 createArchitecture ::
175 (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- ^ The function
176 -> VHDLState AST.ArchBody -- ^ The architecture for this function
178 createArchitecture (fname, expr) = do
179 --signaturemap <- getA vsSignatures
180 --let signature = Maybe.fromMaybe
181 -- (error $ "Generating architecture for function " ++ (prettyShow hsfunc) ++ "without signature? This should not happen!")
182 -- (Map.lookup hsfunc signaturemap)
183 let entity_id = mkVHDLBasicId $ bndrToString fname
184 -- Strip off lambda's, these will be arguments
185 let (args, letexpr) = CoreSyn.collectBinders expr
186 -- There must be a let at top level
187 let (CoreSyn.Let (CoreSyn.Rec binds) res) = letexpr
189 -- Create signal declarations for all internal and state signals
190 sig_dec_maybes <- mapM (mkSigDec' . fst) binds
191 let sig_decs = Maybe.catMaybes $ sig_dec_maybes
193 statements <- Monad.mapM mkConcSm binds
194 return $ AST.ArchBody (mkVHDLBasicId "structural") (AST.NSimple entity_id) (map AST.BDISD sig_decs) (statements ++ procs')
196 procs = map mkStateProcSm [] -- (makeStatePairs flatfunc)
197 procs' = map AST.CSPSm procs
198 -- mkSigDec only uses vsTypes from the state
201 -- | Looks up all pairs of old state, new state signals, together with
202 -- the state id they represent.
203 makeStatePairs :: FlatFunction -> [(StateId, SignalInfo, SignalInfo)]
204 makeStatePairs flatfunc =
205 [(Maybe.fromJust $ oldStateId $ sigUse old_info, old_info, new_info)
206 | old_info <- map snd (flat_sigs flatfunc)
207 , new_info <- map snd (flat_sigs flatfunc)
208 -- old_info must be an old state (and, because of the next equality,
209 -- new_info must be a new state).
210 , Maybe.isJust $ oldStateId $ sigUse old_info
211 -- And the state numbers must match
212 , (oldStateId $ sigUse old_info) == (newStateId $ sigUse new_info)]
214 -- Replace the second tuple element with the corresponding SignalInfo
215 --args_states = map (Arrow.second $ signalInfo sigs) args
216 mkStateProcSm :: (StateId, SignalInfo, SignalInfo) -> AST.ProcSm
217 mkStateProcSm (num, old, new) =
218 AST.ProcSm label [clk] [statement]
220 label = mkVHDLExtId $ "state_" ++ (show num)
221 clk = mkVHDLExtId "clk"
222 rising_edge = AST.NSimple $ mkVHDLBasicId "rising_edge"
223 wform = AST.Wform [AST.WformElem (AST.PrimName $ AST.NSimple $ getSignalId new) Nothing]
224 assign = AST.SigAssign (AST.NSimple $ getSignalId old) wform
225 rising_edge_clk = AST.PrimFCall $ AST.FCall rising_edge [Nothing AST.:=>: (AST.ADName $ AST.NSimple clk)]
226 statement = AST.IfSm rising_edge_clk [assign] [] Nothing
228 mkSigDec :: CoreSyn.CoreBndr -> VHDLState (Maybe AST.SigDec)
230 if True then do --isInternalSigUse use || isStateSigUse use then do
231 type_mark <- vhdl_ty $ Var.varType bndr
232 return $ Just (AST.SigDec (bndrToVHDLId bndr) type_mark Nothing)
236 -- | Creates a VHDL Id from a named SignalInfo. Errors out if the SignalInfo
238 getSignalId :: SignalInfo -> AST.VHDLId
240 mkVHDLExtId $ Maybe.fromMaybe
241 (error $ "Unnamed signal? This should not happen!")
244 -- | Transforms a core binding into a VHDL concurrent statement
246 (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- ^ The binding to process
247 -> VHDLState AST.ConcSm -- ^ The corresponding VHDL component instantiation.
249 mkConcSm (bndr, app@(CoreSyn.App _ _))= do
250 signatures <- getA vsSignatures
251 funSignatures <- getA vsNameTable
252 let (CoreSyn.Var f, args) = CoreSyn.collectArgs app
253 case (Map.lookup (bndrToString f) funSignatures) of
256 sigs = map (bndrToString.varBndr) args
257 sigsNames = map (\signal -> (AST.PrimName (AST.NSimple (mkVHDLExtId signal)))) sigs
258 func = (snd funSignature) sigsNames
259 src_wform = AST.Wform [AST.WformElem func Nothing]
260 dst_name = AST.NSimple (mkVHDLExtId (bndrToString bndr))
261 assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
263 return $ AST.CSSASm assign
266 signature = Maybe.fromMaybe
267 (error $ "Using function '" ++ (bndrToString f) ++ "' without signature? This should not happen!")
268 (Map.lookup (bndrToString f) signatures)
269 entity_id = ent_id signature
270 label = bndrToString bndr
271 -- Add a clk port if we have state
272 --clk_port = Maybe.fromJust $ mkAssocElem (Just $ mkVHDLExtId "clk") "clk"
273 --portmaps = mkAssocElems sigs args res signature ++ (if hasState hsfunc then [clk_port] else [])
274 portmaps = mkAssocElems args bndr signature
276 return $ AST.CSISm $ AST.CompInsSm (mkVHDLExtId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps)
278 -- GHC generates some funny "r = r" bindings in let statements before
279 -- simplification. This outputs some dummy ConcSM for these, so things will at
280 -- least compile for now.
281 mkConcSm (bndr, CoreSyn.Var _) = return $ AST.CSPSm $ AST.ProcSm (mkVHDLBasicId "unused") [] []
283 -- A single alt case must be a selector
284 mkConcSm (bndr, (Case (Var scrut) b ty [alt])) = error "Single case alt not supported yet"
286 -- Multiple case alt are be conditional assignments and have only wild
287 -- binders in the alts and only variables in the case values and a variable
288 -- for a scrutinee. We check the constructor of the second alt, since the
289 -- first is the default case, if there is any.
290 mkConcSm (bndr, (Case (Var scrut) b ty [(_, _, Var false), (con, _, Var true)])) =
292 cond_expr = (varToVHDLExpr scrut) AST.:=: (conToVHDLExpr con)
293 true_expr = (varToVHDLExpr true)
294 false_expr = (varToVHDLExpr false)
295 false_wform = AST.Wform [AST.WformElem false_expr Nothing]
296 true_wform = AST.Wform [AST.WformElem true_expr Nothing]
297 whenelse = AST.WhenElse true_wform cond_expr
298 dst_name = AST.NSimple (bndrToVHDLId bndr)
299 assign = dst_name AST.:<==: (AST.ConWforms [whenelse] false_wform Nothing)
301 return $ AST.CSSASm assign
302 mkConcSm (_, (Case (Var _) _ _ alts)) = error "VHDL.mkConcSm Not in normal form: Case statement with more than two alternatives"
303 mkConcSm (_, Case _ _ _ _) = error "VHDL.mkConcSm Not in normal form: Case statement has does not have a simple variable as scrutinee"
305 -- Turn a variable reference into a AST expression
306 varToVHDLExpr :: Var.Var -> AST.Expr
307 varToVHDLExpr var = AST.PrimName $ AST.NSimple $ bndrToVHDLId var
309 -- Turn a constructor into an AST expression. For dataconstructors, this is
310 -- only the constructor itself, not any arguments it has. Should not be called
311 -- with a DEFAULT constructor.
312 conToVHDLExpr :: CoreSyn.AltCon -> AST.Expr
313 conToVHDLExpr (DataAlt dc) = AST.PrimLit lit
315 tycon = DataCon.dataConTyCon dc
316 tyname = TyCon.tyConName tycon
317 dcname = DataCon.dataConName dc
318 lit = case Name.getOccString tyname of
319 -- TODO: Do something more robust than string matching
320 "Bit" -> case Name.getOccString dcname of "High" -> "'1'"; "Low" -> "'0'"
321 "Bool" -> case Name.getOccString dcname of "True" -> "true"; "False" -> "false"
322 conToVHDLExpr (LitAlt _) = error "VHDL.conToVHDLExpr Literals not support in case alternatives yet"
323 conToVHDLExpr DEFAULT = error "VHDL.conToVHDLExpr DEFAULT alternative should not occur here!"
328 mkConcSm sigs (UncondDef src dst) _ = do
329 src_expr <- vhdl_expr src
330 let src_wform = AST.Wform [AST.WformElem src_expr Nothing]
331 let dst_name = AST.NSimple (getSignalId $ signalInfo sigs dst)
332 let assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
333 return $ AST.CSSASm assign
335 vhdl_expr (Left id) = return $ mkIdExpr sigs id
336 vhdl_expr (Right expr) =
339 return $ (mkIdExpr sigs id) AST.:=: (AST.PrimLit lit)
340 (Literal lit Nothing) ->
341 return $ AST.PrimLit lit
342 (Literal lit (Just ty)) -> do
343 -- Create a cast expression, which is just a function call using the
344 -- type name as the function name.
345 let litexpr = AST.PrimLit lit
347 let ty_name = AST.NSimple ty_id
348 let args = [Nothing AST.:=>: (AST.ADExpr litexpr)]
349 return $ AST.PrimFCall $ AST.FCall ty_name args
351 return $ (mkIdExpr sigs a) AST.:=: (mkIdExpr sigs b)
353 mkConcSm sigs (CondDef cond true false dst) _ =
355 cond_expr = mkIdExpr sigs cond
356 true_expr = mkIdExpr sigs true
357 false_expr = mkIdExpr sigs false
358 false_wform = AST.Wform [AST.WformElem false_expr Nothing]
359 true_wform = AST.Wform [AST.WformElem true_expr Nothing]
360 whenelse = AST.WhenElse true_wform cond_expr
361 dst_name = AST.NSimple (getSignalId $ signalInfo sigs dst)
362 assign = dst_name AST.:<==: (AST.ConWforms [whenelse] false_wform Nothing)
364 return $ AST.CSSASm assign
366 -- | Turn a SignalId into a VHDL Expr
367 mkIdExpr :: [(SignalId, SignalInfo)] -> SignalId -> AST.Expr
369 let src_name = AST.NSimple (getSignalId $ signalInfo sigs id) in
370 AST.PrimName src_name
373 [CoreSyn.CoreExpr] -- | The argument that are applied to function
374 -> CoreSyn.CoreBndr -- | The binder in which to store the result
375 -> Entity -- | The entity to map against.
376 -> [AST.AssocElem] -- | The resulting port maps
378 mkAssocElems args res entity =
379 -- Create the actual AssocElems
380 Maybe.catMaybes $ zipWith mkAssocElem ports sigs
382 -- Turn the ports and signals from a map into a flat list. This works,
383 -- since the maps must have an identical form by definition. TODO: Check
385 arg_ports = ent_args entity
386 res_port = ent_res entity
387 -- Extract the id part from the (id, type) tuple
388 ports = map (Monad.liftM fst) (res_port : arg_ports)
389 -- Translate signal numbers into names
390 sigs = (bndrToString res : map (bndrToString.varBndr) args)
392 -- Turns a Var CoreExpr into the Id inside it. Will of course only work for
393 -- simple Var CoreExprs, not complexer ones.
394 varBndr :: CoreSyn.CoreExpr -> Var.Id
395 varBndr (CoreSyn.Var id) = id
397 -- | Look up a signal in the signal name map
398 lookupSigName :: [(SignalId, SignalInfo)] -> SignalId -> String
399 lookupSigName sigs sig = name
401 info = Maybe.fromMaybe
402 (error $ "Unknown signal " ++ (show sig) ++ " used? This should not happen!")
404 name = Maybe.fromMaybe
405 (error $ "Unnamed signal " ++ (show sig) ++ " used? This should not happen!")
408 -- | Create an VHDL port -> signal association
409 mkAssocElem :: Maybe AST.VHDLId -> String -> Maybe AST.AssocElem
410 mkAssocElem (Just port) signal = Just $ Just port AST.:=>: (AST.ADName (AST.NSimple (mkVHDLExtId signal)))
411 mkAssocElem Nothing _ = Nothing
413 -- | The VHDL Bit type
414 bit_ty :: AST.TypeMark
415 bit_ty = AST.unsafeVHDLBasicId "Bit"
417 -- | The VHDL Boolean type
418 bool_ty :: AST.TypeMark
419 bool_ty = AST.unsafeVHDLBasicId "Boolean"
421 -- | The VHDL std_logic
422 std_logic_ty :: AST.TypeMark
423 std_logic_ty = AST.unsafeVHDLBasicId "std_logic"
425 -- Translate a Haskell type to a VHDL type
426 vhdl_ty :: Type.Type -> VHDLState AST.TypeMark
428 typemap <- getA vsTypes
429 let builtin_ty = do -- See if this is a tycon and lookup its name
430 (tycon, args) <- Type.splitTyConApp_maybe ty
431 let name = Name.getOccString (TyCon.tyConName tycon)
432 Map.lookup name builtin_types
433 -- If not a builtin type, try the custom types
434 let existing_ty = (fmap fst) $ Map.lookup (OrdType ty) typemap
435 case Monoid.getFirst $ Monoid.mconcat (map Monoid.First [builtin_ty, existing_ty]) of
436 -- Found a type, return it
438 -- No type yet, try to construct it
440 newty_maybe <- (construct_vhdl_ty ty)
442 Just (ty_id, ty_def) -> do
443 -- TODO: Check name uniqueness
444 modA vsTypes (Map.insert (OrdType ty) (ty_id, ty_def))
446 Nothing -> error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty)
448 -- Construct a new VHDL type for the given Haskell type.
449 construct_vhdl_ty :: Type.Type -> VHDLState (Maybe (AST.TypeMark, AST.TypeDef))
450 construct_vhdl_ty ty = do
451 case Type.splitTyConApp_maybe ty of
452 Just (tycon, args) -> do
453 let name = Name.getOccString (TyCon.tyConName tycon)
456 res <- mk_vector_ty (tfvec_len ty) ty
459 res <- mk_vector_ty (sized_word_len ty) ty
461 -- Create a custom type from this tycon
462 otherwise -> mk_tycon_ty tycon args
463 Nothing -> return $ Nothing
465 -- | Create VHDL type for a custom tycon
466 mk_tycon_ty :: TyCon.TyCon -> [Type.Type] -> VHDLState (Maybe (AST.TypeMark, AST.TypeDef))
467 mk_tycon_ty tycon args =
468 case TyCon.tyConDataCons tycon of
469 -- Not an algebraic type
470 [] -> error $ "Only custom algebraic types are supported: " ++ (showSDoc $ ppr tycon)
472 let arg_tys = DataCon.dataConRepArgTys dc
473 -- TODO: CoreSubst docs say each Subs can be applied only once. Is this a
474 -- violation? Or does it only mean not to apply it again to the same
476 let real_arg_tys = map (CoreSubst.substTy subst) arg_tys
477 elem_tys <- mapM vhdl_ty real_arg_tys
478 let elems = zipWith AST.ElementDec recordlabels elem_tys
479 -- For a single construct datatype, build a record with one field for
481 -- TODO: Add argument type ids to this, to ensure uniqueness
482 -- TODO: Special handling for tuples?
483 let ty_id = mkVHDLExtId $ nameToString (TyCon.tyConName tycon)
484 let ty_def = AST.TDR $ AST.RecordTypeDef elems
485 return $ Just (ty_id, ty_def)
486 dcs -> error $ "Only single constructor datatypes supported: " ++ (showSDoc $ ppr tycon)
488 -- Create a subst that instantiates all types passed to the tycon
489 -- TODO: I'm not 100% sure that this is the right way to do this. It seems
490 -- to work so far, though..
491 tyvars = TyCon.tyConTyVars tycon
492 subst = CoreSubst.extendTvSubstList CoreSubst.emptySubst (zip tyvars args)
494 -- | Create a VHDL vector type
496 Int -- ^ The length of the vector
497 -> Type.Type -- ^ The Haskell type to create a VHDL type for
498 -> VHDLState (AST.TypeMark, AST.TypeDef) -- The typemark created.
500 mk_vector_ty len ty = do
501 -- Assume there is a single type argument
502 let ty_id = mkVHDLExtId $ "vector_" ++ (show len)
504 let range = AST.IndexConstraint [AST.ToRange (AST.PrimLit "0") (AST.PrimLit $ show (len - 1))]
505 let ty_def = AST.TDA $ AST.ConsArrayDef range std_logic_ty
506 modA vsTypeFuns (Map.insert (OrdType ty) (genUnconsVectorFuns std_logic_ty ty_id))
507 return (ty_id, ty_def)
512 ("Bit", std_logic_ty),
513 ("Bool", bool_ty) -- TysWiredIn.boolTy
517 -- Can only contain alphanumerics and underscores. The supplied string must be
518 -- a valid basic id, otherwise an error value is returned. This function is
519 -- not meant to be passed identifiers from a source file, use mkVHDLExtId for
521 mkVHDLBasicId :: String -> AST.VHDLId
523 AST.unsafeVHDLBasicId $ (strip_multiscore . strip_leading . strip_invalid) s
525 -- Strip invalid characters.
526 strip_invalid = filter (`elem` ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_.")
527 -- Strip leading numbers and underscores
528 strip_leading = dropWhile (`elem` ['0'..'9'] ++ "_")
529 -- Strip multiple adjacent underscores
530 strip_multiscore = concat . map (\cs ->
536 -- Shortcut for Extended VHDL Id's. These Id's can contain a lot more
537 -- different characters than basic ids, but can never be used to refer to
539 -- Use extended Ids for any values that are taken from the source file.
540 mkVHDLExtId :: String -> AST.VHDLId
542 AST.unsafeVHDLExtId $ strip_invalid s
544 -- Allowed characters, taken from ForSyde's mkVHDLExtId
545 allowed = ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ " \"#&\\'()*+,./:;<=>_|!$%@?[]^`{}~-"
546 strip_invalid = filter (`elem` allowed)
548 -- Creates a VHDL Id from a binder
553 bndrToVHDLId = mkVHDLExtId . OccName.occNameString . Name.nameOccName . Var.varName
555 -- Extracts the binder name as a String
560 bndrToString = OccName.occNameString . Name.nameOccName . Var.varName
562 -- Extracts the string version of the name
563 nameToString :: Name.Name -> String
564 nameToString = OccName.occNameString . Name.nameOccName
566 -- | A consise representation of a (set of) ports on a builtin function
567 --type PortMap = HsValueMap (String, AST.TypeMark)
568 -- | A consise representation of a builtin function
569 data BuiltIn = BuiltIn String [(String, AST.TypeMark)] (String, AST.TypeMark)
571 -- | Translate a list of concise representation of builtin functions to a
573 mkBuiltins :: [BuiltIn] -> SignatureMap
574 mkBuiltins = Map.fromList . map (\(BuiltIn name args res) ->
576 Entity (VHDL.mkVHDLBasicId name) (map toVHDLSignalMapElement args) (toVHDLSignalMapElement res))
579 builtin_hsfuncs = Map.keys builtin_funcs
580 builtin_funcs = mkBuiltins
582 BuiltIn "hwxor" [("a", VHDL.bit_ty), ("b", VHDL.bit_ty)] ("o", VHDL.bit_ty),
583 BuiltIn "hwand" [("a", VHDL.bit_ty), ("b", VHDL.bit_ty)] ("o", VHDL.bit_ty),
584 BuiltIn "hwor" [("a", VHDL.bit_ty), ("b", VHDL.bit_ty)] ("o", VHDL.bit_ty),
585 BuiltIn "hwnot" [("a", VHDL.bit_ty)] ("o", VHDL.bit_ty)
588 recordlabels = map (\c -> mkVHDLBasicId [c]) ['A'..'Z']
590 -- | Map a port specification of a builtin function to a VHDL Signal to put in
592 toVHDLSignalMapElement :: (String, AST.TypeMark) -> VHDLSignalMapElement
593 toVHDLSignalMapElement (name, ty) = Just (mkVHDLBasicId name, ty)