X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=VHDL.hs;h=2ac2a12aaffb0a74d6303053f97d871eabdd7775;hb=46f93616d6a7ef012c5f07698d56372881196015;hp=c1b42b3bc89a9b2764ff60626957a036b9242649;hpb=38ac166769b7280fcb9e63f6fda3955d9b58ce11;p=matthijs%2Fmaster-project%2Fc%CE%BBash.git diff --git a/VHDL.hs b/VHDL.hs index c1b42b3..2ac2a12 100644 --- a/VHDL.hs +++ b/VHDL.hs @@ -3,62 +3,91 @@ -- module VHDL where -import qualified Data.Foldable as Foldable +-- Standard modules import qualified Data.List as List import qualified Data.Map as Map import qualified Maybe import qualified Control.Monad as Monad import qualified Control.Arrow as Arrow import qualified Control.Monad.Trans.State as State -import qualified Data.Traversable as Traversable import qualified Data.Monoid as Monoid import Data.Accessor -import qualified Data.Accessor.MonadState as MonadState +import Data.Accessor.MonadState as MonadState +import Debug.Trace -import qualified Type -import qualified TysWiredIn +-- ForSyDe +import qualified ForSyDe.Backend.VHDL.AST as AST + +-- GHC API +import CoreSyn +--import qualified Type import qualified Name +import qualified Var +import qualified Id +import qualified IdInfo import qualified TyCon +import qualified DataCon +--import qualified CoreSubst +import qualified CoreUtils import Outputable ( showSDoc, ppr ) -import qualified ForSyDe.Backend.VHDL.AST as AST - +-- Local imports import VHDLTypes -import Flatten -import FlattenTypes -import TranslatorTypes -import HsValueMap +import VHDLTools import Pretty +import CoreTools +import Constants +import Generate createDesignFiles :: - FlatFuncMap + TypeState + -> [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)] -> [(AST.VHDLId, AST.DesignFile)] -createDesignFiles flatfuncmap = - -- TODO: Output types - (mkVHDLId "types", AST.DesignFile [] [type_package]) : - map (Arrow.second $ AST.DesignFile context) units +createDesignFiles init_typestate binds = + (mkVHDLBasicId "types", AST.DesignFile ieee_context [type_package_dec, type_package_body]) : + map (Arrow.second $ AST.DesignFile full_context) units where - init_session = VHDLSession Map.empty builtin_funcs + init_session = VHDLState init_typestate Map.empty (units, final_session) = - State.runState (createLibraryUnits flatfuncmap) init_session - ty_decls = Map.elems (final_session ^. vsTypes) - context = [ - AST.Library $ mkVHDLId "IEEE", - AST.Use $ (AST.NSimple $ mkVHDLId "IEEE.std_logic_1164") AST.:.: AST.All, - AST.Use $ (AST.NSimple $ mkVHDLId "work.types") AST.:.: AST.All] - type_package = AST.LUPackageDec $ AST.PackageDec (mkVHDLId "types") (map (AST.PDITD . snd) ty_decls) - + State.runState (createLibraryUnits binds) init_session + tyfun_decls = map snd $ Map.elems (final_session ^. vsType ^. vsTypeFuns) + ty_decls = final_session ^. vsType ^. vsTypeDecls + tfvec_index_decl = AST.PDISD $ AST.SubtypeDec tfvec_indexTM tfvec_index_def + tfvec_range = AST.ConstraintRange $ AST.SubTypeRange (AST.PrimLit "-1") (AST.PrimName $ AST.NAttribute $ AST.AttribName (AST.NSimple integerTM) highId Nothing) + tfvec_index_def = AST.SubtypeIn integerTM (Just tfvec_range) + ieee_context = [ + AST.Library $ mkVHDLBasicId "IEEE", + mkUseAll ["IEEE", "std_logic_1164"], + mkUseAll ["IEEE", "numeric_std"] + ] + full_context = + mkUseAll ["work", "types"] + : (mkUseAll ["work"] + : ieee_context) + type_package_dec = AST.LUPackageDec $ AST.PackageDec (mkVHDLBasicId "types") ([tfvec_index_decl] ++ ty_decls ++ subProgSpecs) + type_package_body = AST.LUPackageBody $ AST.PackageBody typesId tyfun_decls + subProgSpecs = map subProgSpec tyfun_decls + subProgSpec = \(AST.SubProgBody spec _ _) -> AST.PDISS spec + +-- Create a use foo.bar.all statement. Takes a list of components in the used +-- name. Must contain at least two components +mkUseAll :: [String] -> AST.ContextItem +mkUseAll ss = + AST.Use $ from AST.:.: AST.All + where + base_prefix = (AST.NSimple $ mkVHDLBasicId $ head ss) + from = foldl select base_prefix (tail ss) + select prefix s = AST.NSelected $ prefix AST.:.: (AST.SSimple $ mkVHDLBasicId s) + createLibraryUnits :: - FlatFuncMap - -> VHDLState [(AST.VHDLId, [AST.LibraryUnit])] + [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)] + -> VHDLSession [(AST.VHDLId, [AST.LibraryUnit])] -createLibraryUnits flatfuncmap = do - let hsfuncs = Map.keys flatfuncmap - let flatfuncs = Map.elems flatfuncmap - entities <- Monad.zipWithM createEntity hsfuncs flatfuncs - archs <- Monad.zipWithM createArchitecture hsfuncs flatfuncs +createLibraryUnits binds = do + entities <- Monad.mapM createEntity binds + archs <- Monad.mapM createArchitecture binds return $ zipWith (\ent arch -> let AST.EntityDec id _ = ent in @@ -68,113 +97,108 @@ createLibraryUnits flatfuncmap = do -- | Create an entity for a given function createEntity :: - HsFunction -- | The function signature - -> FlatFunction -- | The FlatFunction - -> VHDLState AST.EntityDec -- | The resulting entity - -createEntity hsfunc flatfunc = do - let sigs = flat_sigs flatfunc - let args = flat_args flatfunc - let res = flat_res flatfunc - args' <- Traversable.traverse (Traversable.traverse (mkMap sigs)) args - res' <- Traversable.traverse (mkMap sigs) res - let ent_decl' = createEntityAST hsfunc args' res' + (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- | The function + -> VHDLSession AST.EntityDec -- | The resulting entity + +createEntity (fname, expr) = do + -- Strip off lambda's, these will be arguments + let (args, letexpr) = CoreSyn.collectBinders expr + args' <- Monad.mapM mkMap args + -- There must be a let at top level + let (CoreSyn.Let binds (CoreSyn.Var res)) = letexpr + res' <- mkMap res + let vhdl_id = mkVHDLBasicId $ varToString fname ++ "_" ++ varToStringUniq fname + let ent_decl' = createEntityAST vhdl_id args' res' let AST.EntityDec entity_id _ = ent_decl' let signature = Entity entity_id args' res' - modA vsSignatures (Map.insert hsfunc signature) + modA vsSignatures (Map.insert fname signature) return ent_decl' where - mkMap :: - [(SignalId, SignalInfo)] - -> SignalId - -> VHDLState VHDLSignalMapElement + mkMap :: + --[(SignalId, SignalInfo)] + CoreSyn.CoreBndr + -> VHDLSession Port -- We only need the vsTypes element from the state - mkMap sigmap = MonadState.lift vsTypes . (\id -> + mkMap = (\bndr -> let - info = Maybe.fromMaybe - (error $ "Signal not found in the name map? This should not happen!") - (lookup id sigmap) - nm = Maybe.fromMaybe - (error $ "Signal not named? This should not happen!") - (sigName info) - ty = sigTy info - in - if isPortSigUse $ sigUse info - then do - type_mark <- vhdl_ty ty - return $ Just (mkVHDLId nm, type_mark) - else - return $ Nothing - ) + --info = Maybe.fromMaybe + -- (error $ "Signal not found in the name map? This should not happen!") + -- (lookup id sigmap) + -- Assume the bndr has a valid VHDL id already + id = varToVHDLId bndr + ty = Var.varType bndr + error_msg = "\nVHDL.createEntity.mkMap: Can not create entity: " ++ pprString fname ++ "\nbecause no type can be created for port: " ++ pprString bndr + in do + type_mark <- MonadState.lift vsType $ vhdl_ty error_msg ty + return (id, type_mark) + ) -- | Create the VHDL AST for an entity createEntityAST :: - HsFunction -- | The signature of the function we're working with - -> [VHDLSignalMap] -- | The entity's arguments - -> VHDLSignalMap -- | The entity's result - -> AST.EntityDec -- | The entity with the ent_decl filled in as well + AST.VHDLId -- | The name of the function + -> [Port] -- | The entity's arguments + -> Port -- | The entity's result + -> AST.EntityDec -- | The entity with the ent_decl filled in as well -createEntityAST hsfunc args res = +createEntityAST vhdl_id args res = AST.EntityDec vhdl_id ports where - vhdl_id = mkEntityId hsfunc - ports = concatMap (mapToPorts AST.In) args - ++ mapToPorts AST.Out res - ++ clk_port - mapToPorts :: AST.Mode -> VHDLSignalMap -> [AST.IfaceSigDec] - mapToPorts mode m = - Maybe.catMaybes $ map (mkIfaceSigDec mode) (Foldable.toList m) + -- Create a basic Id, since VHDL doesn't grok filenames with extended Ids. + ports = map (mkIfaceSigDec AST.In) args + ++ [mkIfaceSigDec AST.Out res] + ++ [clk_port] -- Add a clk port if we have state - clk_port = if hasState hsfunc - then - [AST.IfaceSigDec (mkVHDLId "clk") AST.In VHDL.std_logic_ty] - else - [] + clk_port = AST.IfaceSigDec (mkVHDLExtId "clk") AST.In std_logicTM -- | Create a port declaration mkIfaceSigDec :: AST.Mode -- | The mode for the port (In / Out) - -> Maybe (AST.VHDLId, AST.TypeMark) -- | The id and type for the port - -> Maybe AST.IfaceSigDec -- | The resulting port declaration + -> (AST.VHDLId, AST.TypeMark) -- | The id and type for the port + -> AST.IfaceSigDec -- | The resulting port declaration -mkIfaceSigDec mode (Just (id, ty)) = Just $ AST.IfaceSigDec id mode ty -mkIfaceSigDec _ Nothing = Nothing +mkIfaceSigDec mode (id, ty) = AST.IfaceSigDec id mode ty +{- -- | Generate a VHDL entity name for the given hsfunc mkEntityId hsfunc = -- TODO: This doesn't work for functions with multiple signatures! - mkVHDLId $ hsFuncName hsfunc + -- Use a Basic Id, since using extended id's for entities throws off + -- precision and causes problems when generating filenames. + mkVHDLBasicId $ hsFuncName hsfunc +-} -- | Create an architecture for a given function createArchitecture :: - HsFunction -- ^ The function signature - -> FlatFunction -- ^ The FlatFunction - -> VHDLState AST.ArchBody -- ^ The architecture for this function + (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- ^ The function + -> VHDLSession AST.ArchBody -- ^ The architecture for this function -createArchitecture hsfunc flatfunc = do +createArchitecture (fname, expr) = do signaturemap <- getA vsSignatures let signature = Maybe.fromMaybe - (error $ "Generating architecture for function " ++ (prettyShow hsfunc) ++ "without signature? This should not happen!") - (Map.lookup hsfunc signaturemap) + (error $ "\nVHDL.createArchitecture: Generating architecture for function \n" ++ (pprString fname) ++ "\nwithout signature? This should not happen!") + (Map.lookup fname signaturemap) let entity_id = ent_id signature - -- Create signal declarations for all internal and state signals - sig_dec_maybes <- mapM (mkSigDec' . snd) sigs + -- Strip off lambda's, these will be arguments + let (args, letexpr) = CoreSyn.collectBinders expr + -- There must be a let at top level + let (CoreSyn.Let (CoreSyn.Rec binds) (Var res)) = letexpr + + -- Create signal declarations for all binders in the let expression, except + -- for the output port (that will already have an output port declared in + -- the entity). + sig_dec_maybes <- mapM (mkSigDec' . fst) (filter ((/=res).fst) binds) let sig_decs = Maybe.catMaybes $ sig_dec_maybes - -- Create concurrent statements for all signal definitions - let statements = zipWith (mkConcSm signaturemap sigs) defs [0..] - return $ AST.ArchBody (mkVHDLId "structural") (AST.NSimple entity_id) (map AST.BDISD sig_decs) (statements ++ procs') + + statementss <- Monad.mapM mkConcSm binds + let statements = concat statementss + return $ AST.ArchBody (mkVHDLBasicId "structural") (AST.NSimple entity_id) (map AST.BDISD sig_decs) (statements ++ procs') where - sigs = flat_sigs flatfunc - args = flat_args flatfunc - res = flat_res flatfunc - defs = flat_defs flatfunc - -- TODO: Unique ty_decls - -- TODO: Store ty_decls somewhere - procs = map mkStateProcSm (makeStatePairs flatfunc) + procs = [] --map mkStateProcSm [] -- (makeStatePairs flatfunc) procs' = map AST.CSPSm procs -- mkSigDec only uses vsTypes from the state - mkSigDec' = MonadState.lift vsTypes . mkSigDec + mkSigDec' = mkSigDec +{- -- | Looks up all pairs of old state, new state signals, together with -- the state id they represent. makeStatePairs :: FlatFunction -> [(StateId, SignalInfo, SignalInfo)] @@ -194,233 +218,82 @@ mkStateProcSm :: (StateId, SignalInfo, SignalInfo) -> AST.ProcSm mkStateProcSm (num, old, new) = AST.ProcSm label [clk] [statement] where - label = mkVHDLId $ "state_" ++ (show num) - clk = mkVHDLId "clk" - rising_edge = AST.NSimple $ mkVHDLId "rising_edge" + label = mkVHDLExtId $ "state_" ++ (show num) + clk = mkVHDLExtId "clk" + rising_edge = AST.NSimple $ mkVHDLBasicId "rising_edge" wform = AST.Wform [AST.WformElem (AST.PrimName $ AST.NSimple $ getSignalId new) Nothing] assign = AST.SigAssign (AST.NSimple $ getSignalId old) wform rising_edge_clk = AST.PrimFCall $ AST.FCall rising_edge [Nothing AST.:=>: (AST.ADName $ AST.NSimple clk)] statement = AST.IfSm rising_edge_clk [assign] [] Nothing -mkSigDec :: SignalInfo -> TypeState (Maybe AST.SigDec) -mkSigDec info = - let use = sigUse info in - if isInternalSigUse use || isStateSigUse use then do - type_mark <- vhdl_ty ty - return $ Just (AST.SigDec (getSignalId info) type_mark Nothing) - else - return Nothing - where - ty = sigTy info - -- | Creates a VHDL Id from a named SignalInfo. Errors out if the SignalInfo -- is not named. getSignalId :: SignalInfo -> AST.VHDLId getSignalId info = - mkVHDLId $ Maybe.fromMaybe - (error $ "Unnamed signal? This should not happen!") - (sigName info) + mkVHDLExtId $ Maybe.fromMaybe + (error $ "Unnamed signal? This should not happen!") + (sigName info) +-} + +mkSigDec :: CoreSyn.CoreBndr -> VHDLSession (Maybe AST.SigDec) +mkSigDec bndr = + if True then do --isInternalSigUse use || isStateSigUse use then do + let error_msg = "\nVHDL.mkSigDec: Can not make signal declaration for type: \n" ++ pprString bndr + type_mark <- MonadState.lift vsType $ vhdl_ty error_msg (Var.varType bndr) + return $ Just (AST.SigDec (varToVHDLId bndr) type_mark Nothing) + else + return Nothing --- | Transforms a signal definition into a VHDL concurrent statement +-- | Transforms a core binding into a VHDL concurrent statement mkConcSm :: - SignatureMap -- ^ The interfaces of functions in the session - -> [(SignalId, SignalInfo)] -- ^ The signals in the current architecture - -> SigDef -- ^ The signal definition - -> Int -- ^ A number that will be unique for all - -- concurrent statements in the architecture. - -> AST.ConcSm -- ^ The corresponding VHDL component instantiation. - -mkConcSm signatures sigs (FApp hsfunc args res) num = - let - signature = Maybe.fromMaybe - (error $ "Using function '" ++ (prettyShow hsfunc) ++ "' without signature? This should not happen!") - (Map.lookup hsfunc signatures) - entity_id = ent_id signature - label = (AST.fromVHDLId entity_id) ++ "_" ++ (show num) - -- Add a clk port if we have state - clk_port = Maybe.fromJust $ mkAssocElem (Just $ mkVHDLId "clk") "clk" - portmaps = mkAssocElems sigs args res signature ++ (if hasState hsfunc then [clk_port] else []) - in - AST.CSISm $ AST.CompInsSm (mkVHDLId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps) - -mkConcSm _ sigs (UncondDef src dst) _ = - let - src_expr = vhdl_expr src - src_wform = AST.Wform [AST.WformElem src_expr Nothing] - dst_name = AST.NSimple (getSignalId $ signalInfo sigs dst) - assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing) - in - AST.CSSASm assign - where - vhdl_expr (Left id) = mkIdExpr sigs id - vhdl_expr (Right expr) = - case expr of - (EqLit id lit) -> - (mkIdExpr sigs id) AST.:=: (AST.PrimLit lit) - (Literal lit) -> - AST.PrimLit lit - (Eq a b) -> - (mkIdExpr sigs a) AST.:=: (mkIdExpr sigs b) - -mkConcSm _ sigs (CondDef cond true false dst) _ = - let - cond_expr = mkIdExpr sigs cond - true_expr = mkIdExpr sigs true - false_expr = mkIdExpr sigs false - false_wform = AST.Wform [AST.WformElem false_expr Nothing] - true_wform = AST.Wform [AST.WformElem true_expr Nothing] - whenelse = AST.WhenElse true_wform cond_expr - dst_name = AST.NSimple (getSignalId $ signalInfo sigs dst) - assign = dst_name AST.:<==: (AST.ConWforms [whenelse] false_wform Nothing) - in - AST.CSSASm assign - --- | Turn a SignalId into a VHDL Expr -mkIdExpr :: [(SignalId, SignalInfo)] -> SignalId -> AST.Expr -mkIdExpr sigs id = - let src_name = AST.NSimple (getSignalId $ signalInfo sigs id) in - AST.PrimName src_name - -mkAssocElems :: - [(SignalId, SignalInfo)] -- | The signals in the current architecture - -> [SignalMap] -- | The signals that are applied to function - -> SignalMap -- | the signals in which to store the function result - -> Entity -- | The entity to map against. - -> [AST.AssocElem] -- | The resulting port maps - -mkAssocElems sigmap args res entity = - -- Create the actual AssocElems - Maybe.catMaybes $ zipWith mkAssocElem ports sigs - where - -- Turn the ports and signals from a map into a flat list. This works, - -- since the maps must have an identical form by definition. TODO: Check - -- the similar form? - arg_ports = concat (map Foldable.toList (ent_args entity)) - res_ports = Foldable.toList (ent_res entity) - arg_sigs = (concat (map Foldable.toList args)) - res_sigs = Foldable.toList res - -- Extract the id part from the (id, type) tuple - ports = (map (fmap fst) (arg_ports ++ res_ports)) - -- Translate signal numbers into names - sigs = (map (lookupSigName sigmap) (arg_sigs ++ res_sigs)) - --- | Look up a signal in the signal name map -lookupSigName :: [(SignalId, SignalInfo)] -> SignalId -> String -lookupSigName sigs sig = name - where - info = Maybe.fromMaybe - (error $ "Unknown signal " ++ (show sig) ++ " used? This should not happen!") - (lookup sig sigs) - name = Maybe.fromMaybe - (error $ "Unnamed signal " ++ (show sig) ++ " used? This should not happen!") - (sigName info) - --- | Create an VHDL port -> signal association -mkAssocElem :: Maybe AST.VHDLId -> String -> Maybe AST.AssocElem -mkAssocElem (Just port) signal = Just $ Just port AST.:=>: (AST.ADName (AST.NSimple (mkVHDLId signal))) -mkAssocElem Nothing _ = Nothing - --- | The VHDL Bit type -bit_ty :: AST.TypeMark -bit_ty = AST.unsafeVHDLBasicId "Bit" - --- | The VHDL Boolean type -bool_ty :: AST.TypeMark -bool_ty = AST.unsafeVHDLBasicId "Boolean" - --- | The VHDL std_logic -std_logic_ty :: AST.TypeMark -std_logic_ty = AST.unsafeVHDLBasicId "std_logic" - --- Translate a Haskell type to a VHDL type -vhdl_ty :: Type.Type -> TypeState AST.TypeMark -vhdl_ty ty = do - typemap <- State.get - let builtin_ty = do -- See if this is a tycon and lookup its name - (tycon, args) <- Type.splitTyConApp_maybe ty - let name = Name.getOccString (TyCon.tyConName tycon) - Map.lookup name builtin_types - -- If not a builtin type, try the custom types - let existing_ty = (fmap fst) $ Map.lookup (OrdType ty) typemap - case Monoid.getFirst $ Monoid.mconcat (map Monoid.First [builtin_ty, existing_ty]) of - -- Found a type, return it - Just t -> return t - -- No type yet, try to construct it - Nothing -> do - let new_ty = do - -- Use the Maybe Monad for failing when one of these fails - (tycon, args) <- Type.splitTyConApp_maybe ty - let name = Name.getOccString (TyCon.tyConName tycon) - case name of - "FSVec" -> Just $ mk_fsvec_ty ty args - otherwise -> Nothing - -- Return new_ty when a new type was successfully created - Maybe.fromMaybe - (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty)) - new_ty - --- | Create a VHDL type belonging to a FSVec Haskell type -mk_fsvec_ty :: - Type.Type -- ^ The Haskell type to create a VHDL type for - -> [Type.Type] -- ^ Type arguments to the FSVec type constructor - -> TypeState AST.TypeMark -- The typemark created. - -mk_fsvec_ty ty args = do - -- Assume there are two type arguments - let [len, el_ty] = args - -- TODO: Find actual number - let ty_id = mkVHDLId ("vector_" ++ (show len)) - -- TODO: Use el_ty - let range = AST.IndexConstraint [AST.ToRange (AST.PrimLit "0") (AST.PrimLit "16")] - let ty_def = AST.TDA $ AST.ConsArrayDef range std_logic_ty - let ty_dec = AST.TypeDec ty_id ty_def - State.modify (Map.insert (OrdType ty) (ty_id, ty_dec)) - return ty_id - - -builtin_types = - Map.fromList [ - ("Bit", std_logic_ty), - ("Bool", bool_ty) -- TysWiredIn.boolTy - ] - --- Shortcut -mkVHDLId :: String -> AST.VHDLId -mkVHDLId s = - AST.unsafeVHDLBasicId $ (strip_multiscore . strip_invalid) s - where - -- Strip invalid characters. - strip_invalid = filter (`elem` ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_.") - -- Strip multiple adjacent underscores - strip_multiscore = concat . map (\cs -> - case cs of - ('_':_) -> "_" - _ -> cs - ) . List.group - --- | A consise representation of a (set of) ports on a builtin function -type PortMap = HsValueMap (String, AST.TypeMark) --- | A consise representation of a builtin function -data BuiltIn = BuiltIn String [PortMap] PortMap - --- | Translate a list of concise representation of builtin functions to a --- SignatureMap -mkBuiltins :: [BuiltIn] -> SignatureMap -mkBuiltins = Map.fromList . map (\(BuiltIn name args res) -> - (HsFunction name (map useAsPort args) (useAsPort res), - Entity (VHDL.mkVHDLId name) (map toVHDLSignalMap args) (toVHDLSignalMap res)) - ) - -builtin_hsfuncs = Map.keys builtin_funcs -builtin_funcs = mkBuiltins - [ - BuiltIn "hwxor" [(Single ("a", VHDL.bit_ty)), (Single ("b", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)), - BuiltIn "hwand" [(Single ("a", VHDL.bit_ty)), (Single ("b", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)), - BuiltIn "hwor" [(Single ("a", VHDL.bit_ty)), (Single ("b", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)), - BuiltIn "hwnot" [(Single ("a", VHDL.bit_ty))] (Single ("o", VHDL.bit_ty)) - ] - --- | Map a port specification of a builtin function to a VHDL Signal to put in --- a VHDLSignalMap -toVHDLSignalMap :: HsValueMap (String, AST.TypeMark) -> VHDLSignalMap -toVHDLSignalMap = fmap (\(name, ty) -> Just (mkVHDLId name, ty)) + (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- ^ The binding to process + -> VHDLSession [AST.ConcSm] -- ^ The corresponding VHDL component instantiations. + + +-- Ignore Cast expressions, they should not longer have any meaning as long as +-- the type works out. +mkConcSm (bndr, Cast expr ty) = mkConcSm (bndr, expr) + +-- Simple a = b assignments are just like applications, but without arguments. +-- We can't just generate an unconditional assignment here, since b might be a +-- top level binding (e.g., a function with no arguments). +mkConcSm (bndr, Var v) = do + genApplication (Left bndr) v [] + +mkConcSm (bndr, app@(CoreSyn.App _ _))= do + let (CoreSyn.Var f, args) = CoreSyn.collectArgs app + let valargs = get_val_args (Var.varType f) args + genApplication (Left bndr) f (map Left valargs) + +-- A single alt case must be a selector. This means thee scrutinee is a simple +-- variable, the alternative is a dataalt with a single non-wild binder that +-- is also returned. +mkConcSm (bndr, expr@(Case (Var scrut) b ty [alt])) = + case alt of + (DataAlt dc, bndrs, (Var sel_bndr)) -> do + case List.elemIndex sel_bndr bndrs of + Just i -> do + labels <- MonadState.lift vsType $ getFieldLabels (Id.idType scrut) + let label = labels!!i + let sel_name = mkSelectedName (varToVHDLName scrut) label + let sel_expr = AST.PrimName sel_name + return [mkUncondAssign (Left bndr) sel_expr] + Nothing -> error $ "\nVHDL.mkConcSM: Not in normal form: Not a selector case:\n" ++ (pprString expr) + + _ -> error $ "\nVHDL.mkConcSM: Not in normal form: Not a selector case:\n" ++ (pprString expr) + +-- Multiple case alt are be conditional assignments and have only wild +-- binders in the alts and only variables in the case values and a variable +-- for a scrutinee. We check the constructor of the second alt, since the +-- first is the default case, if there is any. +mkConcSm (bndr, (Case (Var scrut) b ty [(_, _, Var false), (con, _, Var true)])) = do { + ; ty_state <- getA vsType + ; let { cond_expr = (varToVHDLExpr ty_state scrut) AST.:=: (altconToVHDLExpr con) + ; true_expr = (varToVHDLExpr ty_state true) + ; false_expr = (varToVHDLExpr ty_state false) + } ; + ; return [mkCondAssign (Left bndr) cond_expr true_expr false_expr] + } +mkConcSm (_, (Case (Var _) _ _ alts)) = error "\nVHDL.mkConcSm: Not in normal form: Case statement with more than two alternatives" +mkConcSm (_, Case _ _ _ _) = error "\nVHDL.mkConcSm: Not in normal form: Case statement has does not have a simple variable as scrutinee" +mkConcSm (bndr, expr) = error $ "\nVHDL.mkConcSM: Unsupported binding in let expression: " ++ pprString bndr ++ " = " ++ pprString expr