Added function calls
[matthijs/master-project/cλash.git] / VHDL.hs
1 --
2 -- Functions to generate VHDL from FlatFunctions
3 --
4 module VHDL where
5
6 -- Standard modules
7 import qualified Data.Foldable as Foldable
8 import qualified Data.List as List
9 import qualified Data.Map as Map
10 import qualified Maybe
11 import qualified Control.Monad as Monad
12 import qualified Control.Arrow as Arrow
13 import qualified Control.Monad.Trans.State as State
14 import qualified Data.Traversable as Traversable
15 import qualified Data.Monoid as Monoid
16 import Data.Accessor
17 import qualified Data.Accessor.MonadState as MonadState
18 import Text.Regex.Posix
19 import Debug.Trace
20
21 -- ForSyDe
22 import qualified ForSyDe.Backend.VHDL.AST as AST
23
24 -- GHC API
25 import qualified Type
26 import qualified Name
27 import qualified OccName
28 import qualified Var
29 import qualified TyCon
30 import qualified CoreSyn
31 import Outputable ( showSDoc, ppr )
32
33 -- Local imports
34 import VHDLTypes
35 import Flatten
36 import FlattenTypes
37 import TranslatorTypes
38 import HsValueMap
39 import Pretty
40 import CoreTools
41 import Constants
42 import Generate
43 import GlobalNameTable
44
45 createDesignFiles ::
46   [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)]
47   -> [(AST.VHDLId, AST.DesignFile)]
48
49 createDesignFiles binds =
50   (mkVHDLBasicId "types", AST.DesignFile ieee_context [type_package]) :
51   map (Arrow.second $ AST.DesignFile full_context) units
52   
53   where
54     init_session = VHDLSession Map.empty Map.empty builtin_funcs globalNameTable
55     (units, final_session) = 
56       State.runState (createLibraryUnits binds) init_session
57     ty_decls = Map.elems (final_session ^. vsTypes)
58     ieee_context = [
59         AST.Library $ mkVHDLBasicId "IEEE",
60         mkUseAll ["IEEE", "std_logic_1164"],
61         mkUseAll ["IEEE", "numeric_std"]
62       ]
63     full_context =
64       mkUseAll ["work", "types"]
65       : ieee_context
66     type_package = AST.LUPackageDec $ AST.PackageDec (mkVHDLBasicId "types") (map (AST.PDITD . snd) ty_decls)
67
68 -- Create a use foo.bar.all statement. Takes a list of components in the used
69 -- name. Must contain at least two components
70 mkUseAll :: [String] -> AST.ContextItem
71 mkUseAll ss = 
72   AST.Use $ from AST.:.: AST.All
73   where
74     base_prefix = (AST.NSimple $ mkVHDLBasicId $ head ss)
75     from = foldl select base_prefix (tail ss)
76     select prefix s = AST.NSelected $ prefix AST.:.: (AST.SSimple $ mkVHDLBasicId s)
77       
78 createLibraryUnits ::
79   [(CoreSyn.CoreBndr, CoreSyn.CoreExpr)]
80   -> VHDLState [(AST.VHDLId, [AST.LibraryUnit])]
81
82 createLibraryUnits binds = do
83   entities <- Monad.mapM createEntity binds
84   archs <- Monad.mapM createArchitecture binds
85   return $ zipWith 
86     (\ent arch -> 
87       let AST.EntityDec id _ = ent in 
88       (id, [AST.LUEntity ent, AST.LUArch arch])
89     )
90     entities archs
91
92 -- | Create an entity for a given function
93 createEntity ::
94   (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- | The function
95   -> VHDLState AST.EntityDec -- | The resulting entity
96
97 createEntity (fname, expr) = do
98       -- Strip off lambda's, these will be arguments
99       let (args, letexpr) = CoreSyn.collectBinders expr
100       args' <- Monad.mapM mkMap args
101       -- There must be a let at top level 
102       let (CoreSyn.Let binds (CoreSyn.Var res)) = letexpr
103       res' <- mkMap res
104       let ent_decl' = createEntityAST fname args' res'
105       let AST.EntityDec entity_id _ = ent_decl' 
106       let signature = Entity entity_id args' res'
107       modA vsSignatures (Map.insert (bndrToString fname) signature)
108       return ent_decl'
109   where
110     mkMap :: 
111       --[(SignalId, SignalInfo)] 
112       CoreSyn.CoreBndr 
113       -> VHDLState VHDLSignalMapElement
114     -- We only need the vsTypes element from the state
115     mkMap = (\bndr ->
116       let
117         --info = Maybe.fromMaybe
118         --  (error $ "Signal not found in the name map? This should not happen!")
119         --  (lookup id sigmap)
120         --  Assume the bndr has a valid VHDL id already
121         id = bndrToVHDLId bndr
122         ty = Var.varType bndr
123       in
124         if True -- isPortSigUse $ sigUse info
125           then do
126             type_mark <- vhdl_ty ty
127             return $ Just (id, type_mark)
128           else
129             return $ Nothing
130        )
131
132   -- | Create the VHDL AST for an entity
133 createEntityAST ::
134   CoreSyn.CoreBndr             -- | The name of the function
135   -> [VHDLSignalMapElement]    -- | The entity's arguments
136   -> VHDLSignalMapElement      -- | The entity's result
137   -> AST.EntityDec             -- | The entity with the ent_decl filled in as well
138
139 createEntityAST name args res =
140   AST.EntityDec vhdl_id ports
141   where
142     -- Create a basic Id, since VHDL doesn't grok filenames with extended Ids.
143     vhdl_id = mkVHDLBasicId $ bndrToString name
144     ports = Maybe.catMaybes $ 
145               map (mkIfaceSigDec AST.In) args
146               ++ [mkIfaceSigDec AST.Out res]
147               ++ [clk_port]
148     -- Add a clk port if we have state
149     clk_port = if True -- hasState hsfunc
150       then
151         Just $ AST.IfaceSigDec (mkVHDLExtId "clk") AST.In VHDL.std_logic_ty
152       else
153         Nothing
154
155 -- | Create a port declaration
156 mkIfaceSigDec ::
157   AST.Mode                         -- | The mode for the port (In / Out)
158   -> Maybe (AST.VHDLId, AST.TypeMark)    -- | The id and type for the port
159   -> Maybe AST.IfaceSigDec               -- | The resulting port declaration
160
161 mkIfaceSigDec mode (Just (id, ty)) = Just $ AST.IfaceSigDec id mode ty
162 mkIfaceSigDec _ Nothing = Nothing
163
164 -- | Generate a VHDL entity name for the given hsfunc
165 mkEntityId hsfunc =
166   -- TODO: This doesn't work for functions with multiple signatures!
167   -- Use a Basic Id, since using extended id's for entities throws off
168   -- precision and causes problems when generating filenames.
169   mkVHDLBasicId $ hsFuncName hsfunc
170
171 -- | Create an architecture for a given function
172 createArchitecture ::
173   (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- ^ The function
174   -> VHDLState AST.ArchBody -- ^ The architecture for this function
175
176 createArchitecture (fname, expr) = do
177   --signaturemap <- getA vsSignatures
178   --let signature = Maybe.fromMaybe 
179   --      (error $ "Generating architecture for function " ++ (prettyShow hsfunc) ++ "without signature? This should not happen!")
180   --      (Map.lookup hsfunc signaturemap)
181   let entity_id = mkVHDLBasicId $ bndrToString fname
182   -- Strip off lambda's, these will be arguments
183   let (args, letexpr) = CoreSyn.collectBinders expr
184   -- There must be a let at top level 
185   let (CoreSyn.Let (CoreSyn.Rec binds) res) = letexpr
186
187   -- Create signal declarations for all internal and state signals
188   sig_dec_maybes <- mapM (mkSigDec' . fst) binds
189   let sig_decs = Maybe.catMaybes $ sig_dec_maybes
190
191   statements <- Monad.mapM mkConcSm binds
192   return $ AST.ArchBody (mkVHDLBasicId "structural") (AST.NSimple entity_id) (map AST.BDISD sig_decs) (statements ++ procs')
193   where
194     procs = map mkStateProcSm [] -- (makeStatePairs flatfunc)
195     procs' = map AST.CSPSm procs
196     -- mkSigDec only uses vsTypes from the state
197     mkSigDec' = mkSigDec
198
199 -- | Looks up all pairs of old state, new state signals, together with
200 --   the state id they represent.
201 makeStatePairs :: FlatFunction -> [(StateId, SignalInfo, SignalInfo)]
202 makeStatePairs flatfunc =
203   [(Maybe.fromJust $ oldStateId $ sigUse old_info, old_info, new_info) 
204     | old_info <- map snd (flat_sigs flatfunc)
205     , new_info <- map snd (flat_sigs flatfunc)
206         -- old_info must be an old state (and, because of the next equality,
207         -- new_info must be a new state).
208         , Maybe.isJust $ oldStateId $ sigUse old_info
209         -- And the state numbers must match
210     , (oldStateId $ sigUse old_info) == (newStateId $ sigUse new_info)]
211
212     -- Replace the second tuple element with the corresponding SignalInfo
213     --args_states = map (Arrow.second $ signalInfo sigs) args
214 mkStateProcSm :: (StateId, SignalInfo, SignalInfo) -> AST.ProcSm
215 mkStateProcSm (num, old, new) =
216   AST.ProcSm label [clk] [statement]
217   where
218     label       = mkVHDLExtId $ "state_" ++ (show num)
219     clk         = mkVHDLExtId "clk"
220     rising_edge = AST.NSimple $ mkVHDLBasicId "rising_edge"
221     wform       = AST.Wform [AST.WformElem (AST.PrimName $ AST.NSimple $ getSignalId new) Nothing]
222     assign      = AST.SigAssign (AST.NSimple $ getSignalId old) wform
223     rising_edge_clk = AST.PrimFCall $ AST.FCall rising_edge [Nothing AST.:=>: (AST.ADName $ AST.NSimple clk)]
224     statement   = AST.IfSm rising_edge_clk [assign] [] Nothing
225
226 mkSigDec :: CoreSyn.CoreBndr -> VHDLState (Maybe AST.SigDec)
227 mkSigDec bndr =
228   if True then do --isInternalSigUse use || isStateSigUse use then do
229     type_mark <- vhdl_ty $ Var.varType bndr
230     return $ Just (AST.SigDec (bndrToVHDLId bndr) type_mark Nothing)
231   else
232     return Nothing
233
234 -- | Creates a VHDL Id from a named SignalInfo. Errors out if the SignalInfo
235 --   is not named.
236 getSignalId :: SignalInfo -> AST.VHDLId
237 getSignalId info =
238     mkVHDLExtId $ Maybe.fromMaybe
239       (error $ "Unnamed signal? This should not happen!")
240       (sigName info)
241
242 -- | Transforms a core binding into a VHDL concurrent statement
243 mkConcSm ::
244   (CoreSyn.CoreBndr, CoreSyn.CoreExpr) -- ^ The binding to process
245   -> VHDLState AST.ConcSm  -- ^ The corresponding VHDL component instantiation.
246
247 mkConcSm (bndr, app@(CoreSyn.App _ _))= do
248   signatures <- getA vsSignatures
249   funSignatures <- getA vsNameTable
250   let (CoreSyn.Var f, args) = CoreSyn.collectArgs app
251   case (Map.lookup (bndrToString f) funSignatures) of
252     Just funSignature ->
253       let
254         sigs = map (bndrToString.varBndr) args
255         sigsNames = map (\signal -> (AST.PrimName (AST.NSimple (mkVHDLExtId signal)))) sigs
256         func = (snd funSignature) sigsNames
257         src_wform = AST.Wform [AST.WformElem func Nothing]
258         dst_name = AST.NSimple (mkVHDLExtId (bndrToString bndr))
259         assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
260       in
261         return $ AST.CSSASm assign
262     Nothing ->
263       let  
264         signature = Maybe.fromMaybe 
265           (error $ "Using function '" ++ (bndrToString f) ++ "' without signature? This should not happen!") 
266           (Map.lookup (bndrToString f) signatures)
267         entity_id = ent_id signature
268         label = bndrToString bndr
269       -- Add a clk port if we have state
270       --clk_port = Maybe.fromJust $ mkAssocElem (Just $ mkVHDLExtId "clk") "clk"
271       --portmaps = mkAssocElems sigs args res signature ++ (if hasState hsfunc then [clk_port] else [])
272         portmaps = mkAssocElems args bndr signature
273       in
274         return $ AST.CSISm $ AST.CompInsSm (mkVHDLExtId label) (AST.IUEntity (AST.NSimple entity_id)) (AST.PMapAspect portmaps)
275
276 -- GHC generates some funny "r = r" bindings in let statements before
277 -- simplification. This outputs some dummy ConcSM for these, so things will at
278 -- least compile for now.
279 mkConcSm (bndr, CoreSyn.Var _) = return $ AST.CSPSm $ AST.ProcSm (mkVHDLBasicId "unused") [] []
280
281 {-
282 mkConcSm sigs (UncondDef src dst) _ = do
283   src_expr <- vhdl_expr src
284   let src_wform = AST.Wform [AST.WformElem src_expr Nothing]
285   let dst_name  = AST.NSimple (getSignalId $ signalInfo sigs dst)
286   let assign    = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
287   return $ AST.CSSASm assign
288   where
289     vhdl_expr (Left id) = return $ mkIdExpr sigs id
290     vhdl_expr (Right expr) =
291       case expr of
292         (EqLit id lit) ->
293           return $ (mkIdExpr sigs id) AST.:=: (AST.PrimLit lit)
294         (Literal lit Nothing) ->
295           return $ AST.PrimLit lit
296         (Literal lit (Just ty)) -> do
297           -- Create a cast expression, which is just a function call using the
298           -- type name as the function name.
299           let litexpr = AST.PrimLit lit
300           ty_id <- vhdl_ty ty
301           let ty_name = AST.NSimple ty_id
302           let args = [Nothing AST.:=>: (AST.ADExpr litexpr)] 
303           return $ AST.PrimFCall $ AST.FCall ty_name args
304         (Eq a b) ->
305          return $  (mkIdExpr sigs a) AST.:=: (mkIdExpr sigs b)
306
307 mkConcSm sigs (CondDef cond true false dst) _ =
308   let
309     cond_expr  = mkIdExpr sigs cond
310     true_expr  = mkIdExpr sigs true
311     false_expr  = mkIdExpr sigs false
312     false_wform = AST.Wform [AST.WformElem false_expr Nothing]
313     true_wform = AST.Wform [AST.WformElem true_expr Nothing]
314     whenelse = AST.WhenElse true_wform cond_expr
315     dst_name  = AST.NSimple (getSignalId $ signalInfo sigs dst)
316     assign    = dst_name AST.:<==: (AST.ConWforms [whenelse] false_wform Nothing)
317   in
318     return $ AST.CSSASm assign
319 -}
320 -- | Turn a SignalId into a VHDL Expr
321 mkIdExpr :: [(SignalId, SignalInfo)] -> SignalId -> AST.Expr
322 mkIdExpr sigs id =
323   let src_name  = AST.NSimple (getSignalId $ signalInfo sigs id) in
324   AST.PrimName src_name
325
326 mkAssocElems :: 
327   [CoreSyn.CoreExpr]            -- | The argument that are applied to function
328   -> CoreSyn.CoreBndr           -- | The binder in which to store the result
329   -> Entity                     -- | The entity to map against.
330   -> [AST.AssocElem]            -- | The resulting port maps
331
332 mkAssocElems args res entity =
333     -- Create the actual AssocElems
334     Maybe.catMaybes $ zipWith mkAssocElem ports sigs
335   where
336     -- Turn the ports and signals from a map into a flat list. This works,
337     -- since the maps must have an identical form by definition. TODO: Check
338     -- the similar form?
339     arg_ports = ent_args entity
340     res_port  = ent_res entity
341     -- Extract the id part from the (id, type) tuple
342     ports     = map (Monad.liftM fst) (res_port : arg_ports)
343     -- Translate signal numbers into names
344     sigs      = (bndrToString res : map (bndrToString.varBndr) args)
345
346 -- Turns a Var CoreExpr into the Id inside it. Will of course only work for
347 -- simple Var CoreExprs, not complexer ones.
348 varBndr :: CoreSyn.CoreExpr -> Var.Id
349 varBndr (CoreSyn.Var id) = id
350
351 -- | Look up a signal in the signal name map
352 lookupSigName :: [(SignalId, SignalInfo)] -> SignalId -> String
353 lookupSigName sigs sig = name
354   where
355     info = Maybe.fromMaybe
356       (error $ "Unknown signal " ++ (show sig) ++ " used? This should not happen!")
357       (lookup sig sigs)
358     name = Maybe.fromMaybe
359       (error $ "Unnamed signal " ++ (show sig) ++ " used? This should not happen!")
360       (sigName info)
361
362 -- | Create an VHDL port -> signal association
363 mkAssocElem :: Maybe AST.VHDLId -> String -> Maybe AST.AssocElem
364 mkAssocElem (Just port) signal = Just $ Just port AST.:=>: (AST.ADName (AST.NSimple (mkVHDLExtId signal))) 
365 mkAssocElem Nothing _ = Nothing
366
367 -- | The VHDL Bit type
368 bit_ty :: AST.TypeMark
369 bit_ty = AST.unsafeVHDLBasicId "Bit"
370
371 -- | The VHDL Boolean type
372 bool_ty :: AST.TypeMark
373 bool_ty = AST.unsafeVHDLBasicId "Boolean"
374
375 -- | The VHDL std_logic
376 std_logic_ty :: AST.TypeMark
377 std_logic_ty = AST.unsafeVHDLBasicId "std_logic"
378
379 -- Translate a Haskell type to a VHDL type
380 vhdl_ty :: Type.Type -> VHDLState AST.TypeMark
381 vhdl_ty ty = do
382   typemap <- getA vsTypes
383   let builtin_ty = do -- See if this is a tycon and lookup its name
384         (tycon, args) <- Type.splitTyConApp_maybe ty
385         let name = Name.getOccString (TyCon.tyConName tycon)
386         Map.lookup name builtin_types
387   -- If not a builtin type, try the custom types
388   let existing_ty = (fmap fst) $ Map.lookup (OrdType ty) typemap
389   case Monoid.getFirst $ Monoid.mconcat (map Monoid.First [builtin_ty, existing_ty]) of
390     -- Found a type, return it
391     Just t -> return t
392     -- No type yet, try to construct it
393     Nothing -> do
394       let new_ty = do
395             -- Use the Maybe Monad for failing when one of these fails
396             (tycon, args) <- Type.splitTyConApp_maybe ty
397             let name = Name.getOccString (TyCon.tyConName tycon)
398             case name of
399               "TFVec" -> Just $ mk_vector_ty (tfvec_len ty) ty
400               "SizedWord" -> Just $ mk_vector_ty (sized_word_len ty) ty
401               otherwise -> Nothing
402       -- Return new_ty when a new type was successfully created
403       Maybe.fromMaybe 
404         (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty))
405         new_ty
406
407 -- | Create a VHDL vector type
408 mk_vector_ty ::
409   Int -- ^ The length of the vector
410   -> Type.Type -- ^ The Haskell type to create a VHDL type for
411   -> VHDLState AST.TypeMark -- The typemark created.
412
413 mk_vector_ty len ty = do
414   -- Assume there is a single type argument
415   let ty_id = mkVHDLExtId $ "vector_" ++ (show len)
416   -- TODO: Use el_ty
417   let range = AST.IndexConstraint [AST.ToRange (AST.PrimLit "0") (AST.PrimLit $ show (len - 1))]
418   let ty_def = AST.TDA $ AST.ConsArrayDef range std_logic_ty
419   let ty_dec = AST.TypeDec ty_id ty_def
420   -- TODO: Check name uniqueness
421   --State.modify (Map.insert (OrdType ty) (ty_id, ty_dec))
422   modA vsTypes (Map.insert (OrdType ty) (ty_id, ty_dec))
423   modA vsTypeFuns (Map.insert (OrdType ty) (genUnconsVectorFuns std_logic_ty ty_id))
424   return ty_id
425
426
427 builtin_types = 
428   Map.fromList [
429     ("Bit", std_logic_ty),
430     ("Bool", bool_ty) -- TysWiredIn.boolTy
431   ]
432
433 -- Shortcut for 
434 -- Can only contain alphanumerics and underscores. The supplied string must be
435 -- a valid basic id, otherwise an error value is returned. This function is
436 -- not meant to be passed identifiers from a source file, use mkVHDLExtId for
437 -- that.
438 mkVHDLBasicId :: String -> AST.VHDLId
439 mkVHDLBasicId s = 
440   AST.unsafeVHDLBasicId $ (strip_multiscore . strip_leading . strip_invalid) s
441   where
442     -- Strip invalid characters.
443     strip_invalid = filter (`elem` ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ "_.")
444     -- Strip leading numbers and underscores
445     strip_leading = dropWhile (`elem` ['0'..'9'] ++ "_")
446     -- Strip multiple adjacent underscores
447     strip_multiscore = concat . map (\cs -> 
448         case cs of 
449           ('_':_) -> "_"
450           _ -> cs
451       ) . List.group
452
453 -- Shortcut for Extended VHDL Id's. These Id's can contain a lot more
454 -- different characters than basic ids, but can never be used to refer to
455 -- basic ids.
456 -- Use extended Ids for any values that are taken from the source file.
457 mkVHDLExtId :: String -> AST.VHDLId
458 mkVHDLExtId s = 
459   AST.unsafeVHDLExtId $ strip_invalid s
460   where 
461     -- Allowed characters, taken from ForSyde's mkVHDLExtId
462     allowed = ['A'..'Z'] ++ ['a'..'z'] ++ ['0'..'9'] ++ " \"#&\\'()*+,./:;<=>_|!$%@?[]^`{}~-"
463     strip_invalid = filter (`elem` allowed)
464
465 -- Creates a VHDL Id from a binder
466 bndrToVHDLId ::
467   CoreSyn.CoreBndr
468   -> AST.VHDLId
469
470 bndrToVHDLId = mkVHDLExtId . OccName.occNameString . Name.nameOccName . Var.varName
471
472 -- Extracts the binder name as a String
473 bndrToString ::
474   CoreSyn.CoreBndr
475   -> String
476
477 bndrToString = OccName.occNameString . Name.nameOccName . Var.varName
478
479 -- | A consise representation of a (set of) ports on a builtin function
480 --type PortMap = HsValueMap (String, AST.TypeMark)
481 -- | A consise representation of a builtin function
482 data BuiltIn = BuiltIn String [(String, AST.TypeMark)] (String, AST.TypeMark)
483
484 -- | Translate a list of concise representation of builtin functions to a
485 --   SignatureMap
486 mkBuiltins :: [BuiltIn] -> SignatureMap
487 mkBuiltins = Map.fromList . map (\(BuiltIn name args res) ->
488     (name,
489      Entity (VHDL.mkVHDLBasicId name) (map toVHDLSignalMapElement args) (toVHDLSignalMapElement res))
490   )
491
492 builtin_hsfuncs = Map.keys builtin_funcs
493 builtin_funcs = mkBuiltins
494   [ 
495     BuiltIn "hwxor" [("a", VHDL.bit_ty), ("b", VHDL.bit_ty)] ("o", VHDL.bit_ty),
496     BuiltIn "hwand" [("a", VHDL.bit_ty), ("b", VHDL.bit_ty)] ("o", VHDL.bit_ty),
497     BuiltIn "hwor" [("a", VHDL.bit_ty), ("b", VHDL.bit_ty)] ("o", VHDL.bit_ty),
498     BuiltIn "hwnot" [("a", VHDL.bit_ty)] ("o", VHDL.bit_ty)
499   ]
500
501 -- | Map a port specification of a builtin function to a VHDL Signal to put in
502 --   a VHDLSignalMap
503 toVHDLSignalMapElement :: (String, AST.TypeMark) -> VHDLSignalMapElement
504 toVHDLSignalMapElement (name, ty) = Just (mkVHDLBasicId name, ty)