1 module Translator where
2 import qualified Directory
5 import qualified Control.Arrow as Arrow
6 import GHC hiding (loadModule, sigName)
8 import qualified CoreUtils
11 import qualified TyCon
12 import qualified DataCon
13 import qualified HscMain
14 import qualified SrcLoc
15 import qualified FastString
16 import qualified Maybe
17 import qualified Module
18 import qualified Data.Foldable as Foldable
19 import qualified Control.Monad.Trans.State as State
21 import qualified Data.Map as Map
24 import NameEnv ( lookupNameEnv )
25 import qualified HscTypes
26 import HscTypes ( cm_binds, cm_types )
27 import MonadUtils ( liftIO )
28 import Outputable ( showSDoc, ppr )
29 import GHC.Paths ( libdir )
30 import DynFlags ( defaultDynFlags )
31 import qualified UniqSupply
34 import qualified Monad
36 -- The following modules come from the ForSyDe project. They are really
37 -- internal modules, so ForSyDe.cabal has to be modified prior to installing
38 -- ForSyDe to get access to these modules.
39 import qualified ForSyDe.Backend.VHDL.AST as AST
40 import qualified ForSyDe.Backend.VHDL.Ppr
41 import qualified ForSyDe.Backend.VHDL.FileIO
42 import qualified ForSyDe.Backend.Ppr
43 -- This is needed for rendering the pretty printed VHDL
44 import Text.PrettyPrint.HughesPJ (render)
46 import TranslatorTypes
55 makeVHDL :: String -> String -> Bool -> IO ()
56 makeVHDL filename name stateful = do
58 core <- loadModule filename
60 vhdl <- moduleToVHDL core [(name, stateful)]
62 let dir = "./vhdl/" ++ name ++ "/"
63 mapM (writeVHDL dir) vhdl
66 -- | Show the core structure of the given binds in the given file.
67 listBind :: String -> String -> IO ()
68 listBind filename name = do
69 core <- loadModule filename
70 let [(b, expr)] = findBinds core [name]
72 putStr $ prettyShow expr
74 putStr $ showSDoc $ ppr expr
76 putStr $ showSDoc $ ppr $ CoreUtils.exprType expr
79 -- | Translate the binds with the given names from the given core module to
80 -- VHDL. The Bool in the tuple makes the function stateful (True) or
82 moduleToVHDL :: HscTypes.CoreModule -> [(String, Bool)] -> IO [(AST.VHDLId, AST.DesignFile)]
83 moduleToVHDL core list = do
84 let (names, statefuls) = unzip list
85 let binds = map fst $ findBinds core names
86 -- Generate a UniqSupply
88 -- egrep -r "(initTcRnIf|mkSplitUniqSupply)" .
89 -- on the compiler dir of ghc suggests that 'z' is not used to generate a
90 -- unique supply anywhere.
91 uniqSupply <- UniqSupply.mkSplitUniqSupply 'z'
92 -- Turn bind into VHDL
93 let all_bindings = (CoreSyn.flattenBinds $ cm_binds core)
94 let normalized_bindings = normalizeModule uniqSupply all_bindings binds statefuls
95 let vhdl = VHDL.createDesignFiles normalized_bindings
96 mapM (putStr . render . ForSyDe.Backend.Ppr.ppr . snd) vhdl
97 --putStr $ "\n\nFinal session:\n" ++ prettyShow sess ++ "\n\n"
101 -- | Write the given design file to a file with the given name inside the
103 writeVHDL :: String -> (AST.VHDLId, AST.DesignFile) -> IO ()
104 writeVHDL dir (name, vhdl) = do
105 -- Create the dir if needed
106 exists <- Directory.doesDirectoryExist dir
107 Monad.unless exists $ Directory.createDirectory dir
109 let fname = dir ++ (AST.fromVHDLId name) ++ ".vhdl"
111 ForSyDe.Backend.VHDL.FileIO.writeDesignFile vhdl fname
113 -- | Loads the given file and turns it into a core module.
114 loadModule :: String -> IO HscTypes.CoreModule
115 loadModule filename =
116 defaultErrorHandler defaultDynFlags $ do
117 runGhc (Just libdir) $ do
118 dflags <- getSessionDynFlags
119 setSessionDynFlags dflags
120 --target <- guessTarget "adder.hs" Nothing
121 --liftIO (print (showSDoc (ppr (target))))
122 --liftIO $ printTarget target
123 --setTargets [target]
124 --load LoadAllTargets
125 --core <- GHC.compileToCoreSimplified "Adders.hs"
126 core <- GHC.compileToCoreModule filename
129 -- | Extracts the named binds from the given module.
130 findBinds :: HscTypes.CoreModule -> [String] -> [(CoreBndr, CoreExpr)]
131 findBinds core names = Maybe.mapMaybe (findBind (CoreSyn.flattenBinds $ cm_binds core)) names
133 -- | Extract a named bind from the given list of binds
134 findBind :: [(CoreBndr, CoreExpr)] -> String -> Maybe (CoreBndr, CoreExpr)
135 findBind binds lookfor =
136 -- This ignores Recs and compares the name of the bind with lookfor,
137 -- disregarding any namespaces in OccName and extra attributes in Name and
139 find (\(var, _) -> lookfor == (occNameString $ nameOccName $ getName var)) binds
141 -- | Flattens the given bind into the given signature and adds it to the
142 -- session. Then (recursively) finds any functions it uses and does the same
145 HsFunction -- The signature to flatten into
146 -> (CoreBndr, CoreExpr) -- The bind to flatten
147 -> TranslatorState ()
149 flattenBind hsfunc bind@(var, expr) = do
150 -- Flatten the function
151 let flatfunc = flattenFunction hsfunc bind
152 -- Propagate state variables
153 let flatfunc' = propagateState hsfunc flatfunc
154 -- Store the flat function in the session
155 modA tsFlatFuncs (Map.insert hsfunc flatfunc')
156 -- Flatten any functions used
157 let used_hsfuncs = Maybe.mapMaybe usedHsFunc (flat_defs flatfunc')
158 mapM_ resolvFunc used_hsfuncs
160 -- | Decide which incoming state variables will become state in the
161 -- given function, and which will be propagate to other applied
168 propagateState hsfunc flatfunc =
169 flatfunc {flat_defs = apps', flat_sigs = sigs'}
171 (olds, news) = unzip $ getStateSignals hsfunc flatfunc
172 states' = zip olds news
173 -- Find all signals used by all sigdefs
174 uses = concatMap sigDefUses (flat_defs flatfunc)
175 -- Find all signals that are used more than once (is there a
176 -- prettier way to do this?)
177 multiple_uses = uses List.\\ (List.nub uses)
178 -- Find the states whose "old state" signal is used only once
179 single_use_states = filter ((`notElem` multiple_uses) . fst) states'
180 -- See if these single use states can be propagated
181 (substate_sigss, apps') = unzip $ map (propagateState' single_use_states) (flat_defs flatfunc)
182 substate_sigs = concat substate_sigss
183 -- Mark any propagated state signals as SigSubState
185 (\(id, info) -> (id, if id `elem` substate_sigs then info {sigUse = SigSubState} else info))
188 -- | Propagate the state into a single function application.
190 [(SignalId, SignalId)]
192 -> SigDef -- ^ The SigDef to process.
193 -> ([SignalId], SigDef)
194 -- ^ Any signal ids that should become substates,
195 -- and the resulting application.
197 propagateState' states def =
198 if (is_FApp def) then
199 (our_old ++ our_new, def {appFunc = hsfunc'})
206 our_states = filter our_state states
207 -- A state signal belongs in this function if the old state is
208 -- passed in, and the new state returned
209 our_state (old, new) =
210 any (old `Foldable.elem`) args
211 && new `Foldable.elem` res
212 (our_old, our_new) = unzip our_states
214 zipped_res = zipValueMaps res (hsFuncRes hsfunc)
215 res' = fmap (mark_state (zip our_new [0..])) zipped_res
217 zipped_args = zipWith zipValueMaps args (hsFuncArgs hsfunc)
218 args' = map (fmap (mark_state (zip our_old [0..]))) zipped_args
219 hsfunc' = hsfunc {hsFuncArgs = args', hsFuncRes = res'}
221 mark_state :: [(SignalId, StateId)] -> (SignalId, HsValueUse) -> HsValueUse
222 mark_state states (id, use) =
223 case lookup id states of
225 Just state_id -> State state_id
227 -- | Returns pairs of signals that should be mapped to state in this function.
229 HsFunction -- | The function to look at
230 -> FlatFunction -- | The function to look at
231 -> [(SignalId, SignalId)]
232 -- | TODO The state signals. The first is the state number, the second the
233 -- signal to assign the current state to, the last is the signal
234 -- that holds the new state.
236 getStateSignals hsfunc flatfunc =
238 | (old_num, old_id) <- args
239 , (new_num, new_id) <- res
240 , old_num == new_num]
242 sigs = flat_sigs flatfunc
243 -- Translate args and res to lists of (statenum, sigid)
244 args = concat $ zipWith stateList (hsFuncArgs hsfunc) (flat_args flatfunc)
245 res = stateList (hsFuncRes hsfunc) (flat_res flatfunc)
247 -- | Find the given function, flatten it and add it to the session. Then
248 -- (recursively) do the same for any functions used.
250 HsFunction -- | The function to look for
251 -> TranslatorState ()
253 resolvFunc hsfunc = do
254 flatfuncmap <- getA tsFlatFuncs
255 -- Don't do anything if there is already a flat function for this hsfunc or
256 -- when it is a builtin function.
257 Monad.unless (Map.member hsfunc flatfuncmap) $ do
258 -- Not working with new builtins -- Monad.unless (elem hsfunc VHDL.builtin_hsfuncs) $ do
259 -- New function, resolve it
260 core <- getA tsCoreModule
261 -- Find the named function
262 let name = (hsFuncName hsfunc)
263 let bind = findBind (CoreSyn.flattenBinds $ cm_binds core) name
265 Nothing -> error $ "Couldn't find function " ++ name ++ " in current module."
266 Just b -> flattenBind hsfunc b
268 -- | Translate a top level function declaration to a HsFunction. i.e., which
269 -- interface will be provided by this function. This function essentially
270 -- defines the "calling convention" for hardware models.
272 Var.Var -- ^ The function defined
273 -> Type -- ^ The function type (including arguments!)
274 -> Bool -- ^ Is this a stateful function?
275 -> HsFunction -- ^ The resulting HsFunction
277 mkHsFunction f ty stateful=
278 HsFunction hsname hsargs hsres
280 hsname = getOccString f
281 (arg_tys, res_ty) = Type.splitFunTys ty
286 -- The last argument must be state
287 state_ty = last arg_tys
288 state = useAsState (mkHsValueMap state_ty)
289 -- All but the last argument are inports
290 inports = map (useAsPort . mkHsValueMap)(init arg_tys)
291 hsargs = inports ++ [state]
292 hsres = case splitTupleType res_ty of
293 -- Result type must be a two tuple (state, ports)
294 Just [outstate_ty, outport_ty] -> if Type.coreEqType state_ty outstate_ty
296 Tuple [state, useAsPort (mkHsValueMap outport_ty)]
298 error $ "Input state type of function " ++ hsname ++ ": " ++ (showSDoc $ ppr state_ty) ++ " does not match output state type: " ++ (showSDoc $ ppr outstate_ty)
299 otherwise -> error $ "Return type of top-level function " ++ hsname ++ " must be a two-tuple containing a state and output ports."
303 -- Just use everything as a port
304 (map (useAsPort . mkHsValueMap) arg_tys, useAsPort $ mkHsValueMap res_ty)
306 -- | Adds signal names to the given FlatFunction
311 nameFlatFunction flatfunc =
314 s = flat_sigs flatfunc
315 s' = map nameSignal s in
316 flatfunc { flat_sigs = s' }
318 nameSignal :: (SignalId, SignalInfo) -> (SignalId, SignalInfo)
319 nameSignal (id, info) =
320 let hints = nameHints info in
321 let parts = ("sig" : hints) ++ [show id] in
322 let name = concat $ List.intersperse "_" parts in
323 (id, info {sigName = Just name})
325 -- | Splits a tuple type into a list of element types, or Nothing if the type
326 -- is not a tuple type.
328 Type -- ^ The type to split
329 -> Maybe [Type] -- ^ The tuples element types
332 case Type.splitTyConApp_maybe ty of
333 Just (tycon, args) -> if TyCon.isTupleTyCon tycon
340 -- vim: set ts=8 sw=2 sts=2 expandtab: