1 module CLasH.Translator
7 import qualified System.Directory as Directory
10 import qualified System.FilePath as FilePath
11 import qualified Control.Monad.Trans.State as State
12 import Text.PrettyPrint.HughesPJ (render)
14 import qualified Data.Map as Map
18 import qualified CoreSyn
20 import qualified HscTypes
21 import qualified UniqSupply
24 import qualified Language.VHDL.AST as AST
25 import qualified Language.VHDL.FileIO
26 import qualified Language.VHDL.Ppr as Ppr
29 import CLasH.Normalize
30 import CLasH.Translator.TranslatorTypes
31 import CLasH.Translator.Annotations
33 import CLasH.Utils.Core.CoreTools
34 import CLasH.Utils.GhcTools
36 import CLasH.VHDL.Testbench
38 -- | Turn Haskell to VHDL, Usings Strings to indicate the Top Entity, Initial
39 -- State and Test Inputs.
41 -- FilePath -- ^ The GHC Library Dir
42 -- -> [FilePath] -- ^ The FileNames
43 -- -> String -- ^ The TopEntity
44 -- -> String -- ^ The InitState
45 -- -> String -- ^ The TestInput
47 -- makeVHDLStrings libdir filenames topentity initstate testinput = do
48 -- makeVHDL libdir filenames finder
50 -- finder = findSpec (hasVarName topentity)
51 -- (hasVarName initstate)
52 -- (isCLasHAnnotation isInitState)
53 -- (hasVarName testinput)
55 -- | Turn Haskell to VHDL, Using the Annotations for Top Entity, Initial State
56 -- and Test Inputs found in the Files.
57 makeVHDLAnnotations ::
58 FilePath -- ^ The GHC Library Dir
59 -> [FilePath] -- ^ The FileNames
61 makeVHDLAnnotations libdir filenames = do
62 makeVHDL libdir filenames finder
64 finder = findSpec (hasCLasHAnnotation isTopEntity)
65 (hasCLasHAnnotation isInitState)
66 (isCLasHAnnotation isInitState)
67 (hasCLasHAnnotation isTestInput)
69 -- | Turn Haskell to VHDL, using the given finder functions to find the Top
70 -- Entity, Initial State and Test Inputs in the Haskell Files.
72 FilePath -- ^ The GHC Library Dir
73 -> [FilePath] -- ^ The Filenames
76 makeVHDL libdir filenames finder = do
78 (cores, env, specs) <- loadModules libdir filenames (Just finder)
80 vhdl <- moduleToVHDL env cores specs
81 -- Write VHDL to file. Just use the first entity for the name
82 let top_entity = head $ Maybe.catMaybes $ map (\(t, _, _) -> t) specs
83 let dir = "./vhdl/" ++ (show top_entity) ++ "/"
85 mapM (writeVHDL dir) vhdl
88 -- | Translate the specified entities in the given modules to VHDL.
90 HscTypes.HscEnv -- ^ The GHC Environment
91 -> [HscTypes.CoreModule] -- ^ The Core Modules
92 -> [EntitySpec] -- ^ The entities to generate
93 -> IO [(AST.VHDLId, AST.DesignFile)]
94 moduleToVHDL env cores specs = do
95 vhdl <- runTranslatorSession env $ do
96 let all_bindings = concat (map (\x -> CoreSyn.flattenBinds (HscTypes.cm_binds x)) cores)
97 -- Store the bindings we loaded
98 tsBindings %= Map.fromList all_bindings
99 let all_initstates = concat (map (\x -> case x of (_, Nothing, _) -> []; (_, Just inits, _) -> inits) specs)
100 tsInitStates %= Map.fromList all_initstates
101 test_binds <- catMaybesM $ Monad.mapM mkTest specs
102 mapM_ printAnns specs
103 let topbinds = Maybe.catMaybes $ map (\(top, _, _) -> top) specs
105 [] -> error $ "Could not find top entity requested"
106 tops -> createDesignFiles (tops ++ test_binds)
107 mapM (putStr . render . Ppr.ppr . snd) vhdl
110 mkTest :: EntitySpec -> TranslatorSession (Maybe CoreSyn.CoreBndr)
111 -- Create a testbench for any entry that has test input
112 mkTest (_, _, Nothing) = return Nothing
113 mkTest (Nothing, _, _) = return Nothing
114 mkTest (Just top, _, Just input) = do
115 bndr <- createTestbench Nothing cores input top
117 printAnns :: EntitySpec -> TranslatorSession ()
118 printAnns (_, Nothing, _) = trace ("no anns found:\n\n") $ return ()
119 printAnns (_, (Just anns), _) = trace ("anns:\n\n" ++ show anns ++ "\n") $ return ()
121 -- Run the given translator session. Generates a new UniqSupply for that
123 runTranslatorSession :: HscTypes.HscEnv -> TranslatorSession a -> IO a
124 runTranslatorSession env session = do
125 -- Generate a UniqSupply
127 -- egrep -r "(initTcRnIf|mkSplitUniqSupply)" .
128 -- on the compiler dir of ghc suggests that 'z' is not used to generate
129 -- a unique supply anywhere.
130 uniqSupply <- UniqSupply.mkSplitUniqSupply 'z'
131 let init_typestate = TypeState Map.empty [] Map.empty Map.empty env
132 let init_state = TranslatorState uniqSupply init_typestate Map.empty Map.empty 0 Map.empty Map.empty Map.empty
133 return $ State.evalState session init_state
135 -- | Prepares the directory for writing VHDL files. This means creating the
136 -- dir if it does not exist and removing all existing .vhdl files from it.
137 prepareDir :: String -> IO()
139 -- Create the dir if needed
140 Directory.createDirectoryIfMissing True dir
141 -- Find all .vhdl files in the directory
142 files <- Directory.getDirectoryContents dir
143 let to_remove = filter ((==".vhdl") . FilePath.takeExtension) files
144 -- Prepend the dirname to the filenames
145 let abs_to_remove = map (FilePath.combine dir) to_remove
147 mapM_ Directory.removeFile abs_to_remove
149 -- | Write the given design file to a file with the given name inside the
151 writeVHDL :: String -> (AST.VHDLId, AST.DesignFile) -> IO ()
152 writeVHDL dir (name, vhdl) = do
154 let fname = dir ++ (AST.fromVHDLId name) ++ ".vhdl"
156 Language.VHDL.FileIO.writeDesignFile vhdl fname
158 -- vim: set ts=8 sw=2 sts=2 expandtab: