-- top level function "normalize", and defines the actual transformation passes that
-- are performed.
--
-module CLasH.Normalize (getNormalized, normalizeExpr) where
+module CLasH.Normalize (getNormalized, normalizeExpr, splitNormalized) where
-- Standard modules
import Debug.Trace
-- If the binding isn't in the "cache" (bindings map), then we can't create
-- it out of thin air, so return an error.
error $ "Normalize.getBinding: Unknown function requested: " ++ show bndr
+
+-- | Split a normalized expression into the argument binders, top level
+-- bindings and the result binder.
+splitNormalized ::
+ CoreExpr -- ^ The normalized expression
+ -> ([CoreBndr], [Binding], CoreBndr)
+splitNormalized expr = (args, binds, res)
+ where
+ (args, letexpr) = CoreSyn.collectBinders expr
+ (binds, resexpr) = flattenLets letexpr
+ res = case resexpr of
+ (Var x) -> x
+ _ -> error $ "Normalize.splitNormalized: Not in normal form: " ++ pprString expr ++ "\n"
+
+-- | Flattens nested lets into a single list of bindings. The expression
+-- passed does not have to be a let expression, if it isn't an empty list of
+-- bindings is returned.
+flattenLets ::
+ CoreExpr -- ^ The expression to flatten.
+ -> ([Binding], CoreExpr) -- ^ The bindings and resulting expression.
+flattenLets (Let binds expr) =
+ (bindings ++ bindings', expr')
+ where
+ -- Recursively flatten the contained expression
+ (bindings', expr') =flattenLets expr
+ -- Flatten our own bindings to remove the Rec / NonRec constructors
+ bindings = CoreSyn.flattenBinds [binds]
+flattenLets expr = ([], expr)
getEntity fname = Utils.makeCached fname tsEntities $ do
expr <- Normalize.getNormalized fname
- -- Strip off lambda's, these will be arguments
- let (args, letexpr) = CoreSyn.collectBinders expr
+ -- Split the normalized expression
+ let (args, binds, res) = Normalize.splitNormalized expr
-- Generate ports for all non-empty types
args' <- catMaybesM $ mapM mkMap args
- -- There must be a let at top level
- let (CoreSyn.Let binds (CoreSyn.Var res)) = letexpr
-- TODO: Handle Nothing
res' <- mkMap res
count <- getA tsEntityCounter
getArchitecture fname = Utils.makeCached fname tsArchitectures $ do
expr <- Normalize.getNormalized fname
+ -- Split the normalized expression
+ let (args, binds, res) = Normalize.splitNormalized expr
+
+ -- Get the entity for this function
signature <- getEntity fname
let entity_id = ent_id signature
- -- 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) (CoreSyn.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
let (in_state_maybes, out_state_maybes) = unzip state_vars
let (statementss, used_entitiess) = unzip sms
-- Create a state proc, if needed
- let state_proc = case (Maybe.catMaybes in_state_maybes, Maybe.catMaybes out_state_maybes) of
- ([in_state], [out_state]) -> [AST.CSPSm $ mkStateProcSm (in_state, out_state)]
- ([], []) -> []
+ state_proc <- case (Maybe.catMaybes in_state_maybes, Maybe.catMaybes out_state_maybes) of
+ ([in_state], [out_state]) -> mkStateProcSm (in_state, out_state)
+ ([], []) -> return []
(ins, outs) -> error $ "Weird use of state in " ++ show fname ++ ". In: " ++ show ins ++ " Out: " ++ show outs
-- Join the create statements and the (optional) state_proc
let statements = concat statementss ++ state_proc
mkStateProcSm ::
(CoreSyn.CoreBndr, CoreSyn.CoreBndr) -- ^ The current and new state variables
- -> AST.ProcSm -- ^ The resulting statement
-mkStateProcSm (old, new) =
- AST.ProcSm label [clk] [statement]
+ -> TranslatorSession [AST.ConcSm] -- ^ The resulting statements
+mkStateProcSm (old, new) = do
+ nonempty <- hasNonEmptyType old
+ if nonempty
+ then return [AST.CSPSm $ AST.ProcSm label [clk] [statement]]
+ else return []
where
label = mkVHDLBasicId $ "state"
clk = mkVHDLBasicId "clock"
createStimulans expr cycl = do
-- There must be a let at top level
- (CoreSyn.Let (CoreSyn.Rec binds) (Var res)) <- normalizeExpr ("test input #" ++ show cycl) expr
+ expr <- normalizeExpr ("test input #" ++ show cycl) expr
+ -- Split the normalized expression. It can't have a function type, so match
+ -- an empty list of argument binders
+ let ([], binds, res) = splitNormalized expr
(stimulansbindss, useds) <- unzipM $ Monad.mapM mkConcSm binds
sig_dec_maybes <- mapM (mkSigDec . fst) (filter ((/=res).fst) binds)
let sig_decs = map (AST.BDISD) (Maybe.catMaybes $ sig_dec_maybes)