+-- | Create an architecture for a given function
+createArchitecture ::
+ HsFunction -- ^ The function signature
+ -> FlatFunction -- ^ The FlatFunction
+ -> VHDLState AST.ArchBody -- ^ The architecture for this function
+
+createArchitecture hsfunc flatfunc = 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)
+ let entity_id = ent_id signature
+ -- Create signal declarations for all internal and state signals
+ sig_dec_maybes <- mapM (mkSigDec' . snd) sigs
+ 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')
+ where
+ sigs = flat_sigs flatfunc
+ args = flat_args flatfunc
+ res = flat_res flatfunc
+ defs = flat_defs flatfunc
+ procs = map mkStateProcSm (makeStatePairs flatfunc)
+ procs' = map AST.CSPSm procs
+ -- mkSigDec only uses vsTypes from the state
+ mkSigDec' = MonadState.lift vsTypes . mkSigDec
+
+-- | Looks up all pairs of old state, new state signals, together with
+-- the state id they represent.
+makeStatePairs :: FlatFunction -> [(StateId, SignalInfo, SignalInfo)]
+makeStatePairs flatfunc =
+ [(Maybe.fromJust $ oldStateId $ sigUse old_info, old_info, new_info)
+ | old_info <- map snd (flat_sigs flatfunc)
+ , new_info <- map snd (flat_sigs flatfunc)
+ -- old_info must be an old state (and, because of the next equality,
+ -- new_info must be a new state).
+ , Maybe.isJust $ oldStateId $ sigUse old_info
+ -- And the state numbers must match
+ , (oldStateId $ sigUse old_info) == (newStateId $ sigUse new_info)]
+
+ -- Replace the second tuple element with the corresponding SignalInfo
+ --args_states = map (Arrow.second $ signalInfo sigs) args
+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"
+ 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)
+
+-- | Transforms a signal definition 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)