clash-shake 0.1.1 → 0.2.0
raw patch · 7 files changed
+345/−26 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Clash.Shake.Xilinx: XilinxTarget :: String -> String -> String -> String -> XilinxTarget
- Clash.Shake.Xilinx: data XilinxTarget
- Clash.Shake.Xilinx: xilinxISE :: XilinxTarget -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
- Clash.Shake.Xilinx: xilinxVivado :: XilinxTarget -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
+ Clash.Shake: (|>) :: String -> Action () -> (String, Action ())
+ Clash.Shake.Intel: Target :: String -> String -> Target
+ Clash.Shake.Intel: [targetDevice] :: Target -> String
+ Clash.Shake.Intel: [targetFamily] :: Target -> String
+ Clash.Shake.Intel: data Target
+ Clash.Shake.Intel: de0Nano :: Target
+ Clash.Shake.Intel: quartus :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
+ Clash.Shake.SymbiFlow: xilinx7 :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
+ Clash.Shake.Xilinx: Target :: String -> String -> String -> Word -> Target
+ Clash.Shake.Xilinx: data Target
+ Clash.Shake.Xilinx: ise :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
+ Clash.Shake.Xilinx: targetPart :: Target -> String
+ Clash.Shake.Xilinx: vivado :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit
- Clash.Shake.Xilinx: [targetDevice] :: XilinxTarget -> String
+ Clash.Shake.Xilinx: [targetDevice] :: Target -> String
- Clash.Shake.Xilinx: [targetFamily] :: XilinxTarget -> String
+ Clash.Shake.Xilinx: [targetFamily] :: Target -> String
- Clash.Shake.Xilinx: [targetPackage] :: XilinxTarget -> String
+ Clash.Shake.Xilinx: [targetPackage] :: Target -> String
- Clash.Shake.Xilinx: [targetSpeed] :: XilinxTarget -> String
+ Clash.Shake.Xilinx: [targetSpeed] :: Target -> Word
- Clash.Shake.Xilinx: nexysA750T :: XilinxTarget
+ Clash.Shake.Xilinx: nexysA750T :: Target
- Clash.Shake.Xilinx: papilioOne :: XilinxTarget
+ Clash.Shake.Xilinx: papilioOne :: Target
- Clash.Shake.Xilinx: papilioPro :: XilinxTarget
+ Clash.Shake.Xilinx: papilioPro :: Target
Files
- clash-shake.cabal +4/−1
- src/Clash/Shake.hs +9/−2
- src/Clash/Shake/Intel.hs +94/−0
- src/Clash/Shake/SymbiFlow.hs +100/−0
- src/Clash/Shake/Xilinx.hs +25/−21
- template/intel-quartus/project.tcl.mustache +111/−0
- template/xilinx-ise/project.tcl.mustache +2/−2
clash-shake.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: clash-shake-version: 0.1.1+version: 0.2.0 synopsis: Shake rules for building Clash programs description: Shake rules for building Clash programs and synthesizing FPGA configuration. Contains build rules for Xilinx ISE and Xilinx Vivado@@ -25,6 +25,7 @@ template/xilinx-vivado/project-build.tcl.mustache template/xilinx-vivado/project.tcl.mustache template/xilinx-vivado/upload.tcl.mustache+ template/intel-quartus/project.tcl.mustache source-repository head type: git@@ -34,6 +35,8 @@ exposed-modules: Clash.Shake Clash.Shake.Xilinx+ Clash.Shake.Intel+ Clash.Shake.SymbiFlow other-modules: Paths_clash_shake hs-source-dirs:
src/Clash/Shake.hs view
@@ -2,11 +2,15 @@ module Clash.Shake ( HDL(..) , nestedPhony+ , (|>)++ , useConfig , ClashKit(..) , clashRules , SynthKit(..)+ , binImage- , useConfig+ , toolchain ) where @@ -161,5 +165,8 @@ let exe = case (wrap, root) of (Just wrap, _) -> [wrap, tool] (Nothing, Just root) -> [root </> tool]- (Nothing, Nothing) -> error $ printf "%s or %s must be set in build.mk" (name <> "_ROOT") name+ (Nothing, Nothing) -> [tool] return $ exe ++ args++(|>) :: String -> Action () -> (String, Action ())+(|>) = (,)
+ src/Clash/Shake/Intel.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE OverloadedStrings, RecordWildCards, TemplateHaskell #-}+module Clash.Shake.Intel+ ( Target(..), de0Nano+ , quartus+ ) 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 Target = Target+ { targetFamily :: String+ , targetDevice :: String+ }++targetMustache Target{..} =+ [ "targetFamily" .= T.pack targetFamily+ , "targetDevice" .= T.pack targetDevice+ ]++de0Nano :: Target+de0Nano = Target "Cyclone IV E" "EP4CE22F17C6"++quartus :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit+quartus fpga kit@ClashKit{..} outDir srcDir topName = do+ let projectName = topName+ rootDir = joinPath . map (const "..") . splitPath $ outDir++ let quartus tool args = cmd_ (Cwd outDir) =<< toolchain "QUARTUS" tool args++ let getFiles dir pats = getDirectoryFiles srcDir [ dir </> pat | pat <- pats ]+ hdlSrcs = getFiles "src-hdl" ["*.vhdl", "*.v", "*.sv"]+ tclSrcs = getFiles "src-hdl" ["*.tcl"]+ constrSrcs = getFiles "src-hdl" ["*.sdc"]+ ipCores = getFiles "ip" ["//*.qip"]++ outDir <//> "*.tcl" %> \out -> do+ srcs1 <- manifestSrcs+ srcs2 <- hdlSrcs+ tcls <- tclSrcs+ constrs <- constrSrcs+ cores <- ipCores++ let template = $(TH.compileMustacheFile "template/intel-quartus/project.tcl.mustache")+ let values = object . mconcat $+ [ [ "project" .= T.pack projectName ]+ , [ "top" .= T.pack topName ]+ , targetMustache fpga+ , [ "srcs" .= mconcat+ [ [ object [ "fileName" .= (rootDir </> src) ] | src <- srcs1 ]+ , [ object [ "fileName" .= (rootDir </> srcDir </> src) ] | src <- srcs2 ]+ ]+ ]+ , [ "tclSrcs" .= [ object [ "fileName" .= (rootDir </> srcDir </> src) ] | src <- tcls ] ]+ , [ "ipcores" .= [ object [ "fileName" .= (rootDir </> srcDir </> core) ] | core <- cores ] ]+ , [ "constraintSrcs" .= [ object [ "fileName" .= (rootDir </> srcDir </> src) ] | src <- constrs ] ]+ ]+ writeFileChanged out . TL.unpack $ renderMustache template values++ outDir </> "ip" <//> "*" %> \out -> do+ let src = srcDir </> makeRelative outDir out+ copyFileChanged src out++ outDir </> topName <.> "sof" %> \_out -> do+ srcs1 <- manifestSrcs+ srcs2 <- hdlSrcs+ cores <- ipCores+ need $ mconcat+ [ [ outDir </> projectName <.> "tcl" ]+ , [ src | src <- srcs1 ]+ , [ srcDir </> src | src <- srcs2 ]+ , [ outDir </> core | core <- cores ]+ ]+ quartus "quartus_sh" ["-t", projectName <.> "tcl"]++ return $ SynthKit+ { bitfile = outDir </> topName <.> "sof"+ , phonies =+ [ "quartus" |> do+ need [outDir </> projectName <.> "tcl"]+ quartus "quartus_sh" ["-t", outDir </> projectName <.> "tcl"]+ ]+ }
+ src/Clash/Shake/SymbiFlow.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE OverloadedStrings, RecordWildCards, TemplateHaskell #-}+module Clash.Shake.SymbiFlow+ ( xilinx7+ ) where++import Clash.Shake+import qualified Clash.Shake.Xilinx as Xilinx++import Development.Shake+import Development.Shake.Command+import Development.Shake.FilePath+import Development.Shake.Config++xilinx7 :: Xilinx.Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit+xilinx7 target@Xilinx.Target{..} kit@ClashKit{..} outDir srcDir topName = do+ let rootDir = joinPath . map (const "..") . splitPath $ outDir++ let symbiflow' :: String -> [String] -> Action ()+ symbiflow' tool args = cmd_ (EchoStdout False) (Cwd outDir) =<< toolchain "SYMBIFLOW" tool args+ symbiflow :: String -> [String] -> Action ()+ symbiflow tool args = cmd_ (EchoStdout False) =<< toolchain "SYMBIFLOW" tool args++ let getFiles dir pats = map (srcDir </>) <$> getDirectoryFiles srcDir [ dir </> pat | pat <- pats ]+ verilogSrcs = getFiles "src-hdl" ["*.v"]+ xdcSrcs = getFiles "src-hdl" ["*.xdc" ]++ outDir </> topName <.> "eblif" %> \out -> do+ srcs <- manifestSrcs+ verilogs <- verilogSrcs+ xdcs <- xdcSrcs+ need $ verilogs <> xdcs++ symbiflow' "symbiflow_synth" $+ [ "-d", targetFamily+ , "-p", Xilinx.targetPart target+ , "-t", topName+ ] +++ [ "-v " <> rootDir </> src | src <- srcs <> verilogs ] +++ [ "-x " <> rootDir </> xdc | xdc <- xdcs ]++ outDir <//> "*.net" %> \out -> do+ let eblif = out -<.> "eblif"+ need [eblif]+ symbiflow' "symbiflow_pack" $+ [ "-d", targetDevice <> "_test"+ , "-e", takeFileName eblif+ ]++ outDir <//> "*.place" %> \out -> do+ let eblif = out -<.> "eblif"+ net = out -<.> "net"+ need [eblif, net]+ symbiflow' "symbiflow_place" $+ [ "-d", targetDevice <> "_test"+ , "-P", Xilinx.targetPart target+ , "-e", takeFileName eblif+ , "-n", takeFileName net+ ]++ outDir <//> "*.route" %> \out -> do+ let eblif = out -<.> "eblif"+ place = out -<.> "place"+ need [eblif, place]+ symbiflow' "symbiflow_route" $+ [ "-d", targetDevice <> "_test"+ , "-e", takeFileName eblif+ ]++ outDir <//> "*.fasm" %> \out -> do+ let eblif = out -<.> "eblif"+ route = out -<.> "route"+ need [eblif, route]+ symbiflow' "symbiflow_write_fasm" $+ [ "-d", targetDevice <> "_test"+ , "-e", takeFileName eblif+ ]++ outDir <//> "*.bit" %> \out -> do+ let fasm = out -<.> "fasm"+ need [fasm]+ symbiflow "symbiflow_write_bitstream" $+ [ "-d", targetFamily+ , "-p", Xilinx.targetPart target+ , "-f", fasm+ , "-b", out+ ]++ let bitfile = outDir </> topName <.> "bit"++ return SynthKit+ { bitfile = bitfile+ , phonies =+ [ "upload" |> openFPGALoader ["-c", "digilent"] bitfile+ ]+ }++openFPGALoader :: [String] -> FilePath -> Action ()+openFPGALoader args bitfile = do+ need [bitfile]+ cmd_ =<< toolchain "OPENFPGALOADER" "openFPGALoader" (args ++ [bitfile])
src/Clash/Shake/Xilinx.hs view
@@ -1,8 +1,10 @@ {-# LANGUAGE OverloadedStrings, RecordWildCards, TemplateHaskell #-} module Clash.Shake.Xilinx- ( XilinxTarget(..), papilioPro, papilioOne, nexysA750T- , xilinxISE- , xilinxVivado+ ( Target(..), targetPart+ , ise+ , vivado++ , papilioPro, papilioOne, nexysA750T ) where import Clash.Shake@@ -15,37 +17,42 @@ import Text.Mustache import qualified Text.Mustache.Compile.TH as TH import Data.Aeson+import qualified Data.Aeson.Types as Aeson import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.IO as T -data XilinxTarget = XilinxTarget+data Target = Target { targetFamily :: String , targetDevice :: String , targetPackage :: String- , targetSpeed :: String+ , targetSpeed :: Word } -targetMustache XilinxTarget{..} =+targetPart :: Target -> String+targetPart Target{..} = targetDevice <> targetPackage <> "-" <> show targetSpeed++targetMustache :: Target -> [Aeson.Pair]+targetMustache target@Target{..} = [ "targetFamily" .= T.pack targetFamily , "targetDevice" .= T.pack targetDevice , "targetPackage" .= T.pack targetPackage- , "targetSpeed" .= T.pack targetSpeed- , "part" .= T.pack (targetDevice <> targetPackage <> targetSpeed)+ , "targetSpeed" .= targetSpeed+ , "part" .= T.pack (targetPart target) ] -papilioPro :: XilinxTarget-papilioPro = XilinxTarget "Spartan6" "xc6slx9" "tqg144" "-2"+papilioPro :: Target+papilioPro = Target "Spartan6" "xc6slx9" "tqg144" 2 -papilioOne :: XilinxTarget-papilioOne = XilinxTarget "Spartan3E" "xc3s500e" "vq100" "-5"+papilioOne :: Target+papilioOne = Target "Spartan3E" "xc3s500e" "vq100" 5 -nexysA750T :: XilinxTarget-nexysA750T = XilinxTarget "Artrix7" "xc7a50t" "icsg324" "-1L"+nexysA750T :: Target+nexysA750T = Target "artix7" "xc7a50t" "csg324" 1 -xilinxISE :: XilinxTarget -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit-xilinxISE fpga kit@ClashKit{..} outDir srcDir topName = do+ise :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit+ise fpga kit@ClashKit{..} outDir srcDir topName = do let projectName = topName rootDir = joinPath . map (const "..") . splitPath $ outDir @@ -100,8 +107,8 @@ ] } -xilinxVivado :: XilinxTarget -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit-xilinxVivado fpga kit@ClashKit{..} outDir srcDir topName = do+vivado :: Target -> ClashKit -> FilePath -> FilePath -> String -> Rules SynthKit+vivado fpga kit@ClashKit{..} outDir srcDir topName = do let projectName = topName projectDir = outDir </> projectName xpr = projectDir </> projectName <.> "xpr"@@ -184,6 +191,3 @@ vivadoBatch "upload.tcl" ] }--(|>) :: String -> Action () -> (String, Action ())-(|>) = (,)
+ template/intel-quartus/project.tcl.mustache view
@@ -0,0 +1,111 @@+# Mustache template for Intel Quartus projects+# for more details see: Quartus II Handbook Version 11.0 Volume 2+# and Quartus II Scripting Reference Manual++set myScript "{{project}}.tcl"++# Load Quartus Prime Tcl Project packages+package require ::quartus::project++# Add the next line to get the execute_flow command+package require ::quartus::flow++set need_to_close_project 0+set make_assignments 1++# This procedure will open a quartus project+proc Open {prj_name} {+ global need_to_close_project+ # Check that the right project is open+ if {[is_project_open]} {+ if {[string compare $quartus(project) $prj_name]} {+ puts "Project is not open"+ set make_assignments 0+ }+ } else {+ # Only open if not already open+ if {[project_exists $prj_name]} {+ set current_revision [get_current_revision $prj_name]+ project_open -revision $current_revision $prj_name+ } else {+ project_new -revision $prj_name $prj_name+ }+ set need_to_close_project 1+ }+}++# This procedure adds files to quartus .qsf file+proc Addfile {src_file {library "lib"} } {+ if [regexp {.vhdl?$} $src_file] {+ set_global_assignment -name VHDL_FILE "$src_file" -library "$library"+ } elseif [regexp {.sv?$} $src_file] {+ set_global_assignment -name SYSTEMVERILOG_FILE "$src_file" -library "$library"+ } elseif [regexp {.v?$} $src_file] {+ set_global_assignment -name VERILOG_FILE "$src_file" -library "$library"+ } else {+ puts "Unknown file type: $src_file"+ }+ # Commit assignments+ export_assignments+}++# Open project+Open "{{project}}"++# Make assignments+if {$make_assignments} {+ set_global_assignment -name FAMILY "{{targetFamily}}"+ set_global_assignment -name DEVICE "{{targetDevice}}"+ set_global_assignment -name PROJECT_OUTPUT_DIRECTORY "./"+ set_global_assignment -name NUM_PARALLEL_PROCESSORS 2+ set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (Verilog)"+ set_global_assignment -name EDA_NETLIST_WRITER_OUTPUT_DIR ./netlist -section_id eda_simulation+ set_global_assignment -name EDA_OUTPUT_DATA_FORMAT Verilog -section_id eda_simulation+ set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON+ set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top+ set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT -section_id Top+ set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top+ set_global_assignment -name VERILOG_INPUT_VERSION SYSTEMVERILOG_2005+ set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"+ set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO"+ set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO"+ set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO"+ set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO"+ set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top++ # Setup top entity+ set_global_assignment -name TOP_LEVEL_ENTITY "{{top}}"++ # Source settings+ {{#tclSrcs}}+ source "{{fileName}}"+ {{/tclSrcs}}++ # Source constrains+ {{#constraintSrcs}}+ set_global_assignment -name SDC_FILE "{{fileName}}"+ {{/constraintSrcs}}++ puts "$myScript: Adding sources to project..."++ # Add QIP files (from ip dir)+ {{#ipcores}}+ set_global_assignment -name QIP_FILE "{{fileName}}"+ {{/ipcores}}++ # Add sources to the project+ {{#srcs}}+ Addfile "{{fileName}}"+ {{/srcs}}++ # Commit assignments+ export_assignments+}++execute_flow -compile++# Close project+if {$need_to_close_project} {+ puts "Closing project"+ project_close+}
template/xilinx-ise/project.tcl.mustache view
@@ -134,7 +134,7 @@ project set family "{{targetFamily}}" project set device "{{targetDevice}}" project set package "{{targetPackage}}"- project set speed "{{targetSpeed}}"+ project set speed "-{{targetSpeed}}" project set top_level_module_type "HDL" project set synthesis_tool "XST (VHDL/Verilog)" project set simulator "ISim (VHDL/Verilog)"@@ -176,7 +176,7 @@ if { ! [ file exists "ipcore_dir/{{name}}.vhd" ] } { puts "$myScript: Regenerating {{name}}" cd ipcore_dir- run_cg_regen "{{name}}" {{targetDevice}}{{targetSpeed}}{{targetPackage}} VHDL CURRENT+ run_cg_regen "{{name}}" "{{part}}" VHDL CURRENT cd .. } {{/ipcores}}