1 module Main(main) where
4 import qualified CoreUtils
8 import qualified DataCon
10 import qualified Module
11 import qualified Control.Monad.State as State
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 )
21 -- The following modules come from the ForSyDe project. They are really
22 -- internal modules, so ForSyDe.cabal has to be modified prior to installing
23 -- ForSyDe to get access to these modules.
24 import qualified ForSyDe.Backend.VHDL.AST as AST
25 import qualified ForSyDe.Backend.VHDL.Ppr
26 import qualified ForSyDe.Backend.Ppr
27 -- This is needed for rendering the pretty printed VHDL
28 import Text.PrettyPrint.HughesPJ (render)
32 defaultErrorHandler defaultDynFlags $ do
33 runGhc (Just libdir) $ do
34 dflags <- getSessionDynFlags
35 setSessionDynFlags dflags
36 --target <- guessTarget "adder.hs" Nothing
37 --liftIO (print (showSDoc (ppr (target))))
38 --liftIO $ printTarget target
41 --core <- GHC.compileToCoreSimplified "Adders.hs"
42 core <- GHC.compileToCoreSimplified "Adders.hs"
43 liftIO $ printBinds (cm_binds core)
44 let bind = findBind "half_adder" (cm_binds core)
45 let NonRec var expr = bind
46 -- Turn bind into VHDL
47 let vhdl = State.evalState (mkVHDL bind) (VHDLSession 0 builtin_funcs)
48 liftIO $ putStr $ showSDoc $ ppr expr
49 liftIO $ putStr "\n\n"
50 liftIO $ putStr $ render $ ForSyDe.Backend.Ppr.ppr $ vhdl
53 -- Turns the given bind into VHDL
55 -- Get the function signature
56 (name, f) <- mkHWFunction bind
57 -- Add it to the session
59 arch <- getArchitecture bind
62 printTarget (Target (TargetFile file (Just x)) obj Nothing) =
65 printBinds [] = putStr "done\n\n"
66 printBinds (b:bs) = do
71 printBind (NonRec b expr) = do
75 printBind (Rec binds) = do
77 foldl1 (>>) (map printBind' binds)
79 printBind' (b, expr) = do
80 putStr $ getOccString b
81 --putStr $ showSDoc $ ppr expr
84 findBind :: String -> [CoreBind] -> CoreBind
86 -- This ignores Recs and compares the name of the bind with lookfor,
87 -- disregarding any namespaces in OccName and extra attributes in Name and
89 Maybe.fromJust . find (\b -> case b of
91 NonRec var _ -> lookfor == (occNameString $ nameOccName $ getName var)
94 -- Accepts a port name and an argument to map to it.
95 -- Returns the appropriate line for in the port map
96 getPortMapEntry binds (Port portname) (Var id) =
97 (Just (AST.unsafeVHDLBasicId portname)) AST.:=>: (AST.ADName (AST.NSimple (AST.unsafeVHDLBasicId signalname)))
99 Port signalname = Maybe.fromMaybe
100 (error $ "Argument " ++ getOccString id ++ "is unknown")
103 getPortMapEntry binds _ a = error $ "Unsupported argument: " ++ (showSDoc $ ppr a)
107 -> [PortNameMap] -- The arguments that need to be applied to the
109 -> PortNameMap -- The output ports that the expression should generate.
110 -> [(CoreBndr, PortNameMap)] -- A list of bindings in effect
111 -> CoreSyn.CoreExpr -- The expression to generate an architecture for
112 -> [AST.ConcSm] -- The resulting VHDL code
114 -- A lambda expression binds the first argument (a) to the binder b.
115 getInstantiations sess (a:as) outs binds (Lam b expr) =
116 getInstantiations sess as outs ((b, a):binds) expr
118 -- A case expression that checks a single variable and has a single
119 -- alternative, can be used to take tuples apart
120 getInstantiations sess args outs binds (Case (Var v) b _ [res]) =
123 if (DataCon.isTupleCon datacon) then
124 getInstantiations sess args outs binds' expr
126 error "Data constructors other than tuples not supported"
128 error "Case binders other than tuples not supported"
130 binds' = (zip bind_vars tuple_ports) ++ binds
131 (altcon, bind_vars, expr) = res
132 -- Find the portnamemaps for each of the tuple's elements
133 Tuple tuple_ports = Maybe.fromMaybe
134 (error $ "Case expression uses unknown scrutinee " ++ getOccString v)
137 -- An application is an instantiation of a component
138 getInstantiations sess args outs binds app@(App expr arg) =
139 if isTupleConstructor f then
141 Tuple outports = outs
142 (tys, vals) = splitTupleConstructorArgs fargs
145 (\outs' expr' -> getInstantiations sess args outs' binds expr')
150 ((Var f), fargs) = collectArgs app
152 (AST.unsafeVHDLBasicId "app")
153 (AST.IUEntity (AST.NSimple (AST.unsafeVHDLBasicId compname)))
154 (AST.PMapAspect ports)
155 compname = getOccString f
156 hwfunc = Maybe.fromMaybe
157 (error $ "Function " ++ compname ++ "is unknown")
158 (lookup compname (funcs sess))
159 HWFunction inports outport = hwfunc
161 zipWith (getPortMapEntry binds) inports fargs
162 ++ mapOutputPorts outport outs
164 getInstantiations sess args outs binds expr =
165 error $ "Unsupported expression" ++ (showSDoc $ ppr $ expr)
167 -- Is the given name a (binary) tuple constructor
168 isTupleConstructor :: Var.Var -> Bool
169 isTupleConstructor var =
170 Name.isWiredInName name
171 && Name.nameModule name == tuple_mod
172 && (Name.occNameString $ Name.nameOccName name) == "(,)"
174 name = Var.varName var
175 mod = nameModule name
176 tuple_mod = Module.mkModule (Module.stringToPackageId "ghc-prim") (Module.mkModuleName "GHC.Tuple")
178 -- Split arguments into type arguments and value arguments This is probably
179 -- not really sufficient (not sure if Types can actually occur as value
181 splitTupleConstructorArgs :: [CoreExpr] -> ([CoreExpr], [CoreExpr])
182 splitTupleConstructorArgs (e:es) =
184 Type t -> (e:tys, vals)
185 otherwise -> (tys, e:vals)
187 (tys, vals) = splitTupleConstructorArgs es
190 PortNameMap -- The output portnames of the component
191 -> PortNameMap -- The output portnames and/or signals to map these to
192 -> [AST.AssocElem] -- The resulting output ports
194 -- Map the output port of a component to the output port of the containing
196 mapOutputPorts (Port portname) (Port signalname) =
197 [(Just (AST.unsafeVHDLBasicId portname)) AST.:=>: (AST.ADName (AST.NSimple (AST.unsafeVHDLBasicId signalname)))]
199 -- Map matching output ports in the tuple
200 mapOutputPorts (Tuple ports) (Tuple signals) =
201 concat (zipWith mapOutputPorts ports signals)
204 CoreBind -- The binder to expand into an architecture
205 -> VHDLState AST.ArchBody -- The resulting architecture
207 getArchitecture (Rec _) = error "Recursive binders not supported"
209 getArchitecture (NonRec var expr) = do
210 HWFunction inports outport <- getHWFunc name
212 return $ AST.ArchBody
213 (AST.unsafeVHDLBasicId "structural")
214 -- Use unsafe for now, to prevent pulling in ForSyDe error handling
215 (AST.NSimple (AST.unsafeVHDLBasicId name))
217 (getInstantiations sess inports outport [] expr)
219 name = (getOccString var)
226 -- Generate a port name map (or multiple for tuple types) in the given direction for
228 getPortNameMapForTys :: String -> Int -> [Type] -> [PortNameMap]
229 getPortNameMapForTys prefix num [] = []
230 getPortNameMapForTys prefix num (t:ts) =
231 (getPortNameMapForTy (prefix ++ show num) t) : getPortNameMapForTys prefix (num + 1) ts
233 getPortNameMapForTy :: String -> Type -> PortNameMap
234 getPortNameMapForTy name ty =
235 if (TyCon.isTupleTyCon tycon) then
236 -- Expand tuples we find
237 Tuple (getPortNameMapForTys name 0 args)
238 else -- Assume it's a type constructor application, ie simple data type
242 (tycon, args) = Type.splitTyConApp ty
244 data HWFunction = HWFunction { -- A function that is available in hardware
245 inPorts :: [PortNameMap],
246 outPort :: PortNameMap
247 --entity :: AST.EntityDec
250 -- Turns a CoreExpr describing a function into a description of its input and
253 CoreBind -- The core binder to generate the interface for
254 -> VHDLState (String, HWFunction) -- The name of the function and its interface
256 mkHWFunction (NonRec var expr) =
257 return (name, HWFunction inports outport)
259 name = (getOccString var)
260 ty = CoreUtils.exprType expr
261 (fargs, res) = Type.splitFunTys ty
262 args = if length fargs == 1 then fargs else (init fargs)
263 --state = if length fargs == 1 then () else (last fargs)
264 inports = case args of
265 -- Handle a single port specially, to prevent an extra 0 in the name
266 [port] -> [getPortNameMapForTy "portin" port]
267 ps -> getPortNameMapForTys "portin" 0 ps
268 outport = getPortNameMapForTy "portout" res
270 mkHWFunction (Rec _) =
271 error "Recursive binders not supported"
273 data VHDLSession = VHDLSession {
274 nameCount :: Int, -- A counter that can be used to generate unique names
275 funcs :: [(String, HWFunction)] -- All functions available, indexed by name
278 type VHDLState = State.State VHDLSession
280 -- Add the function to the session
281 addFunc :: String -> HWFunction -> VHDLState ()
283 fs <- State.gets funcs -- Get the funcs element from the session
284 State.modify (\x -> x {funcs = (name, f) : fs }) -- Prepend name and f
286 -- Lookup the function with the given name in the current session. Errors if
288 getHWFunc :: String -> VHDLState HWFunction
290 fs <- State.gets funcs -- Get the funcs element from the session
291 return $ Maybe.fromMaybe
292 (error $ "Function " ++ name ++ "is unknown? This should not happen!")
297 ("hwxor", HWFunction [Port "a", Port "b"] (Port "o")),
298 ("hwand", HWFunction [Port "a", Port "b"] (Port "o"))