X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=VHDL.hs;h=96a541ee0e36f04a1ac27232aeca6e496e005711;hb=130e806e04ceecd8d209f801891d2b1a32fa144e;hp=f145385e6c19f932a089d6bae4b62eb8ef0b7952;hpb=0d5cf9c7743e3db5aec159993ce2280493890a19;p=matthijs%2Fmaster-project%2Fc%CE%BBash.git diff --git a/VHDL.hs b/VHDL.hs index f145385..96a541e 100644 --- a/VHDL.hs +++ b/VHDL.hs @@ -27,6 +27,8 @@ import qualified Type import qualified Name import qualified OccName import qualified Var +import qualified Id +import qualified IdInfo import qualified TyCon import qualified DataCon import qualified CoreSubst @@ -247,41 +249,63 @@ mkConcSm :: -> VHDLState AST.ConcSm -- ^ The corresponding VHDL component instantiation. mkConcSm (bndr, app@(CoreSyn.App _ _))= do - signatures <- getA vsSignatures - funSignatures <- getA vsNameTable let (CoreSyn.Var f, args) = CoreSyn.collectArgs app - case (Map.lookup (bndrToString f) funSignatures) of - Just funSignature -> - let - sigs = map (bndrToString.varBndr) args - sigsNames = map (\signal -> (AST.PrimName (AST.NSimple (mkVHDLExtId signal)))) sigs - func = (snd funSignature) sigsNames - src_wform = AST.Wform [AST.WformElem func Nothing] - dst_name = AST.NSimple (mkVHDLExtId (bndrToString bndr)) - assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing) - in - return $ AST.CSSASm assign - Nothing -> + case Var.globalIdVarDetails f of + IdInfo.VanillaGlobal -> do + -- It's a global value imported from elsewhere. These can be builting + -- functions. + funSignatures <- getA vsNameTable + case (Map.lookup (bndrToString f) funSignatures) of + Just funSignature -> + let + sigs = map (bndrToString.varBndr) args + sigsNames = map (\signal -> (AST.PrimName (AST.NSimple (mkVHDLExtId signal)))) sigs + func = (snd funSignature) sigsNames + src_wform = AST.Wform [AST.WformElem func Nothing] + dst_name = AST.NSimple (mkVHDLExtId (bndrToString bndr)) + assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing) + in + return $ AST.CSSASm assign + Nothing -> error $ "Using function from another module that is not a known builtin: " ++ pprString f + IdInfo.NotGlobalId -> do + signatures <- getA vsSignatures + -- This is a local id, so it should be a function whose definition we + -- have and which can be turned into a component instantiation. let signature = Maybe.fromMaybe (error $ "Using function '" ++ (bndrToString f) ++ "' without signature? This should not happen!") (Map.lookup (bndrToString f) signatures) entity_id = ent_id signature label = bndrToString bndr - -- Add a clk port if we have state - --clk_port = Maybe.fromJust $ mkAssocElem (Just $ mkVHDLExtId "clk") "clk" - --portmaps = mkAssocElems sigs args res signature ++ (if hasState hsfunc then [clk_port] else []) + -- Add a clk port if we have state + --clk_port = Maybe.fromJust $ mkAssocElem (Just $ mkVHDLExtId "clk") "clk" + --portmaps = mkAssocElems sigs args res signature ++ (if hasState hsfunc then [clk_port] else []) portmaps = mkAssocElems args bndr signature - in - return $ AST.CSISm $ AST.CompInsSm (mkVHDLExtId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps) + in + return $ AST.CSISm $ AST.CompInsSm (mkVHDLExtId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps) + details -> error $ "Calling unsupported function " ++ pprString f ++ " with GlobalIdDetails " ++ pprString details -- GHC generates some funny "r = r" bindings in let statements before -- simplification. This outputs some dummy ConcSM for these, so things will at -- least compile for now. mkConcSm (bndr, CoreSyn.Var _) = return $ AST.CSPSm $ AST.ProcSm (mkVHDLBasicId "unused") [] [] --- A single alt case must be a selector -mkConcSm (bndr, (Case (Var scrut) b ty [alt])) = error "Single case alt not supported yet" +-- 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 <- getFieldLabels (Id.idType scrut) + let label = labels!!i + let sel_name = mkSelectedName scrut label + let sel_expr = AST.PrimName sel_name + return $ mkUncondAssign (Left bndr) sel_expr + Nothing -> error $ "VHDL.mkConcSM Not in normal form: Not a selector case:\n" ++ (pprString expr) + + _ -> error $ "VHDL.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 @@ -292,16 +316,76 @@ mkConcSm (bndr, (Case (Var scrut) b ty [(_, _, Var false), (con, _, Var true)])) cond_expr = (varToVHDLExpr scrut) AST.:=: (conToVHDLExpr con) true_expr = (varToVHDLExpr true) false_expr = (varToVHDLExpr 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 (bndrToVHDLId bndr) - assign = dst_name AST.:<==: (AST.ConWforms [whenelse] false_wform Nothing) in - return $ AST.CSSASm assign + return $ mkCondAssign (Left bndr) cond_expr true_expr false_expr mkConcSm (_, (Case (Var _) _ _ alts)) = error "VHDL.mkConcSm Not in normal form: Case statement with more than two alternatives" mkConcSm (_, Case _ _ _ _) = error "VHDL.mkConcSm Not in normal form: Case statement has does not have a simple variable as scrutinee" +-- Create an unconditional assignment statement +mkUncondAssign :: + Either CoreBndr AST.VHDLName -- ^ The signal to assign to + -> AST.Expr -- ^ The expression to assign + -> AST.ConcSm -- ^ The resulting concurrent statement +mkUncondAssign dst expr = mkAssign dst Nothing expr + +-- Create a conditional assignment statement +mkCondAssign :: + Either CoreBndr AST.VHDLName -- ^ The signal to assign to + -> AST.Expr -- ^ The condition + -> AST.Expr -- ^ The value when true + -> AST.Expr -- ^ The value when false + -> AST.ConcSm -- ^ The resulting concurrent statement +mkCondAssign dst cond true false = mkAssign dst (Just (cond, true)) false + +-- Create a conditional or unconditional assignment statement +mkAssign :: + Either CoreBndr AST.VHDLName -> -- ^ The signal to assign to + Maybe (AST.Expr , AST.Expr) -> -- ^ Optionally, the condition to test for + -- and the value to assign when true. + AST.Expr -> -- ^ The value to assign when false or no condition + AST.ConcSm -- ^ The resulting concurrent statement + +mkAssign dst cond false_expr = + let + -- I'm not 100% how this assignment AST works, but this gets us what we + -- want... + whenelse = case cond of + Just (cond_expr, true_expr) -> + let + true_wform = AST.Wform [AST.WformElem true_expr Nothing] + in + [AST.WhenElse true_wform cond_expr] + Nothing -> [] + false_wform = AST.Wform [AST.WformElem false_expr Nothing] + dst_name = case dst of + Left bndr -> AST.NSimple (bndrToVHDLId bndr) + Right name -> name + assign = dst_name AST.:<==: (AST.ConWforms whenelse false_wform Nothing) + in + AST.CSSASm assign + +-- Create a record field selector that selects the given label from the record +-- stored in the given binder. +mkSelectedName :: CoreBndr -> AST.VHDLId -> AST.VHDLName +mkSelectedName bndr label = + let + sel_prefix = AST.NSimple $ bndrToVHDLId bndr + sel_suffix = AST.SSimple $ label + in + AST.NSelected $ sel_prefix AST.:.: sel_suffix + +-- Finds the field labels for VHDL type generated for the given Core type, +-- which must result in a record type. +getFieldLabels :: Type.Type -> VHDLState [AST.VHDLId] +getFieldLabels ty = do + -- Ensure that the type is generated (but throw away it's VHDLId) + vhdl_ty ty + -- Get the types map, lookup and unpack the VHDL TypeDef + types <- getA vsTypes + case Map.lookup (OrdType ty) types of + Just (_, AST.TDR (AST.RecordTypeDef elems)) -> return $ map (\(AST.ElementDec id _) -> id) elems + _ -> error $ "VHDL.getFieldLabels Type not found or not a record type? This should not happen! Type: " ++ (show ty) + -- Turn a variable reference into a AST expression varToVHDLExpr :: Var.Var -> AST.Expr varToVHDLExpr var = AST.PrimName $ AST.NSimple $ bndrToVHDLId var