Make application names unique.
[matthijs/master-project/cλash.git] / VHDL.hs
1 --
2 -- Functions to generate VHDL from FlatFunctions
3 --
4 module VHDL where
5
6 import qualified Data.Foldable as Foldable
7 import qualified Maybe
8 import qualified Control.Monad as Monad
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 import Pretty
21
22 -- | Create an entity for a given function
23 createEntity ::
24   HsFunction        -- | The function signature
25   -> FuncData       -- | The function data collected so far
26   -> VHDLState ()
27
28 createEntity hsfunc fdata = 
29   let func = flatFunc fdata in
30   case func of
31     -- Skip (builtin) functions without a FlatFunction
32     Nothing -> do return ()
33     -- Create an entity for all other functions
34     Just flatfunc ->
35       
36       let 
37         sigs    = flat_sigs flatfunc
38         args    = flat_args flatfunc
39         res     = flat_res  flatfunc
40         args'   = map (fmap (mkMap sigs)) args
41         res'    = fmap (mkMap sigs) res
42         ent_decl' = createEntityAST hsfunc args' res'
43         AST.EntityDec entity_id _ = ent_decl' 
44         entity' = Entity entity_id args' res' (Just ent_decl')
45       in
46         setEntity hsfunc entity'
47   where
48     mkMap :: Eq id => [(id, SignalInfo)] -> id -> (AST.VHDLId, AST.TypeMark)
49     mkMap sigmap id =
50       (mkVHDLId nm, vhdl_ty ty)
51       where
52         info = Maybe.fromMaybe
53           (error $ "Signal not found in the name map? This should not happen!")
54           (lookup id sigmap)
55         nm = Maybe.fromMaybe
56           (error $ "Signal not named? This should not happen!")
57           (sigName info)
58         ty = sigTy info
59
60 -- | Create the VHDL AST for an entity
61 createEntityAST ::
62   HsFunction            -- | The signature of the function we're working with
63   -> [VHDLSignalMap]    -- | The entity's arguments
64   -> VHDLSignalMap      -- | The entity's result
65   -> AST.EntityDec      -- | The entity with the ent_decl filled in as well
66
67 createEntityAST hsfunc args res =
68   AST.EntityDec vhdl_id ports
69   where
70     vhdl_id = mkEntityId hsfunc
71     ports = concatMap (mapToPorts AST.In) args
72             ++ mapToPorts AST.Out res
73     mapToPorts :: AST.Mode -> VHDLSignalMap -> [AST.IfaceSigDec] 
74     mapToPorts mode m =
75       map (mkIfaceSigDec mode) (Foldable.toList m)
76
77 -- | Create a port declaration
78 mkIfaceSigDec ::
79   AST.Mode                         -- | The mode for the port (In / Out)
80   -> (AST.VHDLId, AST.TypeMark)    -- | The id and type for the port
81   -> AST.IfaceSigDec               -- | The resulting port declaration
82
83 mkIfaceSigDec mode (id, ty) = AST.IfaceSigDec id mode ty
84
85 -- | Generate a VHDL entity name for the given hsfunc
86 mkEntityId hsfunc =
87   -- TODO: This doesn't work for functions with multiple signatures!
88   mkVHDLId $ hsFuncName hsfunc
89
90 -- | Create an architecture for a given function
91 createArchitecture ::
92   HsFunction        -- | The function signature
93   -> FuncData       -- | The function data collected so far
94   -> VHDLState ()
95
96 createArchitecture hsfunc fdata = 
97   let func = flatFunc fdata in
98   case func of
99     -- Skip (builtin) functions without a FlatFunction
100     Nothing -> do return ()
101     -- Create an architecture for all other functions
102     Just flatfunc -> do
103       let sigs = flat_sigs flatfunc
104       let args = flat_args flatfunc
105       let res  = flat_res  flatfunc
106       let apps = flat_apps flatfunc
107       let entity_id = Maybe.fromMaybe
108                       (error $ "Building architecture without an entity? This should not happen!")
109                       (getEntityId fdata)
110       -- Create signal declarations for all signals that are not in args and
111       -- res
112       let sig_decs = [mkSigDec info | (id, info) <- sigs, (all (id `Foldable.notElem`) (res:args)) ]
113       -- Create component instantiations for all function applications
114       insts <- mapM mkCompInsSm apps
115       let insts' = map AST.CSISm insts
116       let arch = AST.ArchBody (mkVHDLId "structural") (AST.NSimple entity_id) (map AST.BDISD sig_decs) insts'
117       setArchitecture hsfunc arch
118
119 mkSigDec :: SignalInfo -> AST.SigDec
120 mkSigDec info =
121     AST.SigDec (mkVHDLId name) (vhdl_ty ty) Nothing
122   where
123     name = Maybe.fromMaybe
124       (error $ "Unnamed signal? This should not happen!")
125       (sigName info)
126     ty = sigTy info
127
128 -- | Transforms a flat function application to a VHDL component instantiation.
129 mkCompInsSm ::
130   FApp UnnamedSignal            -- | The application to look at.
131   -> VHDLState AST.CompInsSm    -- | The corresponding VHDL component instantiation.
132
133 mkCompInsSm app = do
134   let hsfunc = appFunc app
135   fdata_maybe <- getFunc hsfunc
136   let fdata = Maybe.fromMaybe
137         (error $ "Using function '" ++ (prettyShow hsfunc) ++ "' that is not in the session? This should not happen!")
138         fdata_maybe
139   let entity = Maybe.fromMaybe
140         (error $ "Using function '" ++ (prettyShow hsfunc) ++ "' without entity declaration? This should not happen!")
141         (funcEntity fdata)
142   let entity_id = ent_id entity
143   label <- uniqueName (AST.fromVHDLId entity_id)
144   return $ AST.CompInsSm (mkVHDLId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps)
145   where
146     portmaps  = []
147
148 -- | Extracts the generated entity id from the given funcdata
149 getEntityId :: FuncData -> Maybe AST.VHDLId
150 getEntityId fdata =
151   case funcEntity fdata of
152     Nothing -> Nothing
153     Just e  -> case ent_decl e of
154       Nothing -> Nothing
155       Just (AST.EntityDec id _) -> Just id
156
157 getLibraryUnits ::
158   (HsFunction, FuncData)      -- | A function from the session
159   -> [AST.LibraryUnit]        -- | The library units it generates
160
161 getLibraryUnits (hsfunc, fdata) =
162   case funcEntity fdata of 
163     Nothing -> []
164     Just ent -> case ent_decl ent of
165       Nothing -> []
166       Just decl -> [AST.LUEntity decl]
167   ++
168   case funcArch fdata of
169     Nothing -> []
170     Just arch -> [AST.LUArch arch]
171
172 -- | The VHDL Bit type
173 bit_ty :: AST.TypeMark
174 bit_ty = AST.unsafeVHDLBasicId "Bit"
175
176 -- Translate a Haskell type to a VHDL type
177 vhdl_ty :: Type.Type -> AST.TypeMark
178 vhdl_ty ty = Maybe.fromMaybe
179   (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty))
180   (vhdl_ty_maybe ty)
181
182 -- Translate a Haskell type to a VHDL type
183 vhdl_ty_maybe :: Type.Type -> Maybe AST.TypeMark
184 vhdl_ty_maybe ty =
185   case Type.splitTyConApp_maybe ty of
186     Just (tycon, args) ->
187       let name = TyCon.tyConName tycon in
188         -- TODO: Do something more robust than string matching
189         case Name.getOccString name of
190           "Bit"      -> Just bit_ty
191           otherwise  -> Nothing
192     otherwise -> Nothing
193
194 -- Shortcut
195 mkVHDLId :: String -> AST.VHDLId
196 mkVHDLId = AST.unsafeVHDLBasicId