X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=VHDL.hs;h=4f4e75cf122ac758be03066ec40c36f261ffbae1;hb=b62b2e3aa902db1f774c2f655b25e8428e2b1cf0;hp=dad3aec2623867ec0c958a3810ac9ca5ff35ce34;hpb=e03f02c419b4365d498c25dfbc861215394046df;p=matthijs%2Fmaster-project%2Fc%CE%BBash.git diff --git a/VHDL.hs b/VHDL.hs index dad3aec..4f4e75c 100644 --- a/VHDL.hs +++ b/VHDL.hs @@ -27,6 +27,7 @@ import qualified Type import qualified Name import qualified OccName import qualified Var +import qualified Id import qualified TyCon import qualified DataCon import qualified CoreSubst @@ -280,8 +281,25 @@ mkConcSm (bndr, app@(CoreSyn.App _ _))= do -- 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 scrut_name = AST.NSimple $ bndrToVHDLId scrut + let sel_suffix = AST.SSimple $ label + let sel_name = AST.NSelected $ scrut_name AST.:.: sel_suffix + let sel_expr = AST.PrimName sel_name + return $ mkUncondAssign 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 +310,64 @@ 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 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 :: + CoreBndr -- ^ The signal to assign to + -> AST.Expr -- ^ The expression to assign + -> AST.ConcSm -- ^ The resulting concurrent statement +mkUncondAssign bndr expr = mkAssign bndr Nothing expr + +-- Create a conditional assignment statement +mkCondAssign :: + CoreBndr -- ^ 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 bndr cond true false = mkAssign bndr (Just (cond, true)) false + +-- Create a conditional or unconditional assignment statement +mkAssign :: + CoreBndr -> -- ^ 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 bndr 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 = AST.NSimple (bndrToVHDLId bndr) + assign = dst_name AST.:<==: (AST.ConWforms whenelse false_wform Nothing) + in + AST.CSSASm assign + +-- 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 @@ -458,9 +524,39 @@ construct_vhdl_ty ty = do "SizedWord" -> do res <- mk_vector_ty (sized_word_len ty) ty return $ Just res - otherwise -> return Nothing + -- Create a custom type from this tycon + otherwise -> mk_tycon_ty tycon args Nothing -> return $ Nothing +-- | Create VHDL type for a custom tycon +mk_tycon_ty :: TyCon.TyCon -> [Type.Type] -> VHDLState (Maybe (AST.TypeMark, AST.TypeDef)) +mk_tycon_ty tycon args = + case TyCon.tyConDataCons tycon of + -- Not an algebraic type + [] -> error $ "Only custom algebraic types are supported: " ++ (showSDoc $ ppr tycon) + [dc] -> do + let arg_tys = DataCon.dataConRepArgTys dc + -- TODO: CoreSubst docs say each Subs can be applied only once. Is this a + -- violation? Or does it only mean not to apply it again to the same + -- subject? + let real_arg_tys = map (CoreSubst.substTy subst) arg_tys + elem_tys <- mapM vhdl_ty real_arg_tys + let elems = zipWith AST.ElementDec recordlabels elem_tys + -- For a single construct datatype, build a record with one field for + -- each argument. + -- TODO: Add argument type ids to this, to ensure uniqueness + -- TODO: Special handling for tuples? + let ty_id = mkVHDLExtId $ nameToString (TyCon.tyConName tycon) + let ty_def = AST.TDR $ AST.RecordTypeDef elems + return $ Just (ty_id, ty_def) + dcs -> error $ "Only single constructor datatypes supported: " ++ (showSDoc $ ppr tycon) + where + -- Create a subst that instantiates all types passed to the tycon + -- TODO: I'm not 100% sure that this is the right way to do this. It seems + -- to work so far, though.. + tyvars = TyCon.tyConTyVars tycon + subst = CoreSubst.extendTvSubstList CoreSubst.emptySubst (zip tyvars args) + -- | Create a VHDL vector type mk_vector_ty :: Int -- ^ The length of the vector @@ -529,6 +625,10 @@ bndrToString :: bndrToString = OccName.occNameString . Name.nameOccName . Var.varName +-- Extracts the string version of the name +nameToString :: Name.Name -> String +nameToString = OccName.occNameString . Name.nameOccName + -- | 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 @@ -551,6 +651,8 @@ builtin_funcs = mkBuiltins BuiltIn "hwnot" [("a", VHDL.bit_ty)] ("o", VHDL.bit_ty) ] +recordlabels = map (\c -> mkVHDLBasicId [c]) ['A'..'Z'] + -- | Map a port specification of a builtin function to a VHDL Signal to put in -- a VHDLSignalMap toVHDLSignalMapElement :: (String, AST.TypeMark) -> VHDLSignalMapElement