Skip to content

Commit

Permalink
Add design rule checking to Shake
Browse files Browse the repository at this point in the history
  • Loading branch information
martijnbastiaan committed Jul 6, 2023
1 parent 7ad875f commit d2d2c17
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 4 deletions.
48 changes: 47 additions & 1 deletion bittide-instances/bin/Shake.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Main where

import Prelude

import Control.Applicative (liftA2)
import Control.Monad.Extra (ifM, unlessM, when)
import Data.Foldable (for_)
import Development.Shake
Expand Down Expand Up @@ -225,6 +226,27 @@ getBoardPart = do
(Just _b, Just _p) ->
error "Both 'SYNTHESIS_BOARD' and 'SYNTHESIS_PART' are set, unset either and retry"

-- | Inspect DRC and timing report. Throw an error if suspicious strings were
-- found.
meetsDrcOrError :: FilePath -> FilePath -> FilePath -> IO ()
meetsDrcOrError methodologyPath summaryPath checkpointPath =
unlessM
(liftA2 (&&) (meetsTiming methodologyPath) (meetsTiming summaryPath))
(error [I.i|
Design did not meet design rule checks (DRC). Check out the timing summary at:

#{summaryPath}

Check out the methodology report at:

#{methodologyPath}

You can investigate interactively by opening the latest checkpoint with Vivado:

vivado #{checkpointPath}

|])

-- | Defines a Shake build executable for calling Vivado. Like Make, in Shake
-- you define rules that explain how to build a certain file. For example:
--
Expand Down Expand Up @@ -288,6 +310,13 @@ main = do
bitstreamPath = synthesisDir </> "bitstream.bit"
probesPath = synthesisDir </> "probes.ltx"

postSynthMethodologyPath = reportDir </> "post_synth_methodology.rpt"
postSynthTimingSummaryPath = reportDir </> "post_synth_timing_summary.rpt"

postPlaceMethodologyPath = reportDir </> "post_place_methodology.rpt"
postPlaceTimingSummaryPath = reportDir </> "post_place_timing_summary.rpt"

postRouteMethodologyPath = reportDir </> "post_route_methodology.rpt"
postRouteTimingSummaryPath = reportDir </> "post_route_timing_summary.rpt"
postRouteTimingPath = reportDir </> "post_route_timing.rpt"

Expand All @@ -296,9 +325,10 @@ main = do
routeReportsPaths =
[ reportDir </> "post_route_clock_util.rpt"
, reportDir </> "post_route_drc.rpt"
, reportDir </> "post_route_methodology.rpt"
, reportDir </> "post_route_power.rpt"
, reportDir </> "post_route_timing.rpt"
, reportDir </> "post_route_timing_summary.rpt"
, reportDir </> "post_route_timing.rpt"
, reportDir </> "post_route_util.rpt"
]

Expand Down Expand Up @@ -351,6 +381,11 @@ main = do
-- also depend on the dependencies' manifest files, etc.
need [runSynthTclPath, manifestPath]
vivadoFromTcl runSynthTclPath
liftIO $
meetsDrcOrError
postSynthMethodologyPath
postSynthTimingSummaryPath
postSynthCheckpointPath

-- Placement
runPlaceTclPath %> \path -> do
Expand All @@ -359,6 +394,11 @@ main = do
(postPlaceCheckpointPath : placeReportPaths) |%> \_ -> do
need [runPlaceTclPath, postSynthCheckpointPath]
vivadoFromTcl runPlaceTclPath
liftIO $
meetsDrcOrError
postPlaceMethodologyPath
postPlaceTimingSummaryPath
postPlaceCheckpointPath

-- Routing
runRouteTclPath %> \path -> do
Expand All @@ -368,6 +408,12 @@ main = do
need [runRouteTclPath, postPlaceCheckpointPath]
vivadoFromTcl runRouteTclPath

liftIO $
meetsDrcOrError
postRouteMethodologyPath
postRouteTimingSummaryPath
postRouteCheckpointPath

-- Design should meet timing post routing. Note that this is not a
-- requirement after synthesis as many of the optimizations only follow
-- after.
Expand Down
1 change: 1 addition & 0 deletions bittide-instances/bittide-instances.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ common common-options
containers,
cryptohash-sha256,
elastic-buffer-sim,
extra,
filepath,
ghc-typelits-extra,
ghc-typelits-knownnat,
Expand Down
30 changes: 27 additions & 3 deletions bittide-instances/src/Clash/Shake/Vivado.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ module Clash.Shake.Vivado
, mkBoardProgramTcl
, mkHardwareTestTcl
, meetsTiming
, meetsDrc
) where

import Prelude

import Development.Shake
import Development.Shake.Extra (decodeFile)

import Control.Monad.Extra (andM, orM)
import Clash.DataFiles (tclConnector)
import Clash.Driver.Manifest
import Data.List (isInfixOf, intercalate)
Expand All @@ -42,11 +44,30 @@ import Clash.Shake.Flags (HardwareTargets(..))

import Paths_bittide_instances

-- | Satisfied if all actions result in 'False'
noneM :: Monad m => [m Bool] -> m Bool
noneM = fmap not . orM

-- | Whether a string occurs in a file
inFile :: String -> FilePath -> IO Bool
inFile msg path = do
content <- readFile path
pure $ (msg `isInfixOf` content)

-- | Read a timing summary or DRC report and determine whether it passed DRC
-- checks.
meetsDrc :: FilePath -> IO Bool
meetsDrc path = noneM
[ inFile "No report available as report_methodology has not been run prior." path
, inFile "Critical Warning" path
]

-- | Read a timing summary and determine whether it met timing.
meetsTiming :: FilePath -> IO Bool
meetsTiming reportPath = do
reportContents <- readFile reportPath
pure $ not ("Timing constraints are not met." `isInfixOf` reportContents)
meetsTiming path = andM
[ meetsDrc path -- for safety; users should use meetDrc for useful error reporting
, fmap not $ inFile "Timing constraints are not met" path
]

-- TODO: Upstream
data LocatedManifest = LocatedManifest
Expand Down Expand Up @@ -151,6 +172,7 @@ mkSynthesisTcl outputDir outOfContext boardPart constraints manifest@LocatedMani

\# Synthesis
synth_design -name #{name} -mode #{outOfContextStr}
report_methodology -file {#{outputDir </> "reports" </> "post_synth_methodology.rpt"}}
report_timing_summary -file {#{outputDir </> "reports" </> "post_synth_timing_summary.rpt"}}
report_utilization -file {#{outputDir </> "reports" </> "post_synth_util.rpt"}}
write_checkpoint -force {#{outputDir </> "checkpoints" </> "post_synth.dcp"}}
Expand Down Expand Up @@ -191,6 +213,7 @@ mkPlaceTcl outputDir = [__i|
place_design
phys_opt_design
write_checkpoint -force {#{outputDir </> "checkpoints" </> "post_place.dcp"}}
report_methodology -file {#{outputDir </> "reports" </> "post_place_methodology.rpt"}}
report_timing_summary -file {#{outputDir </> "reports" </> "post_place_timing_summary.rpt"}}
|]

Expand All @@ -204,6 +227,7 @@ mkRouteTcl outputDir = [__i|
\# Routing
route_design
write_checkpoint -force {#{outputDir </> "checkpoints" </> "post_route.dcp"}}
report_methodology -file {#{outputDir </> "reports" </> "post_route_methodology.rpt"}}
report_timing_summary -file {#{outputDir </> "reports" </> "post_route_timing_summary.rpt"}}
report_timing -sort_by group -max_paths 100 -path_type summary -file {#{outputDir </> "reports" </> "post_route_timing.rpt"}}

Expand Down

0 comments on commit d2d2c17

Please sign in to comment.