module Development.KansasLava.Shake.Xilinx
( XilinxConfig(..)
, xilinxRules
) where
import Development.Shake
import Development.Shake.FilePath
import System.Directory
import Data.Monoid
import Data.List (stripPrefix)
import Data.Maybe (fromJust)
import Data.String (fromString)
import qualified Data.Text.Lazy as TL
import qualified Data.Text as TS
import Text.Hastache
import Paths_kansas_lava_shake
data XilinxConfig = XilinxConfig{ xilinxRoot :: FilePath
, xilinxPlatform :: String
}
xilinxRules :: XilinxConfig
-> String
-> [String]
-> Rules ()
xilinxRules XilinxConfig{..} mod xaws = do
"*.ut" *>
textTemplate []
"*.xst" *>
textTemplate [("MAIN", fromString mod), ("TOP", fromString mod)]
"*.xise" *>
listTemplate "components" xiseFiles
"*.prj" *> \target -> do
let vhdlWork baseName = mconcat ["vhdl work \"", baseName <.> "vhdl", "\""]
liftIO $ writeFile target . unlines $
map (vhdlWork . gensrc) vhdls ++ map (vhdlWork . xawsrc) xaws
xawsrc "*.vhdl" *> \target -> do
let xaw = ".." </> "xaw" </> takeFileName target -<.> "xaw"
need [xaw]
removeFilesAfter "." ["xaw2vhdl.log"]
xilinx "xaw2vhdl" [xaw, "-st", "XST", target]
xawsrc "*.ucf" *> \target -> need [target -<.> "vhdl"]
"xst/projnav.tmp" *> liftIO . createDirectoryIfMissing True
"*.ngc" *> \target -> do
need $
(target -<.> "prj"):
(target -<.> "xst"):
("xst" </> "projnav.tmp"):
[gensrc $ f <.> "vhdl" | f <- vhdls] ++
[xawsrc $ f <.> "vhdl" | f <- xaws]
removeFilesAfter "."
[ "xst//*"
, "_xmsgs//*"
, target -<.> "lso"
, target -<.> "ngr"
, target -<.> "syr"
, "*.xrpt"
]
xilinx "xst" [ "-ifn", target -<.> "xst"
, "-ofn", target -<.> "syr"
]
"*.ngd" *> \target -> do
let ucf = gensrc $ target -<.> "ucf"
need [ target -<.> "ngc"
, ucf
, "xst/projnav.tmp"
]
removeFilesAfter "."
[ target -<.> "bld"
, "ngo//*"
, "xlnx_auto_0_xdb//*"
, "*.xrpt"
]
xilinx "ngdbuild" [ "-dd", "ngo"
, "-nt", "timestamp"
, "-uc", ucf
, "-p", xilinxPlatform
, target -<.> "ngc"
, target
]
"*.pcf" *> \target -> do
need [ target -<.> "ngc"
, target -<.> "ngd"
, "xst/projnav.tmp"
]
removeFilesAfter "."
[ "*_summary.xml"
, "*_usage.xml"
, target -<.> "ngm"
, target -<.> "mrp"
, target -<.> "map"
]
xilinx "map" [ "-p", xilinxPlatform
, "-ir", "off"
, "-pr", "off"
, "-c", "100"
, "-w"
, "-o", mapFileName (<> "_map") target -<.> "ncd"
, target -<.> "ngd"
, target -<.> "pcf"
]
alternatives $ do
"*_map.ncd" *> \target -> need [mapFileName (fromJust . stripSuffix "_map") target -<.> "pcf"]
"*.ncd" *> \target -> do
need [ "xst" </> "projnav.tmp"
, target -<.> "pcf"
]
removeFilesAfter "."
[ "*_pad.txt"
, "*_pad.xrpt"
, "*_pad.csv"
, "_xmsgs//*"
, target -<.> "pad"
, target -<.> "par"
, target -<.> "xpi"
, target -<.> "unroutes"
, target -<.> "ptwx"
]
xilinx "par" [ "-w"
, "-ol", "high"
, "-mt", "off"
, mapFileName (<> "_map") target -<.> "ncd"
, target -<.> "ncd"
, target -<.> "pcf"
]
"*.bit" *> \target -> do
need [ "xst/projnav.tmp"
, target -<.> "ut"
, target -<.> "ncd"
]
removeFilesAfter "."
[ "*_bitgen.xwbt"
, "usage_statistics_webtalk.html"
, "webtalk.log"
, target -<.> "bgn"
, target -<.> "drc"
]
xilinx "bitgen" [ "-f", target -<.> "ut"
, target -<.> "ncd"
]
where
xilinx tool args = cmd (xilinxRoot </> tool) args
gensrc f = "gensrc" </> f
xawsrc f = gensrc $ "xaw" </> f
vhdls = [mod, "lava-prelude"]
xiseFiles = map (return .) $ ucf : map vhdl vhdls ++ map xaw xaws
where
vhdl componentName = \key -> case key of
"type" -> MuVariable ("FILE_VHDL" :: String)
"fileName" -> MuVariable $ componentName <.> "vhdl"
"behavior" -> MuBool True
ucf = \key -> case key of
"type" -> MuVariable ("FILE_UCF" :: String)
"fileName" -> MuVariable $ mod <.> "ucf"
"behavior" -> MuBool False
xaw componentName = \key -> case key of
"type" -> MuVariable ("FILE_XAW" :: String)
"fileName" -> MuVariable $ ".." </> "xaw" </> componentName <.> "xaw"
"behavior" -> MuBool True
hastache :: MuContext IO -> FilePath -> Action ()
hastache ctxt target = do
templateFile <- liftIO $ getDataFileName ("ise.template" </> templateName)
t <- liftIO $ hastacheFile hastacheConfig templateFile ctxt
writeFileChanged target $ TL.unpack t
where
hastacheConfig = MuConfig{ muEscapeFunc = emptyEscape
, muTemplateFileDir = Nothing
, muTemplateFileExt = Just "mustache"
, muTemplateRead = const $ return Nothing
}
ext = drop 1 . takeExtension $ target
templateName = ext <.> "mustache"
listTemplate :: TS.Text -> [MuContext IO] -> FilePath -> Action ()
listTemplate key0 entities = hastache ctxt
where
ctxt key = return $ if key == key0 then MuList entities else MuNothing
textTemplate :: [(TS.Text, TL.Text)] -> FilePath -> Action ()
textTemplate replacements = hastache ctxt
where
ctxt key = return $ case lookup key replacements of
Just value -> MuVariable value
Nothing -> MuNothing
mapFileName :: (String -> String) -> FilePath -> FilePath
mapFileName f fp = replaceFileName fp (f (takeFileName fp))
stripSuffix :: (Eq a) => [a] -> [a] -> Maybe [a]
stripSuffix suffix = fmap reverse . stripPrefix (reverse suffix) . reverse