Put getInstantiations in the State monad.
[matthijs/master-project/cλash.git] / Translator.hs
index 1b2d24bf13aac610423c22983bd18373519c36ff..64e009e79db6ec6460dd88cbf45b2035a352c79e 100644 (file)
@@ -8,6 +8,7 @@ import qualified TyCon
 import qualified DataCon
 import qualified Maybe
 import qualified Module
+import qualified Control.Monad.State as State
 import Name
 import Data.Generics
 import NameEnv ( lookupNameEnv )
@@ -42,11 +43,21 @@ main =
                                        liftIO $ printBinds (cm_binds core)
                                        let bind = findBind "half_adder" (cm_binds core)
                                        let NonRec var expr = bind
-                                       let sess = VHDLSession 0 builtin_funcs
+                                       -- Turn bind into VHDL
+                                       let vhdl = State.evalState (mkVHDL bind) (VHDLSession 0 builtin_funcs)
                                        liftIO $ putStr $ showSDoc $ ppr expr
                                        liftIO $ putStr "\n\n"
-                                       liftIO $ putStr $ render $ ForSyDe.Backend.Ppr.ppr $ getArchitecture sess bind
+                                       liftIO $ putStr $ render $ ForSyDe.Backend.Ppr.ppr $ vhdl
                                        return expr
+       where
+               -- Turns the given bind into VHDL
+               mkVHDL bind = do
+                       -- Get the function signature
+                       (name, f) <- mkHWFunction bind
+                       -- Add it to the session
+                       addFunc name f
+                       arch <- getArchitecture bind
+                       return arch
 
 printTarget (Target (TargetFile file (Just x)) obj Nothing) =
        print $ show file
@@ -82,7 +93,7 @@ findBind lookfor =
 
 -- Accepts a port name and an argument to map to it.
 -- Returns the appropriate line for in the port map
-getPortMapEntry binds portname (Var id) = 
+getPortMapEntry binds (Port portname) (Var id) = 
        (Just (AST.unsafeVHDLBasicId portname)) AST.:=>: (AST.ADName (AST.NSimple (AST.unsafeVHDLBasicId signalname)))
        where
                Port signalname = Maybe.fromMaybe
@@ -92,26 +103,24 @@ getPortMapEntry binds portname (Var id) =
 getPortMapEntry binds _ a = error $ "Unsupported argument: " ++ (showSDoc $ ppr a)
 
 getInstantiations ::
-       VHDLSession
-       -> PortNameMap                  -- The arguments that need to be applied to the
-                                                                                                                        -- expression. Should always be the Args
-                                                                                                                        -- constructor.
+       [PortNameMap]                -- The arguments that need to be applied to the
+                                                                                                                        -- expression.
        -> PortNameMap               -- The output ports that the expression should generate.
        -> [(CoreBndr, PortNameMap)] -- A list of bindings in effect
        -> CoreSyn.CoreExpr          -- The expression to generate an architecture for
-       -> [AST.ConcSm]              -- The resulting VHDL code
+       -> VHDLState [AST.ConcSm]    -- The resulting VHDL code
 
 -- A lambda expression binds the first argument (a) to the binder b.
-getInstantiations sess (Args (a:as)) outs binds (Lam b expr) =
-       getInstantiations sess (Args as) outs ((b, a):binds) expr
+getInstantiations (a:as) outs binds (Lam b expr) =
+       getInstantiations as outs ((b, a):binds) expr
 
 -- A case expression that checks a single variable and has a single
 -- alternative, can be used to take tuples apart
-getInstantiations sess args outs binds (Case (Var v) b _ [res]) =
+getInstantiations args outs binds (Case (Var v) b _ [res]) =
        case altcon of
                DataAlt datacon ->
                        if (DataCon.isTupleCon datacon) then
-                               getInstantiations sess args outs binds' expr
+                               getInstantiations args outs binds' expr
                        else
                                error "Data constructors other than tuples not supported"
                otherwise ->
@@ -125,33 +134,29 @@ getInstantiations sess args outs binds (Case (Var v) b _ [res]) =
                        (lookup v binds)
 
 -- An application is an instantiation of a component
-getInstantiations sess args outs binds app@(App expr arg) =
-       if isTupleConstructor f then
-               let
-                       Tuple outports = outs
-                       (tys, vals) = splitTupleConstructorArgs fargs
-               in
-                       concat $ zipWith 
-                               (\outs' expr' -> getInstantiations sess args outs' binds expr')
+getInstantiations args outs binds app@(App expr arg) = do
+       let ((Var f), fargs) = collectArgs app
+           name = getOccString f
+       if isTupleConstructor f 
+               then do
+                       let Tuple outports = outs
+                           (tys, vals) = splitTupleConstructorArgs fargs
+                       insts <- sequence $ zipWith 
+                               (\outs' expr' -> getInstantiations args outs' binds expr')
                                outports vals
-       else
-               [AST.CSISm comp]
-       where
-               ((Var f), fargs) = collectArgs app
-               comp = AST.CompInsSm
-                       (AST.unsafeVHDLBasicId "app")
-                       (AST.IUEntity (AST.NSimple (AST.unsafeVHDLBasicId compname)))
-                       (AST.PMapAspect ports)
-               compname = getOccString f
-               hwfunc = Maybe.fromMaybe
-                       (error $ "Function " ++ compname ++ "is unknown")
-                       (lookup compname (funcs sess))
-               HWFunction inports outports = hwfunc
-               ports = 
-                       zipWith (getPortMapEntry binds) ["portin0", "portin1"] fargs
-                 ++ mapOutputPorts outports outs
-
-getInstantiations sess args outs binds expr = 
+                       return $ concat insts
+               else do
+                       HWFunction inports outport <- getHWFunc name
+                       let comp = AST.CompInsSm
+                                               (AST.unsafeVHDLBasicId "app")
+                                               (AST.IUEntity (AST.NSimple (AST.unsafeVHDLBasicId name)))
+                                               (AST.PMapAspect ports)
+                           ports = 
+                                   zipWith (getPortMapEntry binds) inports fargs
+                                   ++ mapOutputPorts outport outs
+                       return [AST.CSISm comp]
+
+getInstantiations args outs binds expr = 
        error $ "Unsupported expression" ++ (showSDoc $ ppr $ expr)
 
 -- Is the given name a (binary) tuple constructor
@@ -191,35 +196,27 @@ mapOutputPorts (Tuple ports) (Tuple signals) =
        concat (zipWith mapOutputPorts ports signals)
 
 getArchitecture ::
-       VHDLSession
-       -> CoreBind               -- The binder to expand into an architecture
-       -> AST.ArchBody           -- The resulting architecture
+       CoreBind                  -- The binder to expand into an architecture
+       -> VHDLState AST.ArchBody -- The resulting architecture
         
-getArchitecture sess (Rec _) = error "Recursive binders not supported"
+getArchitecture (Rec _) = error "Recursive binders not supported"
 
-getArchitecture sess (NonRec var expr) =
-       AST.ArchBody
+getArchitecture (NonRec var expr) = do
+       let name = (getOccString var)
+       HWFunction inports outport <- getHWFunc name
+       sess <- State.get
+       insts <- getInstantiations inports outport [] expr
+       return $ AST.ArchBody
                (AST.unsafeVHDLBasicId "structural")
                -- Use unsafe for now, to prevent pulling in ForSyDe error handling
                (AST.NSimple (AST.unsafeVHDLBasicId name))
                []
-               (getInstantiations sess (Args inportnames) outport [] expr)
-       where
-               name = (getOccString var)
-               ty = CoreUtils.exprType expr
-               (fargs, res) = Type.splitFunTys ty
-               --state = if length fargs == 1 then () else (last fargs)
-               ports = if length fargs == 1 then fargs else (init fargs)
-               inportnames = case ports of
-                       [port] -> [getPortNameMapForTy "portin" port]
-                       ps     -> getPortNameMapForTys "portin" 0 ps
-               outport = getPortNameMapForTy "portout" res
+               (insts)
 
 data PortNameMap =
-       Args [PortNameMap] -- Each of the submaps represent an argument to the
-                          -- function. Should only occur at top level.
-       | Tuple [PortNameMap]
+       Tuple [PortNameMap]
        | Port  String
+  deriving (Show)
 
 -- Generate a port name map (or multiple for tuple types) in the given direction for
 -- each type given.
@@ -240,18 +237,58 @@ getPortNameMapForTy name ty =
                (tycon, args) = Type.splitTyConApp ty 
 
 data HWFunction = HWFunction { -- A function that is available in hardware
-       inPorts   :: PortNameMap,
-       outPorts  :: PortNameMap
+       inPorts   :: [PortNameMap],
+       outPort   :: PortNameMap
        --entity    :: AST.EntityDec
-}
+} deriving (Show)
+
+-- Turns a CoreExpr describing a function into a description of its input and
+-- output ports.
+mkHWFunction ::
+       CoreBind                                   -- The core binder to generate the interface for
+       -> VHDLState (String, HWFunction)          -- The name of the function and its interface
+
+mkHWFunction (NonRec var expr) =
+               return (name, HWFunction inports outport)
+       where
+               name = (getOccString var)
+               ty = CoreUtils.exprType expr
+               (fargs, res) = Type.splitFunTys ty
+               args = if length fargs == 1 then fargs else (init fargs)
+               --state = if length fargs == 1 then () else (last fargs)
+               inports = case args of
+                       -- Handle a single port specially, to prevent an extra 0 in the name
+                       [port] -> [getPortNameMapForTy "portin" port]
+                       ps     -> getPortNameMapForTys "portin" 0 ps
+               outport = getPortNameMapForTy "portout" res
+
+mkHWFunction (Rec _) =
+       error "Recursive binders not supported"
 
 data VHDLSession = VHDLSession {
        nameCount :: Int,                      -- A counter that can be used to generate unique names
        funcs     :: [(String, HWFunction)]    -- All functions available, indexed by name
-}
+} deriving (Show)
+
+type VHDLState = State.State VHDLSession
+
+-- Add the function to the session
+addFunc :: String -> HWFunction -> VHDLState ()
+addFunc name f = do
+       fs <- State.gets funcs -- Get the funcs element from the session
+       State.modify (\x -> x {funcs = (name, f) : fs }) -- Prepend name and f
+
+-- Lookup the function with the given name in the current session. Errors if
+-- it was not found.
+getHWFunc :: String -> VHDLState HWFunction
+getHWFunc name = do
+       fs <- State.gets funcs -- Get the funcs element from the session
+       return $ Maybe.fromMaybe
+               (error $ "Function " ++ name ++ "is unknown? This should not happen!")
+               (lookup name fs)
 
 builtin_funcs = 
        [ 
-               ("hwxor", HWFunction (Args [Port "a", Port "b"]) (Port "o")),
-               ("hwand", HWFunction (Args [Port "a", Port "b"]) (Port "o"))
+               ("hwxor", HWFunction [Port "a", Port "b"] (Port "o")),
+               ("hwand", HWFunction [Port "a", Port "b"] (Port "o"))
        ]