clash-lib 1.8.4 → 1.8.5
raw patch · 25 files changed
+220/−74 lines, 25 filesdep ~clash-preludePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: clash-prelude
API changes (from Hackage documentation)
+ Clash.Core.Subst: acmpTerm :: Term -> Term -> Ordering
+ Clash.Core.Term: Attributes :: Type -> Term -> TickInfo
+ Clash.Driver.Types: [opt_ghcDebugLevel] :: ClashOpts -> Int
+ Clash.Netlist.Types: [_localAttrs] :: NetlistEnv -> [Attr Text]
+ Clash.Netlist.Types: [_peEvaluator] :: NetlistEnv -> Evaluator
+ Clash.Netlist.Types: localAttrs :: Lens' NetlistEnv [Attr Text]
+ Clash.Netlist.Types: peEvaluator :: Lens' NetlistEnv Evaluator
- Clash.Driver.Types: ClashOpts :: Bool -> Int -> Int -> Word -> Word -> Word -> DebugOpts -> Bool -> Bool -> Bool -> OverridingBool -> Int -> Maybe String -> HdlSyn -> Bool -> [FilePath] -> Maybe Text -> Bool -> Bool -> PreserveCase -> Bool -> Maybe (Maybe Int) -> Bool -> Bool -> Bool -> Word -> Bool -> Bool -> Period -> ClashOpts
+ Clash.Driver.Types: ClashOpts :: Bool -> Int -> Int -> Word -> Word -> Word -> DebugOpts -> Int -> Bool -> Bool -> Bool -> OverridingBool -> Int -> Maybe String -> HdlSyn -> Bool -> [FilePath] -> Maybe Text -> Bool -> Bool -> PreserveCase -> Bool -> Maybe (Maybe Int) -> Bool -> Bool -> Bool -> Word -> Bool -> Bool -> Period -> ClashOpts
- Clash.Netlist: genNetlist :: ClashEnv -> Bool -> BindingMap -> VarEnv TopEntityT -> VarEnv Identifier -> (CustomReprs -> TyConMap -> Type -> State HWMap (Maybe (Either String FilteredHWType))) -> Bool -> SomeBackend -> IdentifierSet -> FilePath -> Maybe Text -> Id -> IO (Component, ComponentMap, IdentifierSet)
+ Clash.Netlist: genNetlist :: ClashEnv -> Evaluator -> Bool -> BindingMap -> VarEnv TopEntityT -> VarEnv Identifier -> (CustomReprs -> TyConMap -> Type -> State HWMap (Maybe (Either String FilteredHWType))) -> Bool -> SomeBackend -> IdentifierSet -> FilePath -> Maybe Text -> Id -> IO (Component, ComponentMap, IdentifierSet)
- Clash.Netlist: runNetlistMonad :: ClashEnv -> Bool -> BindingMap -> VarEnv TopEntityT -> (CustomReprs -> TyConMap -> Type -> State HWMap (Maybe (Either String FilteredHWType))) -> Bool -> SomeBackend -> IdentifierSet -> FilePath -> VarEnv Identifier -> NetlistMonad a -> IO (a, NetlistState)
+ Clash.Netlist: runNetlistMonad :: ClashEnv -> Evaluator -> Bool -> BindingMap -> VarEnv TopEntityT -> (CustomReprs -> TyConMap -> Type -> State HWMap (Maybe (Either String FilteredHWType))) -> Bool -> SomeBackend -> IdentifierSet -> FilePath -> VarEnv Identifier -> NetlistMonad a -> IO (a, NetlistState)
- Clash.Netlist.Types: NetlistEnv :: ClashEnv -> Text -> Text -> Maybe Text -> NetlistEnv
+ Clash.Netlist.Types: NetlistEnv :: ClashEnv -> Text -> Text -> Maybe Text -> [Attr Text] -> Evaluator -> NetlistEnv
- Clash.Rewrite.Types: bindings :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) BindingMap
+ Clash.Rewrite.Types: bindings :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) BindingMap
- Clash.Rewrite.Types: curFun :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) (Id, SrcSpan)
+ Clash.Rewrite.Types: curFun :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) (Id, SrcSpan)
- Clash.Rewrite.Types: extra :: forall extra_a4GHC extra_a4GSV. Lens (RewriteState extra_a4GHC) (RewriteState extra_a4GSV) extra_a4GHC extra_a4GSV
+ Clash.Rewrite.Types: extra :: forall extra_a4HGd extra_a4HRw. Lens (RewriteState extra_a4HGd) (RewriteState extra_a4HRw) extra_a4HGd extra_a4HRw
- Clash.Rewrite.Types: globalHeap :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) PrimHeap
+ Clash.Rewrite.Types: globalHeap :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) PrimHeap
- Clash.Rewrite.Types: nameCounter :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) Int
+ Clash.Rewrite.Types: nameCounter :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) Int
- Clash.Rewrite.Types: transformCounter :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) Word
+ Clash.Rewrite.Types: transformCounter :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) Word
- Clash.Rewrite.Types: transformCounters :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) (HashMap Text Word)
+ Clash.Rewrite.Types: transformCounters :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) (HashMap Text Word)
- Clash.Rewrite.Types: uniqSupply :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) Supply
+ Clash.Rewrite.Types: uniqSupply :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) Supply
- Clash.Rewrite.Types: workFreeBinders :: forall extra_a4GHC. Lens' (RewriteState extra_a4GHC) (VarEnv Bool)
+ Clash.Rewrite.Types: workFreeBinders :: forall extra_a4HGd. Lens' (RewriteState extra_a4HGd) (VarEnv Bool)
Files
- CHANGELOG.md +21/−1
- clash-lib.cabal +3/−3
- prims/common/Clash_Annotations_SynthesisAttributes.primitives.yaml +3/−0
- prims/commonverilog/Clash_Sized_Internal_Signed.primitives.yaml +2/−2
- prims/systemverilog/Clash_Signal_Internal.primitives.yaml +1/−1
- prims/verilog/Clash_Signal_Internal.primitives.yaml +1/−1
- prims/vhdl/Clash_Signal_Internal.primitives.yaml +1/−1
- src/Clash/Core/EqSolver.hs +3/−3
- src/Clash/Core/Evaluator/Types.hs +2/−2
- src/Clash/Core/FreeVars.hs +2/−0
- src/Clash/Core/Pretty.hs +5/−4
- src/Clash/Core/Subst.hs +2/−0
- src/Clash/Core/Subst.hs-boot +5/−0
- src/Clash/Core/Term.hs +11/−5
- src/Clash/Core/TermLiteral.hs +1/−0
- src/Clash/Driver.hs +1/−1
- src/Clash/Driver/Types.hs +7/−1
- src/Clash/Netlist.hs +35/−19
- src/Clash/Netlist/Types.hs +6/−0
- src/Clash/Netlist/Util.hs +64/−7
- src/Clash/Normalize.hs +19/−6
- src/Clash/Normalize/Transformations/Cast.hs +2/−2
- src/Clash/Primitives/Sized/Signed.hs +1/−1
- src/Clash/Primitives/Sized/ToInteger.hs +1/−1
- src/Clash/Primitives/Verification.hs +21/−13
CHANGELOG.md view
@@ -1,5 +1,25 @@ # Changelog for the Clash project +## 1.8.5 *Mar 24th, 2026*++Added:+* `Clash.Annotation.SynthesisAtrributes.annotateReg`, a function to add synthesis attributes (e.g. `ASYNC_REG`) to register declarations in the HDL generated by the Clash compiler.+ [#3093](https://github.com/clash-lang/clash-compiler/pull/3093)+* `registerSyncReset` [#3115](https://github.com/clash-lang/clash-compiler/issues/3115)++Fixed:+* The `Clash.Explicit.Verification.check` blackbox now correctly uses the given clock line, not assuming any longer that it is already bound to an identifier in the first place. [#2907](https://github.com/clash-lang/clash-compiler/issues/2907)+* The type of string literals passed to the `Clash.Explicit.Verification.check` blackbox now matches with the input provided via `Clash.Explicit.Verification.name`. [#2908](https://github.com/clash-lang/clash-compiler/issues/2908)+* `toInteger`, `toEnum`, and `fromEnum` now correctly sign extend when using Verilog backend. [#2729](https://github.com/clash-lang/clash-compiler/issues/2729).+* `dumpVCD` now properly aligns the first clock edges in multi-domain designs. [#3075](https://github.com/clash-lang/clash-compiler/issues/3075)+* Removed the limit on the number of traces in `dumpVCD`. Also removed unnecessary double newlines after 1-bit signals. [#3082](https://github.com/clash-lang/clash-compiler/issues/3082)+* In Clash simulation, `pack` for `Vec` and `RTree` had all bits undefined when the spine of the value had an `XException`. Now, those elements with defined bits will output those defined bits. In HDL, this was already the case. Example: consider `xs = 1 :> undefined :> Nil :: Vec 2 (Unsigned 4)` and `ys = 1 :> undefined :: Vec 2 (Unsigned 4)`. `xs` merely has an undefined element, but `ys` has an undefined spine: it is a `:>` constructor that is undefined. `pack ys` used to be `0b...._....` but is now `0b0001_....`, just as `pack xs` already was.+ [#3114](https://github.com/clash-lang/clash-compiler/pull/3114)+* Clash drops cached normalization result. [#3109](https://github.com/clash-lang/clash-compiler/issues/3109)+* Fix `holdReset` glitch behavior for asynchronous resets and wrong hold cycles for sync resets. [#3115](https://github.com/clash-lang/clash-compiler/issues/3115)+* Do not emit source locations if `-g` is not passed to clash [#3132](https://github.com/clash-lang/clash-compiler/issues/3132)+* `clash-ghc`: Remove `Opt_LlvmTBAA` from unwanted flags [#2508](https://github.com/clash-lang/clash-compiler/issues/2823)+ ## 1.8.4 *Nov 6th 2025* Changed:@@ -314,7 +334,7 @@ Added: * `Clash.Class.Counter`: a class that defines a odometer-style supercounter. [#1763](https://github.com/clash-lang/clash-compiler/pull/1763) * `isLike` function for BitPack types. [#1774](https://github.com/clash-lang/clash-compiler/pull/1774)- * 'seqErrorX' for catching both `XException` and `ErrorCall`. [#1774](https://github.com/clash-lang/clash-compiler/pull/1774)+ * 'seqErrorX' for catching both `XException` and `ErrorCall`. [#1839](https://github.com/clash-lang/clash-compiler/pull/1839) * `Clash.Explicit.BlockRam.File.memFile`, a function for creating the contents of the data files this blockRAM uses. Can also be imported from `Clash.Prelude.BlockRam.File`, `Clash.Prelude.ROM.File` and `Clash.Explicit.ROM.File`. [#1840](https://github.com/clash-lang/clash-compiler/pull/1840) * Support for Yosys compatible SVA to `Clash.Verification`. This enables formal verification using SymbiYosis for Verilog and SystemVerilog. [#1798](https://github.com/clash-lang/clash-compiler/pull/1798) * `Clash.Explicit.Signal.Delayed.forward`, a function that can be used to retime a `DSignal` into the future without applying any logic. [#1882](https://github.com/clash-lang/clash-compiler/pull/1882)
clash-lib.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.2 Name: clash-lib-Version: 1.8.4+Version: 1.8.5 Synopsis: Clash: a functional hardware description language - As a library Description: Clash is a functional hardware description language that borrows both its@@ -151,7 +151,7 @@ base16-bytestring >= 0.1.1 && < 1.1, binary >= 0.8.5 && < 0.11, bytestring >= 0.10.0.2 && < 0.13,- clash-prelude == 1.8.4,+ clash-prelude == 1.8.5, containers >= 0.5.0.0 && < 0.8, cryptohash-sha256 >= 0.11 && < 0.12, data-binary-ieee754 >= 0.4.4 && < 0.6,@@ -380,7 +380,7 @@ build-depends: base, clash-lib,- doctest-parallel >= 0.2 && < 0.4,+ doctest-parallel >= 0.2 && < 0.5, filepath test-suite unittests
+ prims/common/Clash_Annotations_SynthesisAttributes.primitives.yaml view
@@ -0,0 +1,3 @@+- Primitive:+ name: Clash.Annotations.SynthesisAttributes.annotateReg+ primType: Function
prims/commonverilog/Clash_Sized_Internal_Signed.primitives.yaml view
@@ -44,7 +44,7 @@ type: 'fromEnum# :: KnownNat n => Signed n -> Int' template: ~IF~SIZE[~TYP[1]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]])- {1'b0}},~VAR[i][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI+ {~VAR[i][1][~SIZE[~TYP[1]]-1]}},~VAR[i][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI workInfo: Never - BlackBox: name: Clash.Sized.Internal.Signed.size#@@ -118,7 +118,7 @@ type: 'toEnum# :: KnownNat n => Int -> Signed n' template: ~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]])- {1'b0}},~VAR[i][1]})~FI+ {~VAR[i][1][~SIZE[~TYP[1]]-1]}},~VAR[i][1]})~FI workInfo: Never - BlackBox: name: Clash.Sized.Internal.Signed.plus#
prims/systemverilog/Clash_Signal_Internal.primitives.yaml view
@@ -94,7 +94,7 @@ => Signal dom Bool -- ARG[1] -> Clock dom template: |-- // tbClockGen begin+ // ~IF~ISACTIVEENABLE[1]~THENtbClockGen~ELSEclockGen~FI begin // pragma translate_off // 1 = 0.1ps localparam ~GENSYM[half_period][0] = (~PERIOD[0]0 / 2);
prims/verilog/Clash_Signal_Internal.primitives.yaml view
@@ -93,7 +93,7 @@ => Signal dom Bool -- ARG[1] -> Clock dom template: |-- // tbClockGen begin+ // ~IF~ISACTIVEENABLE[1]~THENtbClockGen~ELSEclockGen~FI begin // pragma translate_off reg ~TYPO ~GENSYM[clk][0]; // 1 = 0.1ps
prims/vhdl/Clash_Signal_Internal.primitives.yaml view
@@ -141,7 +141,7 @@ => Signal dom Bool -- ARG[1] -> Clock dom template: |-- -- tbClockGen begin+ -- ~IF~ISACTIVEENABLE[1]~THENtbClockGen~ELSEclockGen~FI begin -- pragma translate_off ~GENSYM[clkGen][0] : process is constant ~GENSYM[half_periodH][1] : time := ~PERIOD[0]000 fs / 2;
src/Clash/Core/EqSolver.hs view
@@ -92,7 +92,7 @@ [] -- | Solve equations supported by @normalizeAdd@. See documentation of--- @TypeEqSolution@ to understand the return value.+-- 'TypeEqSolution' to understand the return value. solveAdd :: VarSet -> (Type, Type)@@ -134,7 +134,7 @@ lhsLit _ _ = Nothing -- | Tests for nonsencical patterns due to types being "absurd". See--- @isAbsurdEq@ for more info.+-- 'isAbsurdEq' for more info. isAbsurdPat :: TyConMap -> Pat@@ -152,7 +152,7 @@ DataPat _dc extNms _ids -> mkVarSet extNms _ -> emptyVarSet --- | Determines if an "equation" obtained through @patEqs@ or @typeEq@ is+-- | Determines if an "equation" obtained through 'patEqs' or 'typeEq' is -- absurd. That is, it tests if two types that are definitely not equal are -- asserted to be equal OR if the computation of the types yield some absurd -- (intermediate) result such as -1.
src/Clash/Core/Evaluator/Types.hs view
@@ -80,10 +80,10 @@ -- define partial evaluation. In this implementation, it consists of two types -- of function: ----- * steps, which applies the reduction realtion to the current term+-- * steps, which applies the reduction relation to the current term -- * unwindings, which pop the stack and evaluate the stack frame ----- Variants of these functions also exist for evalauting primitive operations.+-- Variants of these functions also exist for evaluating primitive operations. -- This is because there may be multiple frontends to the compiler which can -- reuse a common step and unwind, but have different primitives. --
src/Clash/Core/FreeVars.hs view
@@ -281,6 +281,8 @@ goTick inLocalScope = \case NameMod m ty -> NameMod m <$> typeFreeVars' interesting inLocalScope f ty+ Attributes ty tm -> Attributes <$> typeFreeVars' interesting inLocalScope f ty+ <*> go inLocalScope tm tick -> pure tick -- | Get the free variables of an expression and count the number of occurrences
src/Clash/Core/Pretty.hs view
@@ -246,7 +246,7 @@ pprPrec _ = pure . pretty instance PrettyPrec Type where- pprPrec _ t = annotate (AnnSyntax Type) <$> pprType t+ pprPrec _ t = pprType t instance ClashPretty Type where clashPretty = fromPpr@@ -265,7 +265,7 @@ name <- pprPrec prec dc ty <- pprType (dcType dc) - pure (name <+> dcolon <+> ty)+ pure (name <> annotate (AnnSyntax Type) (space <> dcolon <+> ty)) AlgTyCon _ nm kn _ (NewTyCon dc _) _ -> do name <- pprPrec prec nm@@ -275,7 +275,7 @@ conName <- pprPrec prec (dcName dc) conType <- pprType (dcType dc) - pure (vsep [newtype_ <+> decl, conName <+> dcolon <+> conType])+ pure (vsep [newtype_ <+> decl, conName <> annotate (AnnSyntax Type) (space <> dcolon <+> conType)]) PromotedDataCon _ _ _ _ dc -> fmap ("promoted" <+>) (pprPrec prec dc)@@ -313,7 +313,7 @@ Var x -> do v <- pprPrec prec (varName x) s <- pprPrecIdScope x- pure (v <> brackets s)+ pure (v <> annotate (AnnSyntax Unique) (brackets s)) Data dc -> pprPrec prec dc Literal l -> pprPrec prec l Prim p -> pprPrecPrim prec (primName p)@@ -341,6 +341,7 @@ pprPrec prec (NameMod SetName t) = ("<setName>" <>) <$> pprPrec prec t pprPrec _ DeDup = pure "<deDup>" pprPrec _ NoDeDup = pure "<noDeDup>"+ pprPrec prec (Attributes _ attrs) = ("<attributes>" <>) <$> pprPrec prec attrs instance PrettyPrec SrcSpan where pprPrec _ sp = return ("<src>"<>pretty (GHC.showSDocUnsafe (GHC.ppr sp)))
src/Clash/Core/Subst.hs view
@@ -56,6 +56,7 @@ -- * Alpha equivalence , aeqType , aeqTerm+ , acmpTerm -- * Structural equivalence , eqTerm , eqType@@ -584,6 +585,7 @@ goTick (NameMod m ty) = NameMod m (substTy subst ty) goTick t@DeDup = t goTick t@NoDeDup = t+ goTick (Attributes ty tm) = Attributes (substTy subst ty) (go tm) -- | Substitute within a case-alternative substAlt
src/Clash/Core/Subst.hs-boot view
@@ -3,6 +3,7 @@ module Clash.Core.Subst where import GHC.Stack (HasCallStack)+import {-# SOURCE #-} Clash.Core.Term (Term) import {-# SOURCE #-} Clash.Core.Type (Type) import Clash.Core.Var (TyVar) @@ -20,3 +21,7 @@ instance Eq Type instance Ord Type++acmpTerm :: Term -> Term -> Ordering++instance Eq Term
src/Clash/Core/Term.hs view
@@ -81,7 +81,7 @@ import Clash.Core.DataCon (DataCon) import Clash.Core.Literal (Literal) import Clash.Core.Name (Name (..))-import {-# SOURCE #-} Clash.Core.Subst () -- instance Eq/Ord Type+import {-# SOURCE #-} Clash.Core.Subst (acmpTerm) -- instance Eq/Ord Type, Eq Term import {-# SOURCE #-} Clash.Core.Type (Type) import Clash.Core.Var (Var, Id, TyVar) import Clash.Util (curLoc, thenCompare)@@ -124,19 +124,25 @@ | NoDeDup -- ^ Do not deduplicate, i.e. /keep/, an expression inside a case-alternative; -- do not try to share expressions between multiple branches.+ | Attributes Type Term+ -- ^ Synthesis attributes brough into scope by+ -- 'Clash.Annotations.SynthesisAttributes.annotateReg' deriving (Eq, Show, Generic, NFData, Binary) instance Ord TickInfo where compare (SrcSpan s1) (SrcSpan s2) = leftmost_smallest s1 s2 compare (NameMod m1 t1) (NameMod m2 t2) = compare m1 m2 `thenCompare` compare t1 t2+ compare (Attributes t1 a1) (Attributes t2 a2) =+ compare t1 t2 `thenCompare` acmpTerm a1 a2 compare t1 t2 = compare (getRank t1) (getRank t2) where getRank :: TickInfo -> Word- getRank SrcSpan{} = 0- getRank NameMod{} = 1- getRank DeDup = 2- getRank NoDeDup = 3+ getRank SrcSpan{} = 0+ getRank NameMod{} = 1+ getRank DeDup = 2+ getRank NoDeDup = 3+ getRank Attributes {} = 4 -- | Tag to indicate which instance/register name modifier was used data NameMod
src/Clash/Core/TermLiteral.hs view
@@ -129,6 +129,7 @@ instance TermLiteral Integer where termToData (Tick _ e) = termToData e termToData (Literal (IntegerLiteral n)) = Right n+ termToData (collectArgs -> (_, [Left (Literal (IntLiteral n))])) = Right n termToData (collectArgs -> (_, [Left (Literal (IntegerLiteral n))])) = Right n termToData t = Left t
src/Clash/Driver.hs view
@@ -458,7 +458,7 @@ (topComponent, netlist) <- modifyMVar seenV $ \seen -> do (topComponent, netlist, seen') <- -- TODO My word, this has far too many arguments.- genNetlist env isTb transformedBindings topEntityMap compNames+ genNetlist env peEval isTb transformedBindings topEntityMap compNames typeTrans ite (SomeBackend hdlState') seen hdlDir prefixM topEntity pure (seen', (topComponent, netlist))
src/Clash/Driver/Types.hs view
@@ -2,8 +2,8 @@ Copyright : (C) 2013-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017 , QBayLogic, Google Inc.,- 2020-2022, QBayLogic, 2022 , Google Inc.,+ 2020-2026, QBayLogic, License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> @@ -322,6 +322,11 @@ -- Command line flag: -fclash-evaluator-fuel-limit , opt_debug :: DebugOpts -- ^ Options which control debugging. See 'DebugOpts'.+ , opt_ghcDebugLevel :: Int+ -- ^ What the GHC debug level is (i.e. @-g<N>@).+ --+ -- Clash uses this to decide whether to emit source-location information in+ -- generated HDL. , opt_cachehdl :: Bool -- ^ Reuse previously generated output from Clash. Only caches topentities. --@@ -411,6 +416,7 @@ , opt_inlineConstantLimit = 0 , opt_evaluatorFuelLimit = 20 , opt_debug = debugNone+ , opt_ghcDebugLevel = 0 , opt_cachehdl = True , opt_clear = False , opt_primWarn = True
src/Clash/Netlist.hs view
@@ -2,8 +2,8 @@ Copyright : (C) 2012-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017-2018, Google Inc.,- 2021-2024, QBayLogic B.V.- 2022 , Google Inc.+ 2022 , Google Inc.,+ 2021-2026, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> @@ -84,11 +84,13 @@ import Clash.Primitives.Types as P import Clash.Util import qualified Clash.Util.Interpolate as I+import Clash.Core.PartialEval (Evaluator) -- | Generate a hierarchical netlist out of a set of global binders with -- @topEntity@ at the top. genNetlist :: ClashEnv+ -> Evaluator -> Bool -- ^ Whether this we're compiling a testbench (suppresses certain warnings) -> BindingMap@@ -113,9 +115,9 @@ -> Id -- ^ Name of the @topEntity@ -> IO (Component, ComponentMap, IdentifierSet)-genNetlist env isTb globals tops topNames typeTrans ite be seen0 dir prefixM topEntity = do+genNetlist env eval isTb globals tops topNames typeTrans ite be seen0 dir prefixM topEntity = do ((_meta, topComponent), s) <-- runNetlistMonad env isTb globals tops typeTrans ite be seen1 dir componentNames_+ runNetlistMonad env eval isTb globals tops typeTrans ite be seen1 dir componentNames_ $ genComponent topEntity return (topComponent, _components s, seen1) where@@ -125,6 +127,7 @@ -- | Run a NetlistMonad action in a given environment runNetlistMonad :: ClashEnv+ -> Evaluator -> Bool -- ^ Whether this we're compiling a testbench (suppresses certain warnings) -> BindingMap@@ -147,8 +150,8 @@ -> NetlistMonad a -- ^ Action to run -> IO (a, NetlistState)-runNetlistMonad env isTb s tops typeTrans ite be seenIds_ dir componentNames_- = flip runReaderT (NetlistEnv env "" "" Nothing)+runNetlistMonad env eval isTb s tops typeTrans ite be seenIds_ dir componentNames_+ = flip runReaderT (NetlistEnv env "" "" Nothing [] eval) . flip runStateT s' . runNetlist where@@ -308,16 +311,33 @@ return (ComponentMeta wereVoids sp ids u, component) mkNetDecl :: (Id, Term) -> NetlistMonad [Declaration]-mkNetDecl (id_,tm) = preserveVarEnv $ do- hwTy <- unsafeCoreTypeToHWTypeM' $(curLoc) (coreTypeOf id_)+mkNetDecl (id_,tm) | (_,_,ticks) <- collectArgsTicks tm = preserveVarEnv $ withTicks ticks $ \_ -> do + lAttrs <- Lens.view localAttrs+ hwTy0 <- unsafeCoreTypeToHWTypeM' $(curLoc) (coreTypeOf id_)+ let hwTy = case hwTy0 of+ Annotated attrs hty0 -> Annotated (attrs ++ lAttrs) hty0+ hty0 -> annotated lAttrs hty0++ -- GHC starts including sources notes on any debug level greater than 0+ -- we copy this behaviour here.+ emitLocs <- (>0) . opt_ghcDebugLevel <$> Lens.view clashOpts+ let+ srcNote =+ if emitLocs then+ addSrcNote $ case tm of+ Tick (SrcSpan s) _ -> s+ _ -> nameLoc (varName id_)+ else+ Nothing+ if | not (shouldRenderDecl hwTy tm) -> return [] | (Prim pInfo@PrimInfo{primMultiResult=MultiResult}, args) <- collectArgs tm ->- multiDecls pInfo args- | otherwise -> pure <$> singleDecl hwTy+ multiDecls srcNote pInfo args+ | otherwise -> pure <$> singleDecl srcNote hwTy where- multiDecls pInfo args0 = do+ multiDecls srcNote pInfo args0 = do tcm <- Lens.view tcCache resInits0 <- getResInits (id_, tm) let@@ -331,7 +351,7 @@ hwTys <- mapM (unsafeCoreTypeToHWTypeM' $(curLoc)) (mpi_resultTypes mpInfo) pure (zipWith3 netdecl res hwTys resInits1) - singleDecl hwTy = do+ singleDecl srcNote hwTy = do rIM <- listToMaybe <$> getResInits (id_, tm) return (NetDecl' srcNote (Id.unsafeFromCoreId id_) hwTy rIM) @@ -339,10 +359,6 @@ | isGoodSrcSpan loc = Just (StrictText.pack (showSDocUnsafe (ppr loc))) | otherwise = Nothing - srcNote = addSrcNote $ case tm of- Tick (SrcSpan s) _ -> s- _ -> nameLoc (varName id_)- isMultiPrimSelect :: Term -> Bool isMultiPrimSelect t = case collectArgs t of (Prim (primName -> "c$multiPrimSelect"), _) -> True@@ -356,16 +372,16 @@ -- Set the initialization value of a signal when a primitive wants to set it getResInits :: (Id, Term) -> NetlistMonad [Expr]- getResInits (i,collectArgsTicks -> (k,args0,ticks)) = case k of+ getResInits (i,collectArgs -> (k,args0)) = case k of Prim p -> extractPrimWarnOrFail (primName p) >>= go p _ -> return [] where- go pInfo (BlackBox {resultInits=nmDs, multiResult=True}) = withTicks ticks $ \_ -> do+ go pInfo (BlackBox {resultInits=nmDs, multiResult=True}) = do tcm <- Lens.view tcCache let (args1, res) = splitMultiPrimArgs (multiPrimInfo' tcm pInfo) args0 (bbCtx, _) <- mkBlackBoxContext (primName pInfo) Concurrent res args1 mapM (go' (primName pInfo) bbCtx) nmDs- go pInfo (BlackBox {resultInits=nmDs}) = withTicks ticks $ \_ -> do+ go pInfo (BlackBox {resultInits=nmDs}) = do (bbCtx, _) <- mkBlackBoxContext (primName pInfo) Concurrent [i] args0 mapM (go' (primName pInfo) bbCtx) nmDs go _ _ = pure []
src/Clash/Netlist/Types.hs view
@@ -75,6 +75,7 @@ import Clash.Annotations.TopEntity (TopEntity) import Clash.Backend (Backend, HasUsageMap (..)) import Clash.Core.HasType+import Clash.Core.PartialEval (Evaluator) import Clash.Core.Type (Type) import Clash.Core.Var (Id) import Clash.Core.TyCon (TyConMap)@@ -282,6 +283,11 @@ -- ^ Postfix for instance/register names , _setName :: Maybe Text -- ^ (Maybe) user given instance/register name+ , _localAttrs :: [Attr Text]+ -- ^ Synthesis attributes brough into scope by+ -- 'Clash.Annotations.SynthesisAttributes.annotateReg'+ , _peEvaluator :: Evaluator+ -- ^ Evaluator to evaluate a term to Normal Form } data ComponentMeta = ComponentMeta
src/Clash/Netlist/Util.hs view
@@ -55,6 +55,7 @@ import Data.Maybe (catMaybes, fromMaybe, isNothing, mapMaybe, isJust, listToMaybe, maybeToList) import Text.Printf (printf)+import Data.Proxy import Data.Text (Text) import qualified Data.Text as Text import Data.Text.Extra (showt)@@ -68,6 +69,8 @@ #endif import GHC.Stack (HasCallStack)+import GHC.TypeLits (someNatVal)+import GHC.TypeNats (SomeNat(..)) #if MIN_VERSION_ghc(9,0,0) import GHC.Utils.Monad (zipWith3M)@@ -90,11 +93,12 @@ import Clash.Core.DataCon (DataCon (..)) import Clash.Core.EqSolver (typeEq) import Clash.Core.FreeVars (typeFreeVars, typeFreeVars')-import Clash.Core.HasFreeVars (elemFreeVars)+import Clash.Core.HasFreeVars (elemFreeVars, isClosed) import Clash.Core.HasType import qualified Clash.Core.Literal as C import Clash.Core.Name- (Name (..), appendToName, nameOcc)+ (Name (..), appendToName, mkUnsafeSystemName, nameOcc)+import Clash.Core.PartialEval import Clash.Core.Pretty (showPpr) import Clash.Core.Subst (Subst (..), extendIdSubst, extendIdSubstList, extendInScopeId,@@ -103,16 +107,18 @@ (primMultiResult, MultiPrimInfo(..), Alt, LetBinding, Pat (..), Term (..), TickInfo (..), NameMod (..), IsMultiPrim (..), collectArgsTicks, collectTicks, collectBndrs, PrimInfo(primName), mkTicks, stripTicks) import Clash.Core.TermInfo+import Clash.Core.TermLiteral (termToDataError) import Clash.Core.TyCon (TyCon (FunTyCon), TyConName, TyConMap, tyConDataCons) import Clash.Core.Type- (Type (..), TyVar, TypeView (..), coreView1, normalizeType, splitTyConAppM, tyView)+ (LitTy (..), Type (..), TyVar, TypeView (..), coreView, coreView1, normalizeType,+ splitTyConAppM, tyView) import Clash.Core.Util (substArgTys, tyLitShow) import Clash.Core.Var (Id, Var (..), mkLocalId, modifyVarName) import Clash.Core.VarEnv- (InScopeSet, extendInScopeSetList, uniqAway, lookupVarEnv)+ (InScopeSet, extendInScopeSetList, uniqAway, lookupVarEnv, emptyInScopeSet) import qualified Clash.Data.UniqMap as UniqMap import {-# SOURCE #-} Clash.Netlist.BlackBox import {-# SOURCE #-} Clash.Netlist.BlackBox.Util@@ -121,8 +127,10 @@ import qualified Clash.Netlist.Id as Id import Clash.Netlist.Types as HW import Clash.Primitives.Types+import qualified Clash.Sized.Vector as V import Clash.Util import qualified Clash.Util.Interpolate as I+import Clash.Util.Supply hmFindWithDefault :: (Eq k, Hashable k) => v -> k -> HashMap k v -> v #if MIN_VERSION_unordered_containers(0,2,11)@@ -220,8 +228,7 @@ :: String -> Type -> NetlistMonad HWType-unsafeCoreTypeToHWTypeM' loc ty =- stripFiltered <$> unsafeCoreTypeToHWTypeM loc ty+unsafeCoreTypeToHWTypeM' loc ty = stripFiltered <$> unsafeCoreTypeToHWTypeM loc ty -- | Converts a Core type to a HWType within the NetlistMonad; errors on failure unsafeCoreTypeToHWTypeM@@ -1881,6 +1888,56 @@ go decls (SrcSpan sp:ticks) = go (TickDecl (Comment (Text.pack (showSDocUnsafe (ppr sp)))):decls) ticks + go decls (Attributes ty attrs0:ticks) = do+ -- We have 'Term', `attrs0`, that represents a value of type `Vec n (Attr String)`.+ -- We want to convert this to an actual value of type `Vec n (Attr String)`, for+ -- which we will use `termToDataError`.+ --+ -- The `termToDataError` only works well for completely evaluated literals.+ -- Sometimes we end up with a term which hasn't been complete beta-reduced, e.g.+ -- `(/\b.Nil 0 b (0~0)) Bool` which represents a value of type `Vec 0 Bool`, for+ -- which `termToDataError` would create an error-value.+ --+ -- To ensure that we only pass literals to `termToDataError` we first evaluate+ -- `attrs0` to Normal Form (NF) using the partial evaluators.+ tcm <- Lens.view tcCache+ case coreView tcm ty of+ LitTy (NumTy n)+ | Just (SomeNat (Proxy :: Proxy n)) <- someNatVal n+ -> if isClosed attrs0 then do+ -- Step 1. Evaluate to normal form+ nm <- Lens.use bindings+ ids <- State.liftIO newSupply+ eval <- Lens.view peEvaluator+ let attrsTy = inferCoreTypeOf tcm attrs0+ -- Safe to use `mkUnsafeSystemName` here, because attrs0 has no+ -- free variables (it's closed), meaning there can be no shadowing+ attrsName = mkUnsafeSystemName "attrs" 0+ attrsId = mkLocalId attrsTy attrsName++ genv = mkGlobalEnv nm tcm emptyInScopeSet ids 20 mempty 0+ -- Force attributes term to Normal Form so that it is a simple literal+ -- that is understood by `termToDataError`.+ (attrs1,_) <- State.liftIO (nf eval genv True attrsId attrs0)++ -- Step 2. Create data from the term+ case termToDataError attrs1 of+ Left msg -> error msg+ Right attrs2 ->+ -- Step 3. Finally add the attributes to the environment.+ let attrs3 = fmap (fmap Text.pack) attrs2+ in local (\env -> env {_localAttrs = V.toList @n attrs3}) (go decls ticks)+ else+ error errFV+ _ -> error errNoNum+ where+ errHeader = "ERROR: cannot add attribues: " <> showPpr attrs0+ errNoNum = unlines [errHeader+ ,"REASON: Internal length is not a literal" <> showPpr ty]+ errFV = unlines [errHeader+ ,"REASON: attributes mentions variables" <> showPpr attrs0+ ]+ go decls (NameMod m nm0:ticks) = do tcm <- Lens.view tcCache case runExcept (tyLitShow tcm nm0) of@@ -1904,7 +1961,7 @@ :: Text -> NetlistMonad Text affixName nm0 = do- NetlistEnv _ pre suf _ <- ask+ NetlistEnv _ pre suf _ _ _ <- ask let nm1 = if Text.null pre then nm0 else pre <> "_" <> nm0 nm2 = if Text.null suf then nm1 else nm1 <> "_" <> suf return nm2
src/Clash/Normalize.hs view
@@ -18,7 +18,7 @@ import Control.Exception (throw) import qualified Control.Lens as Lens-import Control.Monad (when)+import Control.Monad ((>=>), when) import Control.Monad.State.Strict (State) import Data.Default (def) import Data.Either (lefts,partitionEithers)@@ -143,11 +143,24 @@ normalize :: [Id] -> NormalizeSession BindingMap-normalize [] = return emptyVarEnv-normalize top = do- (new,topNormalized) <- unzip <$> mapM normalize' top- newNormalized <- normalize (concat new)- return (unionVarEnv (mkVarEnv topNormalized) newNormalized)+normalize = go >=> unionWithCache+ where+ go [] = return emptyVarEnv+ go top = do+ (new,topNormalized) <- unzip <$> mapM normalize' top+ newNormalized <- normalize (concat new)+ return (unionVarEnv (mkVarEnv topNormalized) newNormalized)++ unionWithCache :: BindingMap -> NormalizeSession BindingMap+ unionWithCache env = do+ cache <- Lens.use (extra.normalized)+ -- We need to include the cache in our final result, forgetting to do so+ -- leads to https://github.com/clash-lang/clash-compiler/issues/3109+ --+ -- On the other hand, just returning the cache as our final result could+ -- not be enough, because normalize' might return a non-normalized binder+ -- that is later picked up and cleaned up by flattenCallTree.+ return (unionVarEnv cache env) normalize' :: Id -> NormalizeSession ([Id], (Id, Binding Term)) normalize' nm = do
src/Clash/Normalize/Transformations/Cast.hs view
@@ -47,11 +47,11 @@ -- -- The reason d'etre for this transformation is that we hope to end up with -- and expression where two casts are "back-to-back" after which we can--- eliminate them in 'eliminateCastCast'.+-- eliminate them in 'elimCastCast'. argCastSpec :: HasCallStack => NormRewrite argCastSpec ctx e@(App f (stripTicks -> Cast e' _ _)) -- Don't specialise when the arguments are casts-of-casts, these casts-of-casts- -- will be eliminated by 'eliminateCastCast' during the normalization of the+ -- will be eliminated by 'elimCastCast' during the normalization of the -- "current" function. We thus prevent the unnecessary introduction of a -- specialized version of 'f'. | not (isCast e')
src/Clash/Primitives/Sized/Signed.hs view
@@ -3,7 +3,7 @@ License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> - VHDL Blackbox implementations for "Clash.Sized.Internal.Signed.toInteger#".+ VHDL Blackbox implementations for 'Clash.Sized.Internal.Signed.fromInteger#'. -} {-# LANGUAGE OverloadedStrings #-}
src/Clash/Primitives/Sized/ToInteger.hs view
@@ -153,7 +153,7 @@ _ -> case hty of BitVector {} -> "~IF~SIZE[~TYP[1]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[bv][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[bv][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" Index {} -> "~IF~SIZE[~TYP[0]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[0]]]~THEN$unsigned(~VAR[i][0][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[0]]) {1'b0}},~VAR[i][0]})~FI~ELSE~SIZE[~TYPO]'sd0~FI"- Signed {} -> "~IF~SIZE[~TYP[0]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[0]]]~THEN$signed(~VAR[i][0][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[0]]) {1'b0}},~VAR[i][0]})~FI~ELSE~SIZE[~TYPO]'sd0~FI"+ Signed {} -> "~IF~SIZE[~TYP[0]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[0]]]~THEN$signed(~VAR[i][0][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[0]]) {~VAR[i][0][~SIZE[~TYP[0]]-1]}},~VAR[i][0]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" Unsigned {} -> "~IF~SIZE[~TYP[0]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[0]]]~THEN$unsigned(~VAR[i][0][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[0]]) {1'b0}},~VAR[i][0]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" _ -> error "internal error"
src/Clash/Primitives/Verification.hs view
@@ -1,3 +1,11 @@+{-|+ Copyright : (C) 2019 , Myrtle Software Ltd+ 2021 , Ellie Hermaszewska+ 2020-2025, QBayLogic B.V.+ License : BSD2 (see the file LICENSE)+ Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}+ {-# LANGUAGE OverloadedStrings #-} module Clash.Primitives.Verification (checkBBF) where@@ -11,14 +19,14 @@ import Data.Maybe (listToMaybe) import Data.Monoid (Ap(getAp)) import Data.Text.Prettyprint.Doc.Extra (Doc)-import qualified Data.Text as Text+import Data.Text (Text) import GHC.Stack (HasCallStack) import Clash.Annotations.Primitive (HDL(..)) import Clash.Backend (Backend, blockDecl, hdlKind) import Clash.Core.HasType-import Clash.Core.Term (Term(Var), varToId)+import Clash.Core.Term (Term(Var)) import Clash.Core.TermLiteral (termToDataError) import Clash.Util (indexNote) import Clash.Netlist (mkExpr)@@ -41,10 +49,11 @@ case litArgs of Left err -> pure (Left err) Right (propName, renderAs, cvProperty0) -> do+ clkBind <- bindMaybe (Just "clk") (indexNote "clk" (lefts args) clkArg) cvProperty1 <- mapM (uncurry bindMaybe) cvProperty0 let decls = concatMap snd cvProperty1 cvProperty2 = fmap fst cvProperty1- pure (Right (meta, bb (checkTF decls (clkExpr, clkId) propName renderAs cvProperty2)))+ pure (Right (meta, bb (checkTF decls clkBind propName renderAs cvProperty2))) where -- TODO: Improve error handling; currently errors don't indicate what -- TODO: blackbox generated them.@@ -55,8 +64,6 @@ :< renderAsArg :< propArg :< _ = ((0 :: Int)...)- (Id.unsafeFromCoreId -> clkId) = varToId (indexNote "clk" (lefts args) clkArg)- clkExpr = Identifier clkId Nothing litArgs = do propName <- termToDataError (indexNote "propName" (lefts args) propNameArg)@@ -68,7 +75,7 @@ meta = emptyBlackBoxMeta {bbKind=TDecl, bbRenderVoid=RenderVoid} bindMaybe- :: Maybe String+ :: Maybe Text -- ^ Hint for new identifier -> Term -- ^ Term to bind. Does not bind if it's already a reference to a signal@@ -78,7 +85,7 @@ bindMaybe Nothing t = bindMaybe (Just "s") t bindMaybe (Just nm) t = do tcm <- Lens.view tcCache- newId <- Id.make (Text.pack nm)+ newId <- Id.make nm (expr0, decls) <- mkExpr False Concurrent (NetlistId newId (inferCoreTypeOf tcm t)) t assn <- contAssign newId expr0 pure@@ -91,8 +98,8 @@ checkTF :: [Declaration]- -> (Expr, Identifier)- -> Text.Text+ -> (Identifier, [Declaration])+ -> Text -> RenderAs -> Property' Identifier -> TemplateFunction@@ -104,20 +111,21 @@ . (HasCallStack, Backend s) => [Declaration] -- ^ Extra decls needed- -> (Expr, Identifier)+ -> (Identifier, [Declaration]) -- ^ Clock- -> Text.Text+ -> Text -- ^ Prop name -> RenderAs -> Property' Identifier -> BlackBoxContext -> State s Doc-checkTF' decls (clk, clkId) propName renderAs prop bbCtx = do+checkTF' decls (clkId, clkDecls) propName renderAs prop bbCtx = do blockName <- Id.makeBasic (propName <> "_block")- getAp (blockDecl blockName (renderedPslProperty : decls))+ getAp (blockDecl blockName (clkDecls <> (renderedPslProperty : decls))) where hdl = hdlKind (undefined :: s)+ clk = Identifier clkId Nothing edge = case bbInputs bbCtx of