Allow variables to be bound to complex expressions.
[matthijs/master-project/cλash.git] / Translator.hs
1 module Main(main) where
2 import GHC
3 import CoreSyn
4 import qualified CoreUtils
5 import qualified Var
6 import qualified Type
7 import qualified TyCon
8 import qualified DataCon
9 import qualified Maybe
10 import qualified Module
11 import qualified Control.Monad.State as State
12 import Name
13 import Data.Generics
14 import NameEnv ( lookupNameEnv )
15 import HscTypes ( cm_binds, cm_types )
16 import MonadUtils ( liftIO )
17 import Outputable ( showSDoc, ppr )
18 import GHC.Paths ( libdir )
19 import DynFlags ( defaultDynFlags )
20 import List ( find )
21 import qualified List
22 import qualified Monad
23
24 -- The following modules come from the ForSyDe project. They are really
25 -- internal modules, so ForSyDe.cabal has to be modified prior to installing
26 -- ForSyDe to get access to these modules.
27 import qualified ForSyDe.Backend.VHDL.AST as AST
28 import qualified ForSyDe.Backend.VHDL.Ppr
29 import qualified ForSyDe.Backend.VHDL.FileIO
30 import qualified ForSyDe.Backend.Ppr
31 -- This is needed for rendering the pretty printed VHDL
32 import Text.PrettyPrint.HughesPJ (render)
33
34 main = 
35     do
36       defaultErrorHandler defaultDynFlags $ do
37         runGhc (Just libdir) $ do
38           dflags <- getSessionDynFlags
39           setSessionDynFlags dflags
40           --target <- guessTarget "adder.hs" Nothing
41           --liftIO (print (showSDoc (ppr (target))))
42           --liftIO $ printTarget target
43           --setTargets [target]
44           --load LoadAllTargets
45           --core <- GHC.compileToCoreSimplified "Adders.hs"
46           core <- GHC.compileToCoreSimplified "Adders.hs"
47           --liftIO $ printBinds (cm_binds core)
48           let binds = Maybe.mapMaybe (findBind (cm_binds core)) ["shalf_adder"]
49           liftIO $ printBinds binds
50           -- Turn bind into VHDL
51           let vhdl = State.evalState (mkVHDL binds) (VHDLSession 0 [])
52           liftIO $ putStr $ render $ ForSyDe.Backend.Ppr.ppr vhdl
53           liftIO $ ForSyDe.Backend.VHDL.FileIO.writeDesignFile vhdl "../vhdl/vhdl/output.vhdl"
54           return ()
55   where
56     -- Turns the given bind into VHDL
57     mkVHDL binds = do
58       -- Add the builtin functions
59       mapM (uncurry addFunc) builtin_funcs
60       -- Create entities and architectures for them
61       units <- mapM expandBind binds
62       return $ AST.DesignFile 
63         []
64         (concat units)
65
66 printTarget (Target (TargetFile file (Just x)) obj Nothing) =
67   print $ show file
68
69 printBinds [] = putStr "done\n\n"
70 printBinds (b:bs) = do
71   printBind b
72   putStr "\n"
73   printBinds bs
74
75 printBind (NonRec b expr) = do
76   putStr "NonRec: "
77   printBind' (b, expr)
78
79 printBind (Rec binds) = do
80   putStr "Rec: \n"  
81   foldl1 (>>) (map printBind' binds)
82
83 printBind' (b, expr) = do
84   putStr $ getOccString b
85   putStr $ showSDoc $ ppr expr
86   putStr "\n"
87
88 findBind :: [CoreBind] -> String -> Maybe CoreBind
89 findBind binds lookfor =
90   -- This ignores Recs and compares the name of the bind with lookfor,
91   -- disregarding any namespaces in OccName and extra attributes in Name and
92   -- Var.
93   find (\b -> case b of 
94     Rec l -> False
95     NonRec var _ -> lookfor == (occNameString $ nameOccName $ getName var)
96   ) binds
97
98 getPortMapEntry ::
99   SignalNameMap  -- The port name to bind to
100   -> SignalNameMap 
101                             -- The signal or port to bind to it
102   -> AST.AssocElem          -- The resulting port map entry
103   
104 -- Accepts a port name and an argument to map to it.
105 -- Returns the appropriate line for in the port map
106 getPortMapEntry (Single (portname, _)) (Single (signame, _)) = 
107   (Just portname) AST.:=>: (AST.ADName (AST.NSimple signame))
108 expandExpr ::
109   [(CoreBndr, SignalNameMap)] 
110                                          -- A list of bindings in effect
111   -> CoreExpr                            -- The expression to expand
112   -> VHDLState (
113        [AST.SigDec],                     -- Needed signal declarations
114        [AST.ConcSm],                     -- Needed component instantations and
115                                          -- signal assignments.
116        [SignalNameMap],       -- The signal names corresponding to
117                                          -- the expression's arguments
118        SignalNameMap)         -- The signal names corresponding to
119                                          -- the expression's result.
120 expandExpr binds lam@(Lam b expr) = do
121   -- Generate a new signal to which we will expect this argument to be bound.
122   signal_name <- uniqueName ("arg_" ++ getOccString b)
123   -- Find the type of the binder
124   let (arg_ty, _) = Type.splitFunTy (CoreUtils.exprType lam)
125   -- Create signal names for the binder
126   let arg_signal = getPortNameMapForTy ("xxx") arg_ty
127   -- Create the corresponding signal declarations
128   let signal_decls = mkSignalsFromMap arg_signal
129   -- Add the binder to the list of binds
130   let binds' = (b, arg_signal) : binds
131   -- Expand the rest of the expression
132   (signal_decls', statements', arg_signals', res_signal') <- expandExpr binds' expr
133   -- Properly merge the results
134   return (signal_decls ++ signal_decls',
135           statements',
136           arg_signal : arg_signals',
137           res_signal')
138
139 expandExpr binds (Var id) =
140   return ([], [], [], bind)
141   where
142     -- Lookup the id in our binds map
143     bind = Maybe.fromMaybe
144       (error $ "Argument " ++ getOccString id ++ "is unknown")
145       (lookup id binds)
146
147 expandExpr binds l@(Let (NonRec b bexpr) expr) = do
148   (signal_decls, statements, arg_signals, res_signals) <- expandExpr binds bexpr
149   let binds' = (b, res_signals) : binds
150   (signal_decls', statements', arg_signals', res_signals') <- expandExpr binds' expr
151   return (
152     signal_decls ++ signal_decls',
153     statements ++ statements',
154     arg_signals',
155     res_signals')
156
157 expandExpr binds app@(App _ _) = do
158   -- Is this a data constructor application?
159   case CoreUtils.exprIsConApp_maybe app of
160     -- Is this a tuple construction?
161     Just (dc, args) -> if DataCon.isTupleCon dc 
162       then
163         expandBuildTupleExpr binds (dataConAppArgs dc args)
164       else
165         error "Data constructors other than tuples not supported"
166     otherise ->
167       -- Normal function application, should map to a component instantiation
168       let ((Var f), args) = collectArgs app in
169       expandApplicationExpr binds (CoreUtils.exprType app) f args
170
171 expandExpr binds expr@(Case (Var v) b _ alts) =
172   case alts of
173     [alt] -> expandSingleAltCaseExpr binds v b alt
174     otherwise -> error $ "Multiple alternative case expression not supported: " ++ (showSDoc $ ppr expr)
175
176 expandExpr binds expr@(Case _ b _ _) =
177   error $ "Case expression with non-variable scrutinee not supported: " ++ (showSDoc $ ppr expr)
178
179 expandExpr binds expr = 
180   error $ "Unsupported expression: " ++ (showSDoc $ ppr $ expr)
181
182 -- Expands the construction of a tuple into VHDL
183 expandBuildTupleExpr ::
184   [(CoreBndr, SignalNameMap)] 
185                                          -- A list of bindings in effect
186   -> [CoreExpr]                          -- A list of expressions to put in the tuple
187   -> VHDLState ( [AST.SigDec], [AST.ConcSm], [SignalNameMap], SignalNameMap)
188                                          -- See expandExpr
189 expandBuildTupleExpr binds args = do
190   -- Split the tuple constructor arguments into types and actual values.
191   -- Expand each of the values in the tuple
192   (signals_declss, statementss, arg_signalss, res_signals) <-
193     (Monad.liftM List.unzip4) $ mapM (expandExpr binds) args
194   if any (not . null) arg_signalss
195     then error "Putting high order functions in tuples not supported"
196     else
197       return (
198         concat signals_declss,
199         concat statementss,
200         [],
201         Tuple res_signals)
202
203 -- Expands the most simple case expression that scrutinizes a plain variable
204 -- and has a single alternative. This simple form currently allows only for
205 -- unpacking tuple variables.
206 expandSingleAltCaseExpr ::
207   [(CoreBndr, SignalNameMap)] 
208                             -- A list of bindings in effect
209   -> Var.Var                -- The scrutinee
210   -> CoreBndr               -- The binder to bind the scrutinee to
211   -> CoreAlt                -- The single alternative
212   -> VHDLState ( [AST.SigDec], [AST.ConcSm], [SignalNameMap], SignalNameMap)
213                                          -- See expandExpr
214
215 expandSingleAltCaseExpr binds v b alt@(DataAlt datacon, bind_vars, expr) =
216   if not (DataCon.isTupleCon datacon) 
217     then
218       error $ "Dataconstructors other than tuple constructors not supported in case pattern of alternative: " ++ (showSDoc $ ppr alt)
219     else
220       let
221         -- Lookup the scrutinee (which must be a variable bound to a tuple) in
222         -- the existing bindings list and get the portname map for each of
223         -- it's elements.
224         Tuple tuple_ports = Maybe.fromMaybe 
225           (error $ "Case expression uses unknown scrutinee " ++ getOccString v)
226           (lookup v binds)
227         -- TODO include b in the binds list
228         -- Merge our existing binds with the new binds.
229         binds' = (zip bind_vars tuple_ports) ++ binds 
230       in
231         -- Expand the expression with the new binds list
232         expandExpr binds' expr
233
234 expandSingleAltCaseExpr _ _ _ alt =
235   error $ "Case patterns other than data constructors not supported in case alternative: " ++ (showSDoc $ ppr alt)
236       
237
238 -- Expands the application of argument to a function into VHDL
239 expandApplicationExpr ::
240   [(CoreBndr, SignalNameMap)] 
241                                          -- A list of bindings in effect
242   -> Type                                -- The result type of the function call
243   -> Var.Var                             -- The function to call
244   -> [CoreExpr]                          -- A list of argumetns to apply to the function
245   -> VHDLState ( [AST.SigDec], [AST.ConcSm], [SignalNameMap], SignalNameMap)
246                                          -- See expandExpr
247 expandApplicationExpr binds ty f args = do
248   let name = getOccString f
249   -- Generate a unique name for the application
250   appname <- uniqueName ("app_" ++ name)
251   -- Lookup the hwfunction to instantiate
252   HWFunction vhdl_id inports outport <- getHWFunc (appToHsFunction f args ty)
253   -- Expand each of the args, so each of them is reduced to output signals
254   (arg_signal_decls, arg_statements, arg_res_signals) <- expandArgs binds args
255   -- Bind each of the input ports to the expanded arguments
256   let inmaps = concat $ zipWith createAssocElems inports arg_res_signals
257   -- Create signal names for our result
258   let res_signal = getPortNameMapForTy (appname ++ "_out") ty
259   -- Create the corresponding signal declarations
260   let signal_decls = mkSignalsFromMap res_signal
261   -- Bind each of the output ports to our output signals
262   let outmaps = mapOutputPorts outport res_signal
263   -- Instantiate the component
264   let component = AST.CSISm $ AST.CompInsSm
265         (AST.unsafeVHDLBasicId appname)
266         (AST.IUEntity (AST.NSimple vhdl_id))
267         (AST.PMapAspect (inmaps ++ outmaps))
268   -- Merge the generated declarations
269   return (
270     signal_decls ++ arg_signal_decls,
271     component : arg_statements,
272     [], -- We don't take any extra arguments; we don't support higher order functions yet
273     res_signal)
274   
275 -- Creates a list of AssocElems (port map lines) that maps the given signals
276 -- to the given ports.
277 createAssocElems ::
278   SignalNameMap      -- The port names to bind to
279   -> SignalNameMap   -- The signals to bind to it
280   -> [AST.AssocElem]            -- The resulting port map lines
281   
282 createAssocElems (Single (port_id, _)) (Single (signal_id, _)) = 
283   [(Just port_id) AST.:=>: (AST.ADName (AST.NSimple signal_id))]
284
285 createAssocElems (Tuple ports) (Tuple signals) = 
286   concat $ zipWith createAssocElems ports signals
287
288 -- Generate a signal declaration for a signal with the given name and the
289 -- given type and no value. Also returns the id of the signal.
290 mkSignal :: String -> AST.TypeMark -> (AST.VHDLId, AST.SigDec)
291 mkSignal name ty =
292   (id, mkSignalFromId id ty)
293   where 
294     id = AST.unsafeVHDLBasicId name
295
296 mkSignalFromId :: AST.VHDLId -> AST.TypeMark -> AST.SigDec
297 mkSignalFromId id ty =
298   AST.SigDec id ty Nothing
299
300 -- Generates signal declarations for all the signals in the given map
301 mkSignalsFromMap ::
302   SignalNameMap 
303   -> [AST.SigDec]
304
305 mkSignalsFromMap (Single (id, ty)) =
306   [mkSignalFromId id ty]
307
308 mkSignalsFromMap (Tuple signals) =
309   concat $ map mkSignalsFromMap signals
310
311 expandArgs :: 
312   [(CoreBndr, SignalNameMap)] -- A list of bindings in effect
313   -> [CoreExpr]                          -- The arguments to expand
314   -> VHDLState ([AST.SigDec], [AST.ConcSm], [SignalNameMap])  
315                                          -- The resulting signal declarations,
316                                          -- component instantiations and a
317                                          -- VHDLName for each of the
318                                          -- expressions passed in.
319 expandArgs binds (e:exprs) = do
320   -- Expand the first expression
321   (signal_decls, statements, arg_signals, res_signal) <- expandExpr binds e
322   if not (null arg_signals)
323     then error $ "Passing functions as arguments not supported: " ++ (showSDoc $ ppr e)
324     else do
325       (signal_decls', statements', res_signals') <- expandArgs binds exprs
326       return (
327         signal_decls ++ signal_decls',
328         statements ++ statements',
329         res_signal : res_signals')
330
331 expandArgs _ [] = return ([], [], [])
332
333 -- Extract the arguments from a data constructor application (that is, the
334 -- normal args, leaving out the type args).
335 dataConAppArgs :: DataCon -> [CoreExpr] -> [CoreExpr]
336 dataConAppArgs dc args =
337     drop tycount args
338   where
339     tycount = length $ DataCon.dataConAllTyVars dc
340
341 mapOutputPorts ::
342   SignalNameMap      -- The output portnames of the component
343   -> SignalNameMap   -- The output portnames and/or signals to map these to
344   -> [AST.AssocElem]            -- The resulting output ports
345
346 -- Map the output port of a component to the output port of the containing
347 -- entity.
348 mapOutputPorts (Single (portname, _)) (Single (signalname, _)) =
349   [(Just portname) AST.:=>: (AST.ADName (AST.NSimple signalname))]
350
351 -- Map matching output ports in the tuple
352 mapOutputPorts (Tuple ports) (Tuple signals) =
353   concat (zipWith mapOutputPorts ports signals)
354
355 expandBind ::
356   CoreBind                        -- The binder to expand into VHDL
357   -> VHDLState [AST.LibraryUnit]  -- The resulting VHDL
358
359 expandBind (Rec _) = error "Recursive binders not supported"
360
361 expandBind bind@(NonRec var expr) = do
362   -- Create the function signature
363   hwfunc <- mkHWFunction bind
364   let ty = CoreUtils.exprType expr
365   let hsfunc = mkHsFunction var ty
366   -- Add it to the session
367   addFunc hsfunc hwfunc 
368   arch <- getArchitecture hwfunc expr
369   let entity = getEntity hwfunc
370   return $ [
371     AST.LUEntity entity,
372     AST.LUArch arch ]
373
374 getArchitecture ::
375   HWFunction                -- The function to generate an architecture for
376   -> CoreExpr               -- The expression that is bound to the function
377   -> VHDLState AST.ArchBody -- The resulting architecture
378    
379 getArchitecture hwfunc expr = do
380   -- Unpack our hwfunc
381   let HWFunction vhdl_id inports outport = hwfunc
382   -- Expand the expression into an architecture body
383   (signal_decls, statements, arg_signals, res_signal) <- expandExpr [] expr
384   let inport_assigns = concat $ zipWith createSignalAssignments arg_signals inports
385   let outport_assigns = createSignalAssignments outport res_signal
386   return $ AST.ArchBody
387     (AST.unsafeVHDLBasicId "structural")
388     (AST.NSimple vhdl_id)
389     (map AST.BDISD signal_decls)
390     (inport_assigns ++ outport_assigns ++ statements)
391
392 -- Generate a VHDL entity declaration for the given function
393 getEntity :: HWFunction -> AST.EntityDec  
394 getEntity (HWFunction vhdl_id inports outport) = 
395   AST.EntityDec vhdl_id ports
396   where
397     ports = 
398       (concat $ map (mkIfaceSigDecs AST.In) inports)
399       ++ mkIfaceSigDecs AST.Out outport
400
401 mkIfaceSigDecs ::
402   AST.Mode                        -- The port's mode (In or Out)
403   -> SignalNameMap        -- The ports to generate a map for
404   -> [AST.IfaceSigDec]            -- The resulting ports
405   
406 mkIfaceSigDecs mode (Single (port_id, ty)) =
407   [AST.IfaceSigDec port_id mode ty]
408
409 mkIfaceSigDecs mode (Tuple ports) =
410   concat $ map (mkIfaceSigDecs mode) ports
411
412 -- Create concurrent assignments of one map of signals to another. The maps
413 -- should have a similar form.
414 createSignalAssignments ::
415   SignalNameMap         -- The signals to assign to
416   -> SignalNameMap      -- The signals to assign
417   -> [AST.ConcSm]                  -- The resulting assignments
418
419 -- A simple assignment of one signal to another (greatly complicated because
420 -- signal assignments can be conditional with multiple conditions in VHDL).
421 createSignalAssignments (Single (dst, _)) (Single (src, _)) =
422     [AST.CSSASm assign]
423   where
424     src_name  = AST.NSimple src
425     src_expr  = AST.PrimName src_name
426     src_wform = AST.Wform [AST.WformElem src_expr Nothing]
427     dst_name  = (AST.NSimple dst)
428     assign    = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
429
430 createSignalAssignments (Tuple dsts) (Tuple srcs) =
431   concat $ zipWith createSignalAssignments dsts srcs
432
433 createSignalAssignments dst src =
434   error $ "Non matching source and destination: " ++ show dst ++ "\nand\n" ++  show src
435
436 type SignalNameMap = HsValueMap (AST.VHDLId, AST.TypeMark)
437
438 -- | A datatype that maps each of the single values in a haskell structure to
439 -- a mapto. The map has the same structure as the haskell type mapped, ie
440 -- nested tuples etc.
441 data HsValueMap mapto =
442   Tuple [HsValueMap mapto]
443   | Single mapto
444   deriving (Show, Eq)
445
446 -- | Creates a HsValueMap with the same structure as the given type, using the
447 --   given function for mapping the single types.
448 mkHsValueMap ::
449   (Type -> HsValueMap mapto)    -- ^ A function to map single value Types
450                                 --   (basically anything but tuples) to a
451                                 --   HsValueMap (not limited to the Single
452                                 --   constructor)
453   -> Type                       -- ^ The type to map to a HsValueMap
454   -> HsValueMap mapto           -- ^ The resulting map
455
456 mkHsValueMap f ty =
457   case Type.splitTyConApp_maybe ty of
458     Just (tycon, args) ->
459       if (TyCon.isTupleTyCon tycon) 
460         then
461           -- Handle tuple construction especially
462           Tuple (map (mkHsValueMap f) args)
463         else
464           -- And let f handle the rest
465           f ty
466     -- And let f handle the rest
467     Nothing -> f ty
468
469 -- Generate a port name map (or multiple for tuple types) in the given direction for
470 -- each type given.
471 getPortNameMapForTys :: String -> Int -> [Type] -> [SignalNameMap]
472 getPortNameMapForTys prefix num [] = [] 
473 getPortNameMapForTys prefix num (t:ts) =
474   (getPortNameMapForTy (prefix ++ show num) t) : getPortNameMapForTys prefix (num + 1) ts
475
476 getPortNameMapForTy :: String -> Type -> SignalNameMap
477 getPortNameMapForTy name ty =
478   if (TyCon.isTupleTyCon tycon) then
479     -- Expand tuples we find
480     Tuple (getPortNameMapForTys name 0 args)
481   else -- Assume it's a type constructor application, ie simple data type
482     Single ((AST.unsafeVHDLBasicId name), (vhdl_ty ty))
483   where
484     (tycon, args) = Type.splitTyConApp ty 
485
486 data HWFunction = HWFunction { -- A function that is available in hardware
487   vhdlId    :: AST.VHDLId,
488   inPorts   :: [SignalNameMap],
489   outPort   :: SignalNameMap
490   --entity    :: AST.EntityDec
491 } deriving (Show)
492
493 -- Turns a CoreExpr describing a function into a description of its input and
494 -- output ports.
495 mkHWFunction ::
496   CoreBind                                   -- The core binder to generate the interface for
497   -> VHDLState HWFunction                    -- The function interface
498
499 mkHWFunction (NonRec var expr) =
500     return $ HWFunction (mkVHDLId name) inports outport
501   where
502     name = getOccString var
503     ty = CoreUtils.exprType expr
504     (fargs, res) = Type.splitFunTys ty
505     args = if length fargs == 1 then fargs else (init fargs)
506     --state = if length fargs == 1 then () else (last fargs)
507     inports = case args of
508       -- Handle a single port specially, to prevent an extra 0 in the name
509       [port] -> [getPortNameMapForTy "portin" port]
510       ps     -> getPortNameMapForTys "portin" 0 ps
511     outport = getPortNameMapForTy "portout" res
512
513 mkHWFunction (Rec _) =
514   error "Recursive binders not supported"
515
516 -- | How is a given (single) value in a function's type (ie, argument or
517 -- return value) used?
518 data HsValueUse = 
519   Port -- ^ Use it as a port (input or output)
520   | State --- ^ Use it as state (input or output)
521   deriving (Show, Eq)
522
523 -- | This type describes a particular use of a Haskell function and is used to
524 --   look up an appropriate hardware description.  
525 data HsFunction = HsFunction {
526   hsName :: String,                      -- ^ What was the name of the original Haskell function?
527   hsArgs :: [HsValueMap HsValueUse],     -- ^ How are the arguments used?
528   hsRes  :: HsValueMap HsValueUse        -- ^ How is the result value used?
529 } deriving (Show, Eq)
530
531 -- | Translate a function application to a HsFunction. i.e., which function
532 --   do you need to translate this function application.
533 appToHsFunction ::
534   Var.Var         -- ^ The function to call
535   -> [CoreExpr]   -- ^ The function arguments
536   -> Type         -- ^ The return type
537   -> HsFunction   -- ^ The needed HsFunction
538
539 appToHsFunction f args ty =
540   HsFunction hsname hsargs hsres
541   where
542     mkPort = \x -> Single Port
543     hsargs = map (mkHsValueMap mkPort . CoreUtils.exprType) args
544     hsres  = mkHsValueMap mkPort ty
545     hsname = getOccString f
546
547 -- | Translate a top level function declaration to a HsFunction. i.e., which
548 --   interface will be provided by this function. This function essentially
549 --   defines the "calling convention" for hardware models.
550 mkHsFunction ::
551   Var.Var         -- ^ The function defined
552   -> Type         -- ^ The function type (including arguments!)
553   -> HsFunction   -- ^ The resulting HsFunction
554
555 mkHsFunction f ty =
556   HsFunction hsname hsargs hsres
557   where
558     mkPort = mkHsValueMap (\x -> Single Port)
559     mkState = mkHsValueMap (\x -> Single State)
560     hsname  = getOccString f
561     (arg_tys, res_ty) = Type.splitFunTys ty
562     -- The last argument must be state
563     state_ty = last arg_tys
564     state    = mkState state_ty
565     -- All but the last argument are inports
566     inports = map mkPort (init arg_tys)
567     hsargs   = inports ++ [state]
568     hsres    = case splitTupleType res_ty of
569       -- Result type must be a two tuple (state, ports)
570       Just [outstate_ty, outport_ty] -> if Type.coreEqType state_ty outstate_ty
571         then
572           Tuple [state, mkPort outport_ty]
573         else
574           error $ "Input state type of function " ++ hsname ++ ": " ++ (showSDoc $ ppr state_ty) ++ " does not match output state type: " ++ (showSDoc $ ppr outstate_ty)
575       otherwise                -> error $ "Return type of top-level function " ++ hsname ++ " must be a two-tuple containing a state and output ports."
576
577 data VHDLSession = VHDLSession {
578   nameCount :: Int,                       -- A counter that can be used to generate unique names
579   funcs     :: [(HsFunction, HWFunction)] -- All functions available
580 } deriving (Show)
581
582 type VHDLState = State.State VHDLSession
583
584 -- Add the function to the session
585 addFunc :: HsFunction -> HWFunction -> VHDLState ()
586 addFunc hsfunc hwfunc = do
587   fs <- State.gets funcs -- Get the funcs element from the session
588   State.modify (\x -> x {funcs = (hsfunc, hwfunc) : fs }) -- Prepend name and f
589
590 -- Lookup the function with the given name in the current session. Errors if
591 -- it was not found.
592 getHWFunc :: HsFunction -> VHDLState HWFunction
593 getHWFunc hsfunc = do
594   fs <- State.gets funcs -- Get the funcs element from the session
595   return $ Maybe.fromMaybe
596     (error $ "Function " ++ (hsName hsfunc) ++ "is unknown? This should not happen!")
597     (lookup hsfunc fs)
598
599 -- | Splits a tuple type into a list of element types, or Nothing if the type
600 --   is not a tuple type.
601 splitTupleType ::
602   Type              -- ^ The type to split
603   -> Maybe [Type]   -- ^ The tuples element types
604
605 splitTupleType ty =
606   case Type.splitTyConApp_maybe ty of
607     Just (tycon, args) -> if TyCon.isTupleTyCon tycon 
608       then
609         Just args
610       else
611         Nothing
612     Nothing -> Nothing
613
614 -- Makes the given name unique by appending a unique number.
615 -- This does not do any checking against existing names, so it only guarantees
616 -- uniqueness with other names generated by uniqueName.
617 uniqueName :: String -> VHDLState String
618 uniqueName name = do
619   count <- State.gets nameCount -- Get the funcs element from the session
620   State.modify (\s -> s {nameCount = count + 1})
621   return $ name ++ "_" ++ (show count)
622
623 -- Shortcut
624 mkVHDLId :: String -> AST.VHDLId
625 mkVHDLId = AST.unsafeVHDLBasicId
626
627 builtin_funcs = 
628   [ 
629     (HsFunction "hwxor" [(Single Port), (Single Port)] (Single Port), HWFunction (mkVHDLId "hwxor") [Single (mkVHDLId "a", vhdl_bit_ty), Single (mkVHDLId "b", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty))),
630     (HsFunction "hwand" [(Single Port), (Single Port)] (Single Port), HWFunction (mkVHDLId "hwand") [Single (mkVHDLId "a", vhdl_bit_ty), Single (mkVHDLId "b", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty))),
631     (HsFunction "hwor" [(Single Port), (Single Port)] (Single Port), HWFunction (mkVHDLId "hwor") [Single (mkVHDLId "a", vhdl_bit_ty), Single (mkVHDLId "b", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty))),
632     (HsFunction "hwnot" [(Single Port)] (Single Port), HWFunction (mkVHDLId "hwnot") [Single (mkVHDLId "i", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty)))
633   ]
634
635 vhdl_bit_ty :: AST.TypeMark
636 vhdl_bit_ty = AST.unsafeVHDLBasicId "Bit"
637
638 -- Translate a Haskell type to a VHDL type
639 vhdl_ty :: Type -> AST.TypeMark
640 vhdl_ty ty = Maybe.fromMaybe
641   (error $ "Unsupported Haskell type: " ++ (showSDoc $ ppr ty))
642   (vhdl_ty_maybe ty)
643
644 -- Translate a Haskell type to a VHDL type
645 vhdl_ty_maybe :: Type -> Maybe AST.TypeMark
646 vhdl_ty_maybe ty =
647   case Type.splitTyConApp_maybe ty of
648     Just (tycon, args) ->
649       let name = TyCon.tyConName tycon in
650         -- TODO: Do something more robust than string matching
651         case getOccString name of
652           "Bit"      -> Just vhdl_bit_ty
653           otherwise  -> Nothing
654     otherwise -> Nothing
655
656 -- vim: set ts=8 sw=2 sts=2 expandtab: