{-# LANGUAGE OverloadedStrings, RecordWildCards, TemplateHaskell #-}
module Clash.Shake.Xilinx
    ( XilinxTarget(..), papilioPro, papilioOne, nexysA750T
    , xilinxISE
    , xilinxVivado
    ) where

import Clash.Shake

import Development.Shake
import Development.Shake.Command
import Development.Shake.FilePath
import Development.Shake.Config

import Text.Mustache
import qualified Text.Mustache.Compile.TH as TH
import Data.Aeson

import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.IO as T

data XilinxTarget = XilinxTarget
    { XilinxTarget -> String
targetFamily :: String
    , XilinxTarget -> String
targetDevice :: String
    , XilinxTarget -> String
targetPackage :: String
    , XilinxTarget -> String
targetSpeed :: String
    }

targetMustache :: XilinxTarget -> [a]
targetMustache XilinxTarget{String
targetSpeed :: String
targetPackage :: String
targetDevice :: String
targetFamily :: String
targetSpeed :: XilinxTarget -> String
targetPackage :: XilinxTarget -> String
targetDevice :: XilinxTarget -> String
targetFamily :: XilinxTarget -> String
..} =
    [ Text
"targetFamily"  Text -> Text -> a
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
targetFamily
    , Text
"targetDevice"  Text -> Text -> a
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
targetDevice
    , Text
"targetPackage" Text -> Text -> a
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
targetPackage
    , Text
"targetSpeed"   Text -> Text -> a
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
targetSpeed
    , Text
"part"          Text -> Text -> a
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack (String
targetDevice String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
targetPackage String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
targetSpeed)
    ]

papilioPro :: XilinxTarget
papilioPro :: XilinxTarget
papilioPro = String -> String -> String -> String -> XilinxTarget
XilinxTarget String
"Spartan6" String
"xc6slx9" String
"tqg144" String
"-2"

papilioOne :: XilinxTarget
papilioOne :: XilinxTarget
papilioOne = String -> String -> String -> String -> XilinxTarget
XilinxTarget String
"Spartan3E" String
"xc3s500e" String
"vq100" String
"-5"

nexysA750T :: XilinxTarget
nexysA750T :: XilinxTarget
nexysA750T = String -> String -> String -> String -> XilinxTarget
XilinxTarget String
"Artrix7" String
"xc7a50t" String
"icsg324" String
"-1L"

xilinxISE :: XilinxTarget -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
xilinxISE :: XilinxTarget
-> ClashKit -> String -> String -> String -> Rules SynthKit
xilinxISE XilinxTarget
fpga kit :: ClashKit
kit@ClashKit{Action [String]
[String] -> Action ()
manifestSrcs :: ClashKit -> Action [String]
clash :: ClashKit -> [String] -> Action ()
manifestSrcs :: Action [String]
clash :: [String] -> Action ()
..} String
outDir String
srcDir String
topName = do
    let projectName :: String
projectName = String
topName
        rootDir :: String
rootDir = [String] -> String
joinPath ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
forall a b. a -> b -> a
const String
"..") ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitPath (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
outDir

    let ise :: String -> t -> Action ()
ise String
tool t
args = do
            Maybe String
root <- String -> Action (Maybe String)
getConfig String
"ISE_ROOT"
            Maybe String
wrap <- String -> Action (Maybe String)
getConfig String
"ISE"
            let exe :: [String]
exe = case (Maybe String
wrap, Maybe String
root) of
                    (Just String
wrap, Maybe String
_) -> [String
wrap, String
tool]
                    (Maybe String
Nothing, Just String
root) -> [String
root String -> String -> String
</> String
"ISE/bin/lin64" String -> String -> String
</> String
tool]
                    (Maybe String
Nothing, Maybe String
Nothing) -> String -> [String]
forall a. HasCallStack => String -> a
error String
"ISE_ROOT or ISE must be set in build.mk"
            (CmdOption -> [String] -> t -> Action ()) :-> Action ()
forall args. (HasCallStack, CmdArguments args, Unit args) => args
cmd_ (String -> CmdOption
Cwd String
outDir) [String]
exe t
args

    let getFiles :: String -> [String] -> Action [String]
getFiles String
dir [String]
pats = String -> [String] -> Action [String]
getDirectoryFiles String
srcDir [ String
dir String -> String -> String
</> String
pat | String
pat <- [String]
pats ]
        hdlSrcs :: Action [String]
hdlSrcs = String -> [String] -> Action [String]
getFiles String
"src-hdl" [String
"*.vhdl", String
"*.v", String
"*.ucf" ]
        ipCores :: Action [String]
ipCores = String -> [String] -> Action [String]
getFiles String
"ipcore_dir" [String
"*.xco", String
"*.xaw"]

    String
outDir String -> String -> String
<//> String
"*.tcl" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> do
        [String]
srcs1 <- Action [String]
manifestSrcs
        [String]
srcs2 <- Action [String]
hdlSrcs
        [String]
cores <- Action [String]
ipCores

        let template :: Template
template = $(TH.compileMustacheFile "template/xilinx-ise/project.tcl.mustache")
        let values :: Value
values = [Pair] -> Value
object ([Pair] -> Value) -> ([[Pair]] -> [Pair]) -> [[Pair]] -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Pair]] -> [Pair]
forall a. Monoid a => [a] -> a
mconcat ([[Pair]] -> Value) -> [[Pair]] -> Value
forall a b. (a -> b) -> a -> b
$
                     [ [ Text
"project" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
projectName ]
                     , [ Text
"top" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
topName ]
                     , XilinxTarget -> [Pair]
forall a. KeyValue a => XilinxTarget -> [a]
targetMustache XilinxTarget
fpga
                     , [ Text
"srcs" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Value]] -> [Value]
forall a. Monoid a => [a] -> a
mconcat
                         [ [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (String
rootDir String -> String -> String
</> String
src) ] | String
src <- [String]
srcs1 ]
                         , [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (String
rootDir String -> String -> String
</> String
srcDir String -> String -> String
</> String
src) ] | String
src <- [String]
srcs2 ]
                         , [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String
core ] | String
core <- [String]
cores ]
                         ]
                       ]
                     , [ Text
"ipcores" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [ [Pair] -> Value
object [ Text
"name" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> String
takeBaseName String
core ] | String
core <- [String]
cores ] ]
                     ]
        String -> String -> Action ()
forall (m :: * -> *).
(MonadIO m, HasCallStack) =>
String -> String -> m ()
writeFileChanged String
out (String -> Action ()) -> (Text -> String) -> Text -> Action ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
TL.unpack (Text -> Action ()) -> Text -> Action ()
forall a b. (a -> b) -> a -> b
$ Template -> Value -> Text
renderMustache Template
template Value
values

    String
outDir String -> String -> String
</> String
"ipcore_dir" String -> String -> String
<//> String
"*" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> do
        let src :: String
src = String
srcDir String -> String -> String
</> String -> String -> String
makeRelative String
outDir String
out
        HasCallStack => String -> String -> Action ()
String -> String -> Action ()
copyFileChanged String
src String
out

    String
outDir String -> String -> String
</> String
topName String -> String -> String
<.> String
"bit" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
_out -> do
        [String]
srcs1 <- Action [String]
manifestSrcs
        [String]
srcs2 <- Action [String]
hdlSrcs
        [String]
cores <- Action [String]
ipCores
        HasCallStack => [String] -> Action ()
[String] -> Action ()
need ([String] -> Action ()) -> [String] -> Action ()
forall a b. (a -> b) -> a -> b
$ [[String]] -> [String]
forall a. Monoid a => [a] -> a
mconcat
            [ [ String
outDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"tcl" ]
            , [ String
src | String
src <- [String]
srcs1 ]
            , [ String
srcDir String -> String -> String
</> String
src | String
src <- [String]
srcs2 ]
            , [ String
outDir String -> String -> String
</> String
core | String
core <- [String]
cores ]
            ]
        String -> [String] -> Action ()
forall t. IsCmdArgument t => String -> t -> Action ()
ise String
"xtclsh" [String
projectName String -> String -> String
<.> String
"tcl", String
"rebuild_project"]

    SynthKit -> Rules SynthKit
forall (m :: * -> *) a. Monad m => a -> m a
return (SynthKit -> Rules SynthKit) -> SynthKit -> Rules SynthKit
forall a b. (a -> b) -> a -> b
$ SynthKit :: String -> [(String, Action ())] -> SynthKit
SynthKit
        { bitfile :: String
bitfile = String
outDir String -> String -> String
</> String
topName String -> String -> String
<.> String
"bit"
        , phonies :: [(String, Action ())]
phonies =
            [ String
"ise" String -> Action () -> (String, Action ())
|> do
                   HasCallStack => [String] -> Action ()
[String] -> Action ()
need [String
outDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"tcl"]
                   String -> [String] -> Action ()
forall t. IsCmdArgument t => String -> t -> Action ()
ise String
"ise" [String
outDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"tcl"]
            ]
        }

xilinxVivado :: XilinxTarget -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
xilinxVivado :: XilinxTarget
-> ClashKit -> String -> String -> String -> Rules SynthKit
xilinxVivado XilinxTarget
fpga kit :: ClashKit
kit@ClashKit{Action [String]
[String] -> Action ()
manifestSrcs :: Action [String]
clash :: [String] -> Action ()
manifestSrcs :: ClashKit -> Action [String]
clash :: ClashKit -> [String] -> Action ()
..} String
outDir String
srcDir String
topName = do
    let projectName :: String
projectName = String
topName
        projectDir :: String
projectDir = String
outDir String -> String -> String
</> String
projectName
        xpr :: String
xpr = String
projectDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"xpr"
        rootDir :: String
rootDir = [String] -> String
joinPath ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
forall a b. a -> b -> a
const String
"..") ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitPath (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
outDir

    let vivado :: String -> t -> Action ()
vivado String
tool t
args = do
            Maybe String
root <- String -> Action (Maybe String)
getConfig String
"VIVADO_ROOT"
            Maybe String
wrap <- String -> Action (Maybe String)
getConfig String
"VIVADO"
            let exe :: [String]
exe = case (Maybe String
wrap, Maybe String
root) of
                    (Just String
wrap, Maybe String
_) -> [String
wrap, String
tool]
                    (Maybe String
Nothing, Just String
root) -> [String
root String -> String -> String
</> String
"bin" String -> String -> String
</> String
tool]
                    (Maybe String
Nothing, Maybe String
Nothing) -> String -> [String]
forall a. HasCallStack => String -> a
error String
"VIVADO_ROOT or VIVADO must be set in build.mk"
            (CmdOption -> [String] -> t -> Action ()) :-> Action ()
forall args. (HasCallStack, CmdArguments args, Unit args) => args
cmd_ (String -> CmdOption
Cwd String
outDir) [String]
exe t
args
        vivadoBatch :: String -> Action ()
vivadoBatch String
tcl = do
            HasCallStack => [String] -> Action ()
[String] -> Action ()
need [String
outDir String -> String -> String
</> String
tcl]
            String -> [String] -> Action ()
forall t. IsCmdArgument t => String -> t -> Action ()
vivado String
"vivado"
              [ String
"-mode", String
"batch"
              , String
"-nojournal"
              , String
"-nolog"
              , String
"-source", String
tcl
              ]

    let getFiles :: String -> [String] -> Action [String]
getFiles String
dir [String]
pats = String -> [String] -> Action [String]
getDirectoryFiles String
srcDir [ String
dir String -> String -> String
</> String
pat | String
pat <- [String]
pats ]
        hdlSrcs :: Action [String]
hdlSrcs = String -> [String] -> Action [String]
getFiles String
"src-hdl" [String
"*.vhdl", String
"*.v" ]
        constrSrcs :: Action [String]
constrSrcs = String -> [String] -> Action [String]
getFiles String
"src-hdl" [String
"*.xdc" ]
        ipCores :: Action [String]
ipCores = String -> [String] -> Action [String]
getFiles String
"ip" [String
"*.xci"]

    String
xpr HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> String -> Action ()
vivadoBatch String
"project.tcl"

    String
outDir String -> String -> String
</> String
"project.tcl" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> do
        [String]
srcs1 <- Action [String]
manifestSrcs
        [String]
srcs2 <- Action [String]
hdlSrcs
        [String]
cores <- Action [String]
ipCores
        [String]
constrs <- Action [String]
constrSrcs

        let template :: Template
template = $(TH.compileMustacheFile "template/xilinx-vivado/project.tcl.mustache")
        let values :: Value
values = [Pair] -> Value
object ([Pair] -> Value) -> ([[Pair]] -> [Pair]) -> [[Pair]] -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Pair]] -> [Pair]
forall a. Monoid a => [a] -> a
mconcat ([[Pair]] -> Value) -> [[Pair]] -> Value
forall a b. (a -> b) -> a -> b
$
                     [ [ Text
"rootDir" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
rootDir]
                     , [ Text
"project" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
projectName ]
                     , [ Text
"top" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
topName ]
                     , XilinxTarget -> [Pair]
forall a. KeyValue a => XilinxTarget -> [a]
targetMustache XilinxTarget
fpga
                     , [ Text
"board" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
"digilentinc.com:nexys-a7-50t:part0:1.0" ] -- TODO
                     , [ Text
"srcs" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Value]] -> [Value]
forall a. Monoid a => [a] -> a
mconcat
                         [ [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String
src ] | String
src <- [String]
srcs1 ]
                         , [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (String
srcDir String -> String -> String
</> String
src) ] | String
src <- [String]
srcs2 ]
                         ]
                       ]
                     , [ Text
"coreSrcs" Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Pair] -> Value
object
                         [ Text
"nonempty" Text -> Bool -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
cores)
                         , Text
"items" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (String
srcDir String -> String -> String
</> String
core) ] | String
core <- [String]
cores ]
                         ]
                       ]
                     , [ Text
"ipcores" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [ [Pair] -> Value
object [ Text
"name" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> String
takeBaseName String
core ] | String
core <- [String]
cores ] ]
                     , [ Text
"constraintSrcs" Text -> [Value] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [ [Pair] -> Value
object [ Text
"fileName" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (String
srcDir String -> String -> String
</> String
src) ] | String
src <- [String]
constrs ] ]
                     ]
        String -> String -> Action ()
forall (m :: * -> *).
(MonadIO m, HasCallStack) =>
String -> String -> m ()
writeFileChanged String
out (String -> Action ()) -> (Text -> String) -> Text -> Action ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
TL.unpack (Text -> Action ()) -> Text -> Action ()
forall a b. (a -> b) -> a -> b
$ Template -> Value -> Text
renderMustache Template
template Value
values

    String
outDir String -> String -> String
</> String
"build.tcl" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> do
        let template :: Template
template = $(TH.compileMustacheFile "template/xilinx-vivado/project-build.tcl.mustache")
        let values :: Value
values = [Pair] -> Value
object ([Pair] -> Value) -> ([[Pair]] -> [Pair]) -> [[Pair]] -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Pair]] -> [Pair]
forall a. Monoid a => [a] -> a
mconcat ([[Pair]] -> Value) -> [[Pair]] -> Value
forall a b. (a -> b) -> a -> b
$
                     [ [ Text
"project" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
projectName ]
                     , [ Text
"top" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
topName ]
                     ]
        String -> String -> Action ()
forall (m :: * -> *).
(MonadIO m, HasCallStack) =>
String -> String -> m ()
writeFileChanged String
out (String -> Action ()) -> (Text -> String) -> Text -> Action ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
TL.unpack (Text -> Action ()) -> Text -> Action ()
forall a b. (a -> b) -> a -> b
$ Template -> Value -> Text
renderMustache Template
template Value
values

    String
outDir String -> String -> String
</> String
"upload.tcl" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> do
        let template :: Template
template = $(TH.compileMustacheFile "template/xilinx-vivado/upload.tcl.mustache")
        let values :: Value
values = [Pair] -> Value
object ([Pair] -> Value) -> ([[Pair]] -> [Pair]) -> [[Pair]] -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Pair]] -> [Pair]
forall a. Monoid a => [a] -> a
mconcat ([[Pair]] -> Value) -> [[Pair]] -> Value
forall a b. (a -> b) -> a -> b
$
                     [ [ Text
"project" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
projectName ]
                     , [ Text
"top" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String -> Text
T.pack String
topName ]
                     , XilinxTarget -> [Pair]
forall a. KeyValue a => XilinxTarget -> [a]
targetMustache XilinxTarget
fpga
                     ]
        String -> String -> Action ()
forall (m :: * -> *).
(MonadIO m, HasCallStack) =>
String -> String -> m ()
writeFileChanged String
out (String -> Action ()) -> (Text -> String) -> Text -> Action ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
TL.unpack (Text -> Action ()) -> Text -> Action ()
forall a b. (a -> b) -> a -> b
$ Template -> Value -> Text
renderMustache Template
template Value
values

    String
projectDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"runs" String -> String -> String
</> String
"impl_1" String -> String -> String
</> String
topName String -> String -> String
<.> String
"bit" HasCallStack => String -> (String -> Action ()) -> Rules ()
String -> (String -> Action ()) -> Rules ()
%> \String
out -> do
        HasCallStack => [String] -> Action ()
[String] -> Action ()
need [String
xpr]
        String -> Action ()
vivadoBatch String
"build.tcl"

    SynthKit -> Rules SynthKit
forall (m :: * -> *) a. Monad m => a -> m a
return SynthKit :: String -> [(String, Action ())] -> SynthKit
SynthKit
        { bitfile :: String
bitfile = String
projectDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"runs" String -> String -> String
</> String
"impl_1" String -> String -> String
</> String
topName String -> String -> String
<.> String
"bit"
        , phonies :: [(String, Action ())]
phonies =
            [ String
"vivado" String -> Action () -> (String, Action ())
|> do
                   HasCallStack => [String] -> Action ()
[String] -> Action ()
need [String
xpr]
                   String -> [String] -> Action ()
forall t. IsCmdArgument t => String -> t -> Action ()
vivado String
"vivado" [String
xpr]
            , String
"upload" String -> Action () -> (String, Action ())
|> do
                   HasCallStack => [String] -> Action ()
[String] -> Action ()
need [String
projectDir String -> String -> String
</> String
projectName String -> String -> String
<.> String
"runs" String -> String -> String
</> String
"impl_1" String -> String -> String
</> String
topName String -> String -> String
<.> String
"bit"]
                   String -> Action ()
vivadoBatch String
"upload.tcl"
            ]
        }

(|>) :: String -> Action () -> (String, Action ())
|> :: String -> Action () -> (String, Action ())
(|>) = (,)