Add port declarations to the VHDL entities.
[matthijs/master-project/cλash.git] / VHDL.hs
1 --
2 -- Functions to generate VHDL from FlatFunctions
3 --
4 module VHDL where
5
6 import Data.Traversable
7 import qualified Data.Foldable as Foldable
8 import qualified Maybe
9
10 import qualified Type
11 import qualified Name
12 import qualified TyCon
13 import Outputable ( showSDoc, ppr )
14
15 import qualified ForSyDe.Backend.VHDL.AST as AST
16
17 import VHDLTypes
18 import FlattenTypes
19 import TranslatorTypes
20
21 -- | Create an entity for a given function
22 createEntity ::
23   HsFunction        -- | The function signature
24   -> FuncData       -- | The function data collected so far
25   -> FuncData       -- | The modified function data
26
27 createEntity hsfunc fdata = 
28   let func = flatFunc fdata in
29   case func of
30     -- Skip (builtin) functions without a FlatFunction
31     Nothing -> fdata
32     -- Create an entity for all other functions
33     Just flatfunc ->
34       
35       let 
36         s       = sigs flatfunc
37         a       = args flatfunc
38         r       = res  flatfunc
39         args'   = map (fmap (mkMap s)) a
40         res'    = fmap (mkMap s) r
41         ent_decl' = createEntityAST hsfunc args' res'
42         entity' = Entity args' res' (Just ent_decl')
43       in
44         fdata { entity = Just entity' }
45   where
46     mkMap :: Eq id => [(id, SignalInfo)] -> id -> (AST.VHDLId, AST.TypeMark)
47     mkMap sigmap id =
48       (mkVHDLId nm, vhdl_ty ty)
49       where
50         info = Maybe.fromMaybe
51           (error $ "Signal not found in the name map? This should not happen!")
52           (lookup id sigmap)
53         nm = Maybe.fromMaybe
54           (error $ "Signal not named? This should not happen!")
55           (sigName info)
56         ty = sigTy info
57
58 -- | Create the VHDL AST for an entity
59 createEntityAST ::
60   HsFunction            -- | The signature of the function we're working with
61   -> [VHDLSignalMap]    -- | The entity's arguments
62   -> VHDLSignalMap      -- | The entity's result
63   -> AST.EntityDec      -- | The entity with the ent_decl filled in as well
64
65 createEntityAST hsfunc args res =
66   AST.EntityDec vhdl_id ports
67   where
68     vhdl_id = mkEntityId hsfunc
69     ports = concatMap (mapToPorts AST.In) args
70             ++ mapToPorts AST.Out res
71     mapToPorts :: AST.Mode -> VHDLSignalMap -> [AST.IfaceSigDec] 
72     mapToPorts mode m =
73       map (mkIfaceSigDec mode) (Foldable.toList m)
74
75 -- | Create a port declaration
76 mkIfaceSigDec ::
77   AST.Mode                         -- | The mode for the port (In / Out)
78   -> (AST.VHDLId, AST.TypeMark)    -- | The id and type for the port
79   -> AST.IfaceSigDec               -- | The resulting port declaration
80
81 mkIfaceSigDec mode (id, ty) = AST.IfaceSigDec id mode ty
82
83 -- | Generate a VHDL entity name for the given hsfunc
84 mkEntityId hsfunc =
85   -- TODO: This doesn't work for functions with multiple signatures!
86   mkVHDLId $ hsFuncName hsfunc
87
88 getLibraryUnits ::
89   (HsFunction, FuncData)      -- | A function from the session
90   -> [AST.LibraryUnit]        -- | The library units it generates
91
92 getLibraryUnits (hsfunc, fdata) =
93   case entity fdata of 
94     Nothing -> []
95     Just ent -> case ent_decl ent of
96       Nothing -> []
97       Just decl -> [AST.LUEntity decl]
98
99 -- | The VHDL Bit type
100 bit_ty :: AST.TypeMark
101 bit_ty = AST.unsafeVHDLBasicId "Bit"
102
103 -- Translate a Haskell type to a VHDL type
104 vhdl_ty :: Type.Type -> AST.TypeMark
105 vhdl_ty ty = Maybe.fromMaybe
106   (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty))
107   (vhdl_ty_maybe ty)
108
109 -- Translate a Haskell type to a VHDL type
110 vhdl_ty_maybe :: Type.Type -> Maybe AST.TypeMark
111 vhdl_ty_maybe ty =
112   case Type.splitTyConApp_maybe ty of
113     Just (tycon, args) ->
114       let name = TyCon.tyConName tycon in
115         -- TODO: Do something more robust than string matching
116         case Name.getOccString name of
117           "Bit"      -> Just bit_ty
118           otherwise  -> Nothing
119     otherwise -> Nothing
120
121 -- Shortcut
122 mkVHDLId :: String -> AST.VHDLId
123 mkVHDLId = AST.unsafeVHDLBasicId