module CLaSH.Driver where
import qualified Control.Concurrent.Supply as Supply
import Control.Monad.State (evalState)
import Control.Lens (_1, use)
import qualified Data.HashMap.Lazy as HashMap
import qualified Data.HashSet as HashSet
import Data.List (isSuffixOf)
import Data.Maybe (listToMaybe)
import qualified Data.Text.Lazy as Text
import qualified System.Directory as Directory
import qualified System.FilePath as FilePath
import qualified System.IO as IO
import Text.PrettyPrint.Leijen.Text (Doc, hPutDoc)
import Unbound.LocallyNameless (name2String)
import CLaSH.Core.Type (Type)
import CLaSH.Driver.TestbenchGen
import CLaSH.Driver.Types
import CLaSH.Netlist (genNetlist)
import CLaSH.Netlist.Types (Component (..), HWType,
VHDLState)
import CLaSH.Netlist.VHDL (genVHDL, mkTyPackage)
import CLaSH.Normalize (checkNonRecursive, cleanupGraph,
normalize, runNormalization)
import CLaSH.Primitives.Types
import CLaSH.Rewrite.Types (DebugLevel (..))
import CLaSH.Util
import qualified Data.Time.Clock as Clock
generateVHDL :: BindingMap
-> PrimMap
-> (Type -> Maybe (Either String HWType))
-> DebugLevel
-> IO ()
generateVHDL bindingsMap primMap typeTrans dbgLevel = do
start <- Clock.getCurrentTime
let topEntities = HashMap.toList
$ HashMap.filterWithKey
(\var _ -> isSuffixOf "topEntity" $ name2String var)
bindingsMap
testInputs = HashMap.toList
$ HashMap.filterWithKey
(\var _ -> isSuffixOf "testInput" $ name2String var)
bindingsMap
expectedOutputs = HashMap.toList
$ HashMap.filterWithKey
(\var _ -> isSuffixOf "expectedOutput" $ name2String var)
bindingsMap
start `seq` case topEntities of
[topEntity] -> do
(supplyN,supplyTB) <- Supply.splitSupply
. snd
. Supply.freshId
<$> Supply.newSupply
prepTime <- bindingsMap `seq` Clock.getCurrentTime
let prepStartDiff = Clock.diffUTCTime prepTime start
putStrLn $ "Loading dependencies took " ++ show prepStartDiff
let doNorm = do norm <- normalize [fst topEntity]
let normChecked = checkNonRecursive (fst topEntity) norm
cleanupGraph [fst topEntity] normChecked
transformedBindings =
runNormalization dbgLevel supplyN bindingsMap typeTrans doNorm
normTime <- transformedBindings `seq` Clock.getCurrentTime
let prepNormDiff = Clock.diffUTCTime normTime prepTime
putStrLn $ "Normalisation took " ++ show prepNormDiff
(netlist,vhdlState) <- genNetlist Nothing
(HashMap.fromList transformedBindings)
primMap typeTrans Nothing (fst topEntity)
netlistTime <- netlist `seq` Clock.getCurrentTime
let normNetDiff = Clock.diffUTCTime netlistTime normTime
putStrLn $ "Netlist generation took " ++ show normNetDiff
let topComponent = head
$ filter (\(Component cName _ _ _ _) ->
Text.isSuffixOf (Text.pack "topEntity_0")
cName)
netlist
(testBench,vhdlState') <- genTestBench dbgLevel supplyTB primMap
typeTrans vhdlState bindingsMap
(listToMaybe $ map fst testInputs)
(listToMaybe $ map fst expectedOutputs)
topComponent
testBenchTime <- testBench `seq` Clock.getCurrentTime
let netTBDiff = Clock.diffUTCTime testBenchTime netlistTime
putStrLn $ "Testbench generation took " ++ show netTBDiff
let vhdlDocs = createVHDL vhdlState' (netlist ++ testBench)
dir = concat [ "./vhdl/"
, takeWhile (/= '.') (name2String $ fst topEntity)
, "/"
]
prepareDir dir
mapM_ (writeVHDL dir) vhdlDocs
end <- vhdlDocs `seq` Clock.getCurrentTime
let startEndDiff = Clock.diffUTCTime end start
putStrLn $ "Total compilation took " ++ show startEndDiff
[] -> error $ $(curLoc) ++ "No 'topEntity' found"
_ -> error $ $(curLoc) ++ "Multiple 'topEntity's found"
createVHDL :: VHDLState
-> [Component]
-> [(String,Doc)]
createVHDL vhdlState components = flip evalState vhdlState $ do
(vhdlNms,vhdlDocs) <- unzip <$> mapM genVHDL components
let vhdlNmDocs = zip vhdlNms vhdlDocs
hwtys <- HashSet.toList <$> use _1
typesPkgM <- case hwtys of
[] -> return Nothing
_ -> Just <$> mkTyPackage hwtys
return $ maybe vhdlNmDocs (\t -> ("types",t):vhdlNmDocs) typesPkgM
prepareDir :: String -> IO ()
prepareDir dir = do
Directory.createDirectoryIfMissing True dir
files <- Directory.getDirectoryContents dir
let to_remove = filter ((==".vhdl") . FilePath.takeExtension) files
let abs_to_remove = map (FilePath.combine dir) to_remove
mapM_ Directory.removeFile abs_to_remove
writeVHDL :: FilePath -> (String, Doc) -> IO ()
writeVHDL dir (cname, vhdl) = do
handle <- IO.openFile (dir ++ cname ++ ".vhdl") IO.WriteMode
IO.hPutStrLn handle "-- Automatically generated VHDL"
hPutDoc handle vhdl
IO.hPutStr handle "\n"
IO.hClose handle