packages feed

clash-lib 1.6.6 → 1.8.0

raw patch · 143 files changed

+8227/−3082 lines, 143 filesdep +docoptdep +doctest-paralleldep +infinite-listdep −interpolatedep ~ansi-terminaldep ~basedep ~clash-preludenew-component:exe:static-filesPVP ok

version bump matches the API change (PVP)

Dependencies added: docopt, doctest-parallel, infinite-list, prettyprinter-interp, string-interpolate, tasty-th

Dependencies removed: interpolate

Dependency ranges changed: ansi-terminal, base, clash-prelude, deepseq, directory, extra, filepath, ghc, ghc-bignum, mtl, tasty, template-haskell

API changes (from Hackage documentation)

- Clash.Core.Subst: instance GHC.Classes.Ord Clash.Core.Term.TickInfo
- Clash.Core.Var: Attr' :: String -> Attr'
- Clash.Core.Var: BoolAttr' :: String -> Bool -> Attr'
- Clash.Core.Var: IntegerAttr' :: String -> Integer -> Attr'
- Clash.Core.Var: StringAttr' :: String -> String -> Attr'
- Clash.Core.Var: attrName :: Attr' -> String
- Clash.Core.Var: data Attr'
- Clash.Core.Var: instance Control.DeepSeq.NFData Clash.Core.Var.Attr'
- Clash.Core.Var: instance Data.Binary.Class.Binary Clash.Core.Var.Attr'
- Clash.Core.Var: instance Data.Hashable.Class.Hashable Clash.Core.Var.Attr'
- Clash.Core.Var: instance GHC.Classes.Eq Clash.Core.Var.Attr'
- Clash.Core.Var: instance GHC.Classes.Ord Clash.Core.Var.Attr'
- Clash.Core.Var: instance GHC.Generics.Generic Clash.Core.Var.Attr'
- Clash.Core.Var: instance GHC.Show.Show Clash.Core.Var.Attr'
- Clash.Driver.Types: [designDomains] :: ClashDesign -> DomainMap
- Clash.Netlist.BlackBox.Types: OutputWireReg :: !Int -> Element
- Clash.Netlist.BlackBox.Types: [bbOutputReg] :: BlackBoxMeta -> Bool
- Clash.Netlist.Types: Reg :: WireOrReg
- Clash.Netlist.Types: Wire :: WireOrReg
- Clash.Netlist.Types: data WireOrReg
- Clash.Netlist.Types: instance Control.DeepSeq.NFData Clash.Netlist.Types.WireOrReg
- Clash.Netlist.Types: instance GHC.Generics.Generic Clash.Netlist.Types.WireOrReg
- Clash.Netlist.Types: instance GHC.Show.Show Clash.Netlist.Types.WireOrReg
- Clash.Netlist.Util: expandTopEntityOrErr :: HasCallStack => IdentifierSet -> [(Maybe Id, FilteredHWType)] -> (Maybe Id, FilteredHWType) -> Maybe TopEntity -> ExpandedTopEntity Identifier
- Clash.Netlist.Util: id2identifier :: Id -> Identifier
- Clash.Netlist.Util: mkAssign :: Identifier -> HWType -> Expr -> [Declaration]
- Clash.Primitives.Intel.ClockGen: alteraPllTemplate :: forall s. Backend s => BlackBoxContext -> State s Doc
- Clash.Primitives.Intel.ClockGen: altpllTemplate :: Backend s => BlackBoxContext -> State s Doc
- Clash.Primitives.Types: [outputReg] :: Primitive a b c d -> Bool
- Clash.Unique: data UniqMap a
- Clash.Unique: data UniqSet a
- Clash.Unique: delListUniqMap :: Uniquable a => UniqMap b -> [a] -> UniqMap b
- Clash.Unique: delUniqMap :: Uniquable a => UniqMap b -> a -> UniqMap b
- Clash.Unique: delUniqSetDirectly :: Unique -> UniqSet b -> UniqSet b
- Clash.Unique: differenceUniqMap :: UniqMap a -> UniqMap a -> UniqMap a
- Clash.Unique: differenceUniqSet :: UniqSet a -> UniqSet a -> UniqSet a
- Clash.Unique: disjointUniqSet :: UniqSet a -> UniqSet a -> Bool
- Clash.Unique: elemUniqMap :: Uniquable a => a -> UniqMap b -> Bool
- Clash.Unique: elemUniqMapDirectly :: Unique -> UniqMap b -> Bool
- Clash.Unique: elemUniqSet :: Uniquable a => a -> UniqSet a -> Bool
- Clash.Unique: elemUniqSetDirectly :: Unique -> UniqSet a -> Bool
- Clash.Unique: eltsUniqMap :: UniqMap a -> [a]
- Clash.Unique: eltsUniqSet :: UniqSet a -> [a]
- Clash.Unique: emptyUniqMap :: UniqMap a
- Clash.Unique: emptyUniqSet :: UniqSet a
- Clash.Unique: extendListUniqMap :: Uniquable a => UniqMap b -> [(a, b)] -> UniqMap b
- Clash.Unique: extendUniqMap :: Uniquable a => a -> b -> UniqMap b -> UniqMap b
- Clash.Unique: extendUniqMapWith :: Uniquable a => a -> b -> (b -> b -> b) -> UniqMap b -> UniqMap b
- Clash.Unique: extendUniqSet :: Uniquable a => UniqSet a -> a -> UniqSet a
- Clash.Unique: filterUniqMap :: (b -> Bool) -> UniqMap b -> UniqMap b
- Clash.Unique: foldlWithUnique' :: (a -> Unique -> b -> a) -> a -> UniqMap b -> a
- Clash.Unique: foldrWithUnique :: (Unique -> a -> b -> b) -> b -> UniqMap a -> b
- Clash.Unique: instance Clash.Pretty.ClashPretty a => Clash.Pretty.ClashPretty (Clash.Unique.UniqMap a)
- Clash.Unique: instance Clash.Pretty.ClashPretty a => Clash.Pretty.ClashPretty (Clash.Unique.UniqSet a)
- Clash.Unique: instance Clash.Pretty.ClashPretty a => GHC.Show.Show (Clash.Unique.UniqMap a)
- Clash.Unique: instance Clash.Unique.Uniquable GHC.Types.Int
- Clash.Unique: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Clash.Unique.UniqMap a)
- Clash.Unique: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Clash.Unique.UniqSet a)
- Clash.Unique: instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (Clash.Unique.UniqMap a)
- Clash.Unique: instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (Clash.Unique.UniqSet a)
- Clash.Unique: instance Data.Foldable.Foldable Clash.Unique.UniqMap
- Clash.Unique: instance Data.Foldable.Foldable Clash.Unique.UniqSet
- Clash.Unique: instance Data.Traversable.Traversable Clash.Unique.UniqMap
- Clash.Unique: instance GHC.Base.Functor Clash.Unique.UniqMap
- Clash.Unique: instance GHC.Base.Monoid (Clash.Unique.UniqMap a)
- Clash.Unique: instance GHC.Base.Monoid (Clash.Unique.UniqSet a)
- Clash.Unique: instance GHC.Base.Semigroup (Clash.Unique.UniqMap a)
- Clash.Unique: instance GHC.Base.Semigroup (Clash.Unique.UniqSet a)
- Clash.Unique: keysUniqMap :: UniqMap a -> [Unique]
- Clash.Unique: listToUniqMap :: Uniquable a => [(a, b)] -> UniqMap b
- Clash.Unique: lookupUniqMap :: Uniquable a => a -> UniqMap b -> Maybe b
- Clash.Unique: lookupUniqMap' :: (HasCallStack, Uniquable a) => UniqMap b -> a -> b
- Clash.Unique: lookupUniqSet :: Uniquable a => a -> UniqSet b -> Maybe b
- Clash.Unique: mapMaybeUniqMap :: (a -> Maybe b) -> UniqMap a -> UniqMap b
- Clash.Unique: mapUniqMap :: (a -> b) -> UniqMap a -> UniqMap b
- Clash.Unique: mkUniqSet :: Uniquable a => [a] -> UniqSet a
- Clash.Unique: notElemUniqMap :: Uniquable a => a -> UniqMap b -> Bool
- Clash.Unique: notElemUniqSet :: Uniquable a => a -> UniqSet a -> Bool
- Clash.Unique: nullUniqMap :: UniqMap a -> Bool
- Clash.Unique: nullUniqSet :: UniqSet a -> Bool
- Clash.Unique: subsetUniqSet :: UniqSet a -> UniqSet a -> Bool
- Clash.Unique: toListUniqMap :: UniqMap a -> [(Unique, a)]
- Clash.Unique: unionUniqMap :: UniqMap a -> UniqMap a -> UniqMap a
- Clash.Unique: unionUniqMapWith :: (a -> a -> a) -> UniqMap a -> UniqMap a -> UniqMap a
- Clash.Unique: unionUniqSet :: UniqSet a -> UniqSet a -> UniqSet a
- Clash.Unique: uniqMapToUniqSet :: UniqMap a -> UniqSet a
- Clash.Unique: unitUniqMap :: Uniquable a => a -> b -> UniqMap b
- Clash.Unique: unitUniqSet :: Uniquable a => a -> UniqSet a
+ Clash.Backend: class HasUsageMap s
+ Clash.Backend: usageMap :: HasUsageMap s => Lens' s UsageMap
+ Clash.Backend.SystemVerilog: instance Clash.Backend.HasUsageMap Clash.Backend.SystemVerilog.SystemVerilogState
+ Clash.Backend.VHDL: instance Clash.Backend.HasUsageMap Clash.Backend.VHDL.VHDLState
+ Clash.Backend.Verilog: instance Clash.Backend.HasUsageMap Clash.Backend.Verilog.VerilogState
+ Clash.Backend.Verilog.Time: Fs :: Unit
+ Clash.Backend.Verilog.Time: Ms :: Unit
+ Clash.Backend.Verilog.Time: Ns :: Unit
+ Clash.Backend.Verilog.Time: Period :: Word64 -> Unit -> Period
+ Clash.Backend.Verilog.Time: Ps :: Unit
+ Clash.Backend.Verilog.Time: S :: Unit
+ Clash.Backend.Verilog.Time: Scale :: Period -> Period -> Scale
+ Clash.Backend.Verilog.Time: Us :: Unit
+ Clash.Backend.Verilog.Time: [precision] :: Scale -> Period
+ Clash.Backend.Verilog.Time: [step] :: Scale -> Period
+ Clash.Backend.Verilog.Time: convertUnit :: Unit -> Period -> Word64
+ Clash.Backend.Verilog.Time: data Period
+ Clash.Backend.Verilog.Time: data Scale
+ Clash.Backend.Verilog.Time: data Unit
+ Clash.Backend.Verilog.Time: instance Control.DeepSeq.NFData Clash.Backend.Verilog.Time.Period
+ Clash.Backend.Verilog.Time: instance Control.DeepSeq.NFData Clash.Backend.Verilog.Time.Scale
+ Clash.Backend.Verilog.Time: instance Control.DeepSeq.NFData Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance Data.Hashable.Class.Hashable Clash.Backend.Verilog.Time.Period
+ Clash.Backend.Verilog.Time: instance Data.Hashable.Class.Hashable Clash.Backend.Verilog.Time.Scale
+ Clash.Backend.Verilog.Time: instance Data.Hashable.Class.Hashable Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance GHC.Classes.Eq Clash.Backend.Verilog.Time.Period
+ Clash.Backend.Verilog.Time: instance GHC.Classes.Eq Clash.Backend.Verilog.Time.Scale
+ Clash.Backend.Verilog.Time: instance GHC.Classes.Eq Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance GHC.Classes.Ord Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance GHC.Enum.Bounded Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance GHC.Enum.Enum Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance GHC.Generics.Generic Clash.Backend.Verilog.Time.Period
+ Clash.Backend.Verilog.Time: instance GHC.Generics.Generic Clash.Backend.Verilog.Time.Scale
+ Clash.Backend.Verilog.Time: instance GHC.Generics.Generic Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: instance GHC.Show.Show Clash.Backend.Verilog.Time.Period
+ Clash.Backend.Verilog.Time: instance GHC.Show.Show Clash.Backend.Verilog.Time.Scale
+ Clash.Backend.Verilog.Time: instance GHC.Show.Show Clash.Backend.Verilog.Time.Unit
+ Clash.Backend.Verilog.Time: parsePeriod :: String -> Maybe Period
+ Clash.Backend.Verilog.Time: parseUnit :: String -> Maybe Unit
+ Clash.Backend.Verilog.Time: periodToString :: Period -> String
+ Clash.Backend.Verilog.Time: scaleToString :: Scale -> String
+ Clash.Backend.Verilog.Time: unitToString :: Unit -> String
+ Clash.Core.Literal: Int16Literal :: !Integer -> Literal
+ Clash.Core.Literal: Int32Literal :: !Integer -> Literal
+ Clash.Core.Literal: Int8Literal :: !Integer -> Literal
+ Clash.Core.Literal: Word16Literal :: !Integer -> Literal
+ Clash.Core.Literal: Word32Literal :: !Integer -> Literal
+ Clash.Core.Literal: Word8Literal :: !Integer -> Literal
+ Clash.Core.Term: instance GHC.Classes.Ord Clash.Core.Term.TickInfo
+ Clash.Core.TermLiteral: deriveTermLiteral :: Name -> Q [Dec]
+ Clash.Core.TermLiteral: instance (Clash.Core.TermLiteral.TermLiteral a, Clash.Core.TermLiteral.TermLiteral b) => Clash.Core.TermLiteral.TermLiteral (Data.Either.Either a b)
+ Clash.Core.TermLiteral: instance (Clash.Core.TermLiteral.TermLiteral a, GHC.TypeNats.KnownNat n) => Clash.Core.TermLiteral.TermLiteral (Clash.Sized.Vector.Vec n a)
+ Clash.Core.TermLiteral: instance Clash.Core.TermLiteral.TermLiteral (Clash.Promoted.Nat.SNat n)
+ Clash.Core.TermLiteral: instance Clash.Core.TermLiteral.TermLiteral a => Clash.Core.TermLiteral.TermLiteral (Clash.Annotations.SynthesisAttributes.Attr a)
+ Clash.Core.TermLiteral: instance GHC.TypeNats.KnownNat n => Clash.Core.TermLiteral.TermLiteral (Clash.Sized.Internal.Index.Index n)
+ Clash.Core.TermLiteral: showType :: TermLiteral a => Proxy a -> String
+ Clash.Core.TermLiteral: showsTypePrec :: TermLiteral a => Int -> Proxy a -> ShowS
+ Clash.Core.TermLiteral.TH: deriveShowsTypePrec :: Name -> Q Dec
+ Clash.Core.TermLiteral.TH: deriveTermLiteral :: Name -> Q [Dec]
+ Clash.Core.Type: CharTy :: !Char -> LitTy
+ Clash.Core.TysPrim: int16PrimTy :: Type
+ Clash.Core.TysPrim: int32PrimTy :: Type
+ Clash.Core.TysPrim: int8PrimTy :: Type
+ Clash.Core.TysPrim: word16PrimTy :: Type
+ Clash.Core.TysPrim: word32PrimTy :: Type
+ Clash.Core.TysPrim: word8PrimTy :: Type
+ Clash.Core.VarEnv: differenceVarEnv :: VarEnv a -> VarEnv a -> VarEnv a
+ Clash.Data.UniqMap: UniqMap :: IntMap a -> UniqMap a
+ Clash.Data.UniqMap: [uniqMapToIntMap] :: UniqMap a -> IntMap a
+ Clash.Data.UniqMap: delete :: Uniquable a => a -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: deleteMany :: Uniquable a => [a] -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: difference :: UniqMap b -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: disjoint :: UniqMap b -> UniqMap b -> Bool
+ Clash.Data.UniqMap: elem :: Uniquable a => a -> UniqMap b -> Bool
+ Clash.Data.UniqMap: elems :: UniqMap b -> [b]
+ Clash.Data.UniqMap: empty :: UniqMap a
+ Clash.Data.UniqMap: filter :: (b -> Bool) -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: find :: Uniquable a => a -> UniqMap b -> b
+ Clash.Data.UniqMap: foldlWithUnique' :: (b -> Unique -> a -> b) -> b -> UniqMap a -> b
+ Clash.Data.UniqMap: foldrWithUnique :: (Unique -> a -> b -> b) -> b -> UniqMap a -> b
+ Clash.Data.UniqMap: fromList :: Uniquable a => [(a, b)] -> UniqMap b
+ Clash.Data.UniqMap: insert :: Uniquable a => a -> b -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: insertMany :: Uniquable a => [(a, b)] -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: insertUnique :: Uniquable a => a -> UniqMap a -> UniqMap a
+ Clash.Data.UniqMap: insertWith :: Uniquable a => (b -> b -> b) -> a -> b -> UniqMap b -> UniqMap b
+ Clash.Data.UniqMap: instance Clash.Pretty.ClashPretty a => Clash.Pretty.ClashPretty (Clash.Data.UniqMap.UniqMap a)
+ Clash.Data.UniqMap: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Clash.Data.UniqMap.UniqMap a)
+ Clash.Data.UniqMap: instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (Clash.Data.UniqMap.UniqMap a)
+ Clash.Data.UniqMap: instance Data.Foldable.Foldable Clash.Data.UniqMap.UniqMap
+ Clash.Data.UniqMap: instance Data.Traversable.Traversable Clash.Data.UniqMap.UniqMap
+ Clash.Data.UniqMap: instance GHC.Base.Functor Clash.Data.UniqMap.UniqMap
+ Clash.Data.UniqMap: instance GHC.Base.Monoid (Clash.Data.UniqMap.UniqMap a)
+ Clash.Data.UniqMap: instance GHC.Base.Semigroup (Clash.Data.UniqMap.UniqMap a)
+ Clash.Data.UniqMap: instance GHC.Show.Show a => GHC.Show.Show (Clash.Data.UniqMap.UniqMap a)
+ Clash.Data.UniqMap: keys :: UniqMap b -> [Unique]
+ Clash.Data.UniqMap: lookup :: Uniquable a => a -> UniqMap b -> Maybe b
+ Clash.Data.UniqMap: mapMaybe :: (a -> Maybe b) -> UniqMap a -> UniqMap b
+ Clash.Data.UniqMap: newtype UniqMap a
+ Clash.Data.UniqMap: notElem :: Uniquable a => a -> UniqMap b -> Bool
+ Clash.Data.UniqMap: null :: UniqMap a -> Bool
+ Clash.Data.UniqMap: singleton :: Uniquable a => a -> b -> UniqMap b
+ Clash.Data.UniqMap: singletonUnique :: Uniquable a => a -> UniqMap a
+ Clash.Data.UniqMap: submap :: UniqMap b -> UniqMap b -> Bool
+ Clash.Data.UniqMap: toList :: UniqMap b -> [(Unique, b)]
+ Clash.Data.UniqMap: unionWith :: (b -> b -> b) -> UniqMap b -> UniqMap b -> UniqMap b
+ Clash.DataFiles: tclConnector :: IO FilePath
+ Clash.Driver.Types: [envDomains] :: ClashEnv -> DomainMap
+ Clash.Driver.Types: [opt_timescalePrecision] :: ClashOpts -> Period
+ Clash.Netlist.BlackBox.Types: OutputUsage :: !Int -> Element
+ Clash.Netlist.BlackBox.Types: [bbOutputUsage] :: BlackBoxMeta -> Usage
+ Clash.Netlist.BlackBox.Util: generalGetDomainConf :: forall m. (Monad m, HasCallStack) => m DomainMap -> HWType -> m VDomainConfiguration
+ Clash.Netlist.BlackBox.Util: getDomainConf :: (Backend backend, HasCallStack) => HWType -> State backend VDomainConfiguration
+ Clash.Netlist.Expr: bits :: HasCallStack => Size -> Expr -> Either Expr (Tree [Bool])
+ Clash.Netlist.Expr: fromBits :: Bits a => [Bool] -> a
+ Clash.Netlist.Expr: toBits :: Bits a => Int -> a -> [Bool]
+ Clash.Netlist.Id: unsafeFromCoreId :: HasCallStack => Id -> Identifier
+ Clash.Netlist.Types: Blocking :: Blocking
+ Clash.Netlist.Types: ClockN :: !DomainName -> HWType
+ Clash.Netlist.Types: CompDecl :: !Text -> [(Text, PortDirection, HWType)] -> Declaration
+ Clash.Netlist.Types: Cont :: Usage
+ Clash.Netlist.Types: NonBlocking :: Blocking
+ Clash.Netlist.Types: Proc :: Blocking -> Usage
+ Clash.Netlist.Types: [_usages] :: NetlistState -> UsageMap
+ Clash.Netlist.Types: [cmUsage] :: ComponentMeta -> UsageMap
+ Clash.Netlist.Types: annotated :: [Attr Text] -> HWType -> HWType
+ Clash.Netlist.Types: data Blocking
+ Clash.Netlist.Types: data Usage
+ Clash.Netlist.Types: instance Clash.Backend.HasUsageMap Clash.Netlist.Types.NetlistState
+ Clash.Netlist.Types: instance Clash.Netlist.Types.HasIdentifierSet s => Clash.Netlist.Types.HasIdentifierSet (s, a)
+ Clash.Netlist.Types: instance Control.DeepSeq.NFData Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance Control.DeepSeq.NFData Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance Data.Aeson.Types.FromJSON.FromJSON Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance Data.Binary.Class.Binary Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance Data.Binary.Class.Binary Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance Data.Hashable.Class.Hashable Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance Data.Hashable.Class.Hashable Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance GHC.Base.Semigroup Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance GHC.Base.Semigroup Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance GHC.Classes.Eq Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance GHC.Classes.Eq Clash.Netlist.Types.NetlistId
+ Clash.Netlist.Types: instance GHC.Classes.Eq Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance GHC.Generics.Generic Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance GHC.Generics.Generic Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: instance GHC.Show.Show Clash.Netlist.Types.Blocking
+ Clash.Netlist.Types: instance GHC.Show.Show Clash.Netlist.Types.Usage
+ Clash.Netlist.Types: isConstExpr :: Expr -> Bool
+ Clash.Netlist.Types: lookupUsage :: Identifier -> UsageMap -> Maybe Usage
+ Clash.Netlist.Types: type UsageMap = Map Text Usage
+ Clash.Netlist.Types: usages :: Lens' NetlistState UsageMap
+ Clash.Netlist.Util: assignmentWith :: HasCallStack => (Identifier -> Declaration) -> Usage -> Identifier -> NetlistMonad Declaration
+ Clash.Netlist.Util: canUse :: HDL -> Usage -> Usage -> Bool
+ Clash.Netlist.Util: condAssign :: Identifier -> HWType -> Expr -> HWType -> [(Maybe Literal, Expr)] -> NetlistMonad Declaration
+ Clash.Netlist.Util: contAssign :: HasCallStack => Identifier -> Expr -> NetlistMonad Declaration
+ Clash.Netlist.Util: declareInstUses :: [(Expr, PortDirection, HWType, Expr)] -> NetlistMonad ()
+ Clash.Netlist.Util: declareUse :: Usage -> Identifier -> NetlistMonad ()
+ Clash.Netlist.Util: declareUseOnce :: HasUsageMap s => Usage -> Identifier -> State s ()
+ Clash.Netlist.Util: instance GHC.Show.Show Clash.Netlist.Util.InstancePort
+ Clash.Netlist.Util: mkInit :: HasCallStack => DeclarationType -> Usage -> Identifier -> HWType -> Expr -> NetlistMonad [Declaration]
+ Clash.Netlist.Util: procAssign :: HasCallStack => Blocking -> Identifier -> Expr -> NetlistMonad Declaration
+ Clash.Normalize.Transformations.Reduce: instance Clash.Normalize.Transformations.Reduce.AbstractOverMissingArgs (Clash.Rewrite.Types.TransformContext -> Clash.Normalize.Types.NormalizeSession Clash.Core.Term.Term)
+ Clash.Normalize.Transformations.Reduce: instance Clash.Normalize.Transformations.Reduce.AbstractOverMissingArgs a => Clash.Normalize.Transformations.Reduce.AbstractOverMissingArgs (Clash.Core.Term.Term -> a)
+ Clash.Primitives.Annotations.SynthesisAttributes: annotateBBF :: HasCallStack => BlackBoxFunction
+ Clash.Primitives.Annotations.SynthesisAttributes: annotateBBTF :: (Backend s, KnownNat n, HasCallStack) => Vec n (Attr Text) -> BlackBoxContext -> State s Doc
+ Clash.Primitives.Annotations.SynthesisAttributes: annotateTF :: HasCallStack => KnownNat n => Vec n (Attr Text) -> TemplateFunction
+ Clash.Primitives.Annotations.SynthesisAttributes: usedArguments :: [Int]
+ Clash.Primitives.DSL: TExpr :: HWType -> Expr -> TExpr
+ Clash.Primitives.DSL: [eex] :: TExpr -> Expr
+ Clash.Primitives.DSL: [ety] :: TExpr -> HWType
+ Clash.Primitives.DSL: addDeclaration :: Declaration -> State (BlockState backend) ()
+ Clash.Primitives.DSL: assign :: Backend backend => Text -> TExpr -> State (BlockState backend) TExpr
+ Clash.Primitives.DSL: bitCoerce :: (HasCallStack, Backend backend) => Text -> HWType -> TExpr -> State (BlockState backend) TExpr
+ Clash.Primitives.DSL: compInBlock :: forall backend. Backend backend => Text -> [(Text, HWType)] -> [(Text, HWType)] -> State (BlockState backend) ()
+ Clash.Primitives.DSL: declare :: Backend backend => Text -> HWType -> State (BlockState backend) TExpr
+ Clash.Primitives.DSL: declareN :: Backend backend => Text -> [HWType] -> State (BlockState backend) [TExpr]
+ Clash.Primitives.DSL: deconstructMaybe :: (HasCallStack, Backend backend) => TExpr -> (Text, Text) -> State (BlockState backend) (TExpr, TExpr)
+ Clash.Primitives.DSL: getVec :: TExpr -> Maybe [TExpr]
+ Clash.Primitives.DSL: instance Clash.Backend.HasUsageMap backend => Clash.Backend.HasUsageMap (Clash.Primitives.DSL.BlockState backend)
+ Clash.Primitives.DSL: litTExpr :: LitHDL -> TExpr
+ Clash.Primitives.DSL: toBvWithAttrs :: Backend backend => [Attr Text] -> Text -> TExpr -> State (BlockState backend) TExpr
+ Clash.Primitives.DSL: unsafeToActiveHigh :: Backend backend => Text -> TExpr -> State (BlockState backend) TExpr
+ Clash.Primitives.DSL: unsafeToActiveLow :: Backend backend => Text -> TExpr -> State (BlockState backend) TExpr
+ Clash.Primitives.Intel.ClockGen: AlteraPll :: Variant
+ Clash.Primitives.Intel.ClockGen: Altpll :: Variant
+ Clash.Primitives.Intel.ClockGen: data Variant
+ Clash.Primitives.Intel.ClockGen: hdlTemplate :: forall s. Backend s => Variant -> BlackBoxContext -> State s Doc
+ Clash.Primitives.Intel.ClockGen: hdlUsed :: [Int]
+ Clash.Primitives.Intel.ClockGen: hdlValid :: BlackBoxContext -> Bool
+ Clash.Primitives.Intel.ClockGen: qsysUsed :: [Int]
+ Clash.Primitives.Magic: clashCompileErrorBBF :: HasCallStack => BlackBoxFunction
+ Clash.Primitives.Types: [outputUsage] :: Primitive a b c d -> Usage
+ Clash.Primitives.Xilinx.ClockGen: clockWizardDifferentialTF :: TemplateFunction
+ Clash.Primitives.Xilinx.ClockGen: clockWizardDifferentialTclTF :: TemplateFunction
+ Clash.Primitives.Xilinx.ClockGen: clockWizardTF :: TemplateFunction
+ Clash.Primitives.Xilinx.ClockGen: clockWizardTclTF :: TemplateFunction
+ Clash.Unique: instance Clash.Unique.Uniquable Clash.Unique.Unique
+ Clash.Util: hoistMaybe :: Applicative m => Maybe b -> MaybeT m b
+ Clash.Util: thenCompare :: Ordering -> Ordering -> Ordering
+ GHC.BasicTypes.Extra: instance Control.DeepSeq.NFData BasicTypes.InlineSpec
+ GHC.BasicTypes.Extra: instance Data.Binary.Class.Binary BasicTypes.InlineSpec
+ GHC.BasicTypes.Extra: instance GHC.Generics.Generic BasicTypes.InlineSpec
+ GHC.BasicTypes.Extra: isNoInline :: InlineSpec -> Bool
+ GHC.BasicTypes.Extra: isOpaque :: InlineSpec -> Bool
- Clash.Backend: class HasIdentifierSet state => Backend state
+ Clash.Backend: class (HasUsageMap state, HasIdentifierSet state) => Backend state
- Clash.Backend: genHDL :: Backend state => ModName -> SrcSpan -> IdentifierSet -> Component -> Ap (State state) ((String, Doc), [(String, Doc)])
+ Clash.Backend: genHDL :: Backend state => ClashOpts -> ModName -> SrcSpan -> IdentifierSet -> UsageMap -> Component -> Ap (State state) ((String, Doc), [(String, Doc)])
- Clash.Core.Evaluator.Types: whnf' :: Evaluator -> BindingMap -> TyConMap -> PrimHeap -> Supply -> InScopeSet -> Bool -> Term -> (PrimHeap, PureHeap, Term)
+ Clash.Core.Evaluator.Types: whnf' :: Evaluator -> BindingMap -> VarEnv Term -> TyConMap -> PrimHeap -> Supply -> InScopeSet -> Bool -> Term -> (PrimHeap, PureHeap, Term)
- Clash.Core.Term: LetBody :: [Id] -> CoreContext
+ Clash.Core.Term: LetBody :: [LetBinding] -> CoreContext
- Clash.Core.TermLiteral: class Typeable a => TermLiteral a
+ Clash.Core.TermLiteral: class TermLiteral a
- Clash.Core.Type: AnnType :: [Attr'] -> !Type -> Type
+ Clash.Core.Type: AnnType :: [Attr Text] -> !Type -> Type
- Clash.Core.Type: typeAttrs :: Type -> [Attr']
+ Clash.Core.Type: typeAttrs :: Type -> [Attr Text]
- Clash.Core.Type: varAttrs :: Var a -> [Attr']
+ Clash.Core.Type: varAttrs :: Var a -> [Attr Text]
- Clash.Core.Util: extractElems :: Supply -> InScopeSet -> DataCon -> Type -> Char -> Integer -> Term -> (Supply, [(Term, [(Id, Term)])])
+ Clash.Core.Util: extractElems :: HasCallStack => Supply -> InScopeSet -> DataCon -> Type -> Char -> Integer -> Term -> (Supply, NonEmpty (Term, NonEmpty (Id, Term)))
- Clash.Core.Util: inverseTopSortLetBindings :: HasCallStack => Term -> Term
+ Clash.Core.Util: inverseTopSortLetBindings :: HasCallStack => [(Id, Term)] -> [(Id, Term)]
- Clash.Core.VarEnv: type VarSet = UniqSet (Var Any)
+ Clash.Core.VarEnv: type VarSet = UniqMap (Var Any)
- Clash.Driver: createHDL :: Backend backend => backend -> IdentifierText -> IdentifierSet -> ComponentMap -> HashMap Text VDomainConfiguration -> Component -> IdentifierText -> ([(String, Doc)], [(String, FilePath)], [(String, String)])
+ Clash.Driver: createHDL :: Backend backend => backend -> ClashOpts -> IdentifierText -> IdentifierSet -> ComponentMap -> HashMap Text VDomainConfiguration -> Component -> IdentifierText -> ([(String, Doc)], [(String, FilePath)], [(String, String)])
- Clash.Driver.Types: ClashDesign :: [TopEntityT] -> DomainMap -> BindingMap -> ClashDesign
+ Clash.Driver.Types: ClashDesign :: [TopEntityT] -> BindingMap -> ClashDesign
- Clash.Driver.Types: ClashEnv :: ClashOpts -> TyConMap -> IntMap TyConName -> CompiledPrimMap -> CustomReprs -> ClashEnv
+ Clash.Driver.Types: ClashEnv :: ClashOpts -> TyConMap -> IntMap TyConName -> CompiledPrimMap -> CustomReprs -> DomainMap -> ClashEnv
- 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 -> ClashOpts
+ 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.Netlist: mkDcApplication :: HasCallStack => [HWType] -> NetlistId -> DataCon -> [Term] -> NetlistMonad (Expr, [Declaration])
+ Clash.Netlist: mkDcApplication :: HasCallStack => DeclarationType -> [HWType] -> NetlistId -> DataCon -> [Term] -> NetlistMonad (Expr, [Declaration])
- Clash.Netlist: mkSelection :: DeclarationType -> NetlistId -> Term -> Type -> [Alt] -> [Declaration] -> NetlistMonad [Declaration]
+ Clash.Netlist: mkSelection :: DeclarationType -> NetlistId -> Term -> Type -> NonEmpty Alt -> [Declaration] -> NetlistMonad [Declaration]
- Clash.Netlist: reorderCustom :: TyConMap -> CustomReprs -> Type -> [(Pat, Term)] -> [(Pat, Term)]
+ Clash.Netlist: reorderCustom :: TyConMap -> CustomReprs -> Type -> NonEmpty (Pat, Term) -> NonEmpty (Pat, Term)
- Clash.Netlist: reorderDefault :: [(Pat, Term)] -> [(Pat, Term)]
+ Clash.Netlist: reorderDefault :: NonEmpty (Pat, Term) -> NonEmpty (Pat, Term)
- Clash.Netlist.BlackBox: mkFunInput :: HasCallStack => Id -> Term -> NetlistMonad ((Either BlackBox (Identifier, [Declaration]), WireOrReg, [BlackBoxTemplate], [BlackBoxTemplate], [((Text, Text), BlackBox)], BlackBoxContext), [Declaration])
+ Clash.Netlist.BlackBox: mkFunInput :: HasCallStack => Text -> Id -> Term -> NetlistMonad ((Either BlackBox (Identifier, [Declaration]), Usage, [BlackBoxTemplate], [BlackBoxTemplate], [((Text, Text), BlackBox)], BlackBoxContext), [Declaration])
- Clash.Netlist.BlackBox: mkPrimitive :: Bool -> Bool -> NetlistId -> PrimInfo -> [Either Term Type] -> [Declaration] -> NetlistMonad (Expr, [Declaration])
+ Clash.Netlist.BlackBox: mkPrimitive :: Bool -> Bool -> DeclarationType -> NetlistId -> PrimInfo -> [Either Term Type] -> [Declaration] -> NetlistMonad (Expr, [Declaration])
- Clash.Netlist.BlackBox.Types: BlackBoxMeta :: Bool -> TemplateKind -> [BlackBoxTemplate] -> [BlackBoxTemplate] -> [(Int, Int)] -> [((Text, Text), BlackBox)] -> RenderVoid -> [BlackBox] -> [BlackBox] -> BlackBoxMeta
+ Clash.Netlist.BlackBox.Types: BlackBoxMeta :: Usage -> TemplateKind -> [BlackBoxTemplate] -> [BlackBoxTemplate] -> [(Int, Int)] -> [((Text, Text), BlackBox)] -> RenderVoid -> [BlackBox] -> [BlackBox] -> BlackBoxMeta
- Clash.Netlist.Types: Annotated :: [Attr'] -> !HWType -> HWType
+ Clash.Netlist.Types: Annotated :: [Attr Text] -> !HWType -> HWType
- Clash.Netlist.Types: Assignment :: !Identifier -> !Expr -> Declaration
+ Clash.Netlist.Types: Assignment :: !Identifier -> !Usage -> !Expr -> Declaration
- Clash.Netlist.Types: Component :: !Identifier -> [(Identifier, HWType)] -> [(WireOrReg, (Identifier, HWType), Maybe Expr)] -> [Declaration] -> Component
+ Clash.Netlist.Types: Component :: !Identifier -> [(Identifier, HWType)] -> [(Usage, (Identifier, HWType), Maybe Expr)] -> [Declaration] -> Component
- Clash.Netlist.Types: ComponentMeta :: [Bool] -> SrcSpan -> IdentifierSet -> ComponentMeta
+ Clash.Netlist.Types: ComponentMeta :: [Bool] -> SrcSpan -> IdentifierSet -> UsageMap -> ComponentMeta
- Clash.Netlist.Types: Context :: Text -> [(Expr, HWType)] -> [(Expr, HWType, Bool)] -> IntMap [(Either BlackBox (Identifier, [Declaration]), WireOrReg, [BlackBoxTemplate], [BlackBoxTemplate], [((Text, Text), BlackBox)], BlackBoxContext)] -> [IdentifierText] -> Int -> Identifier -> Maybe IdentifierText -> BlackBoxContext
+ Clash.Netlist.Types: Context :: Text -> [(Expr, HWType)] -> [(Expr, HWType, Bool)] -> IntMap [(Either BlackBox (Identifier, [Declaration]), Usage, [BlackBoxTemplate], [BlackBoxTemplate], [((Text, Text), BlackBox)], BlackBoxContext)] -> [IdentifierText] -> Int -> Identifier -> Maybe IdentifierText -> BlackBoxContext
- Clash.Netlist.Types: InstDecl :: EntityOrComponent -> Maybe Text -> [Attr'] -> !Identifier -> !Identifier -> [(Expr, HWType, Expr)] -> PortMap -> Declaration
+ Clash.Netlist.Types: InstDecl :: EntityOrComponent -> Maybe Text -> [Attr Text] -> !Identifier -> !Identifier -> [(Expr, HWType, Expr)] -> PortMap -> Declaration
- Clash.Netlist.Types: NetDecl' :: Maybe Comment -> WireOrReg -> !Identifier -> Either IdentifierText HWType -> Maybe Expr -> Declaration
+ Clash.Netlist.Types: NetDecl' :: Maybe Comment -> !Identifier -> HWType -> Maybe Expr -> Declaration
- Clash.Netlist.Types: NetlistState :: BindingMap -> ComponentMap -> (CustomReprs -> TyConMap -> Type -> State HWMap (Maybe (Either String FilteredHWType))) -> !(Identifier, SrcSpan) -> IdentifierSet -> IdentifierSet -> Set Text -> VarEnv Identifier -> VarEnv TopEntityT -> FilePath -> Int -> Bool -> Bool -> SomeBackend -> HWMap -> NetlistState
+ Clash.Netlist.Types: NetlistState :: BindingMap -> ComponentMap -> (CustomReprs -> TyConMap -> Type -> State HWMap (Maybe (Either String FilteredHWType))) -> !(Identifier, SrcSpan) -> IdentifierSet -> IdentifierSet -> Set Text -> VarEnv Identifier -> VarEnv TopEntityT -> FilePath -> Int -> Bool -> Bool -> SomeBackend -> HWMap -> UsageMap -> NetlistState
- Clash.Netlist.Types: [bbFunctions] :: BlackBoxContext -> IntMap [(Either BlackBox (Identifier, [Declaration]), WireOrReg, [BlackBoxTemplate], [BlackBoxTemplate], [((Text, Text), BlackBox)], BlackBoxContext)]
+ Clash.Netlist.Types: [bbFunctions] :: BlackBoxContext -> IntMap [(Either BlackBox (Identifier, [Declaration]), Usage, [BlackBoxTemplate], [BlackBoxTemplate], [((Text, Text), BlackBox)], BlackBoxContext)]
- Clash.Netlist.Types: [outputs] :: Component -> [(WireOrReg, (Identifier, HWType), Maybe Expr)]
+ Clash.Netlist.Types: [outputs] :: Component -> [(Usage, (Identifier, HWType), Maybe Expr)]
- Clash.Netlist.Types: hwTypeAttrs :: HWType -> [Attr']
+ Clash.Netlist.Types: hwTypeAttrs :: HWType -> [Attr Text]
- Clash.Netlist.Util: AttrError :: [Attr'] -> ExpandError
+ Clash.Netlist.Util: AttrError :: [Attr Text] -> ExpandError
- Clash.Netlist.Util: expandTopEntityOrErrM :: (HasCallStack, IdentifierSetMonad m) => [(Maybe Id, FilteredHWType)] -> (Maybe Id, FilteredHWType) -> Maybe TopEntity -> m (ExpandedTopEntity Identifier)
+ Clash.Netlist.Util: expandTopEntityOrErrM :: HasCallStack => [(Maybe Id, FilteredHWType)] -> (Maybe Id, FilteredHWType) -> Maybe TopEntity -> NetlistMonad (ExpandedTopEntity Identifier)
- Clash.Netlist.Util: mkTopCompDecl :: Maybe Text -> [Attr'] -> Identifier -> Identifier -> [(Expr, HWType, Expr)] -> [InstancePort] -> [InstancePort] -> Declaration
+ Clash.Netlist.Util: mkTopCompDecl :: Maybe Text -> [Attr Text] -> Identifier -> Identifier -> [(Expr, HWType, Expr)] -> [InstancePort] -> [InstancePort] -> Declaration
- Clash.Netlist.Util: stripAttributes :: HWType -> ([Attr'], HWType)
+ Clash.Netlist.Util: stripAttributes :: HWType -> ([Attr Text], HWType)
- Clash.Normalize.PrimitiveReductions: reduceAppend :: InScopeSet -> Integer -> Integer -> Type -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceAppend :: Integer -> Integer -> Type -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceDFold :: InScopeSet -> Integer -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceDFold :: Integer -> Type -> Term -> Term -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceDTFold :: InScopeSet -> Integer -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceDTFold :: Integer -> Type -> Term -> Term -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceFold :: TransformContext -> Integer -> Type -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceFold :: Integer -> Type -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceFoldr :: TransformContext -> PrimInfo -> Integer -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceFoldr :: PrimInfo -> Integer -> Type -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceHead :: InScopeSet -> Integer -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceHead :: Integer -> Type -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceImap :: TransformContext -> Integer -> Type -> Type -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceImap :: Integer -> Type -> Type -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceIndex_int :: InScopeSet -> Integer -> Type -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceIndex_int :: Integer -> Type -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceInit :: InScopeSet -> PrimInfo -> Integer -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceInit :: PrimInfo -> Integer -> Type -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceIterateI :: TransformContext -> Integer -> Type -> Type -> Term -> Term -> RewriteMonad NormalizeState Term
+ Clash.Normalize.PrimitiveReductions: reduceIterateI :: Integer -> Type -> Type -> Term -> Term -> Term -> TransformContext -> RewriteMonad NormalizeState Term
- Clash.Normalize.PrimitiveReductions: reduceLast :: InScopeSet -> Integer -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceLast :: Integer -> Type -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceMap :: TransformContext -> PrimInfo -> Integer -> Type -> Type -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceMap :: PrimInfo -> Integer -> Type -> Type -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceReplace_int :: InScopeSet -> Integer -> Type -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceReplace_int :: Integer -> Type -> Type -> Term -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceReplicate :: Integer -> Type -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceReplicate :: Integer -> Type -> Type -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceReverse :: InScopeSet -> Integer -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceReverse :: Integer -> Type -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceTFold :: InScopeSet -> Integer -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceTFold :: Integer -> Type -> Term -> Term -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceTReplicate :: Integer -> Type -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceTReplicate :: Integer -> Type -> Type -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceTail :: InScopeSet -> Integer -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceTail :: Integer -> Type -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceTranspose :: Integer -> Integer -> Type -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceTranspose :: Integer -> Integer -> Type -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceTraverse :: TransformContext -> Integer -> Type -> Type -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceTraverse :: Integer -> Type -> Type -> Type -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceUnconcat :: InScopeSet -> PrimInfo -> Integer -> Integer -> Type -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceUnconcat :: PrimInfo -> Integer -> Integer -> Type -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Normalize.PrimitiveReductions: reduceZipWith :: TransformContext -> PrimInfo -> Integer -> Type -> Type -> Type -> Term -> Term -> Term -> NormalizeSession Term
+ Clash.Normalize.PrimitiveReductions: reduceZipWith :: PrimInfo -> Integer -> Type -> Type -> Type -> Term -> Term -> Term -> TransformContext -> NormalizeSession Term
- Clash.Primitives.DSL: boolFromBit :: Text -> TExpr -> State (BlockState VHDLState) TExpr
+ Clash.Primitives.DSL: boolFromBit :: (HasCallStack, Backend backend) => Text -> TExpr -> State (BlockState backend) TExpr
- Clash.Primitives.DSL: fromBV :: (HasCallStack, Backend backend) => Text -> TExpr -> State (BlockState backend) TExpr
+ Clash.Primitives.DSL: fromBV :: (HasCallStack, Backend backend) => Text -> HWType -> TExpr -> State (BlockState backend) TExpr
- Clash.Primitives.DSL: instDecl :: forall backend. Backend backend => EntityOrComponent -> Identifier -> Identifier -> [(Text, LitHDL)] -> [(Text, TExpr)] -> [(Text, TExpr)] -> State (BlockState backend) ()
+ Clash.Primitives.DSL: instDecl :: forall backend. Backend backend => EntityOrComponent -> Identifier -> Identifier -> [(Text, TExpr)] -> [(Text, TExpr)] -> [(Text, TExpr)] -> State (BlockState backend) ()
- Clash.Primitives.DSL: unsignedFromBitVector :: HasCallStack => Size -> Text -> TExpr -> State (BlockState VHDLState) TExpr
+ Clash.Primitives.DSL: unsignedFromBitVector :: (HasCallStack, Backend backend) => Text -> TExpr -> State (BlockState backend) TExpr
- Clash.Primitives.DSL: viaAnnotatedSignal :: (HasCallStack, Backend backend) => Identifier -> TExpr -> TExpr -> [Attr'] -> State (BlockState backend) ()
+ Clash.Primitives.DSL: viaAnnotatedSignal :: (HasCallStack, Backend backend) => Identifier -> TExpr -> TExpr -> [Attr Text] -> State (BlockState backend) ()
- Clash.Primitives.Types: BlackBox :: !Text -> WorkInfo -> RenderVoid -> Bool -> TemplateKind -> c -> Bool -> [a] -> [a] -> [(Int, Int)] -> [((Text, Text), b)] -> [b] -> [b] -> b -> Primitive a b c d
+ Clash.Primitives.Types: BlackBox :: !Text -> WorkInfo -> RenderVoid -> Bool -> TemplateKind -> c -> Usage -> [a] -> [a] -> [(Int, Int)] -> [((Text, Text), b)] -> [b] -> [b] -> b -> Primitive a b c d
- Clash.Rewrite.Types: bindings :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) BindingMap
+ Clash.Rewrite.Types: bindings :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) BindingMap
- Clash.Rewrite.Types: curFun :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) (Id, SrcSpan)
+ Clash.Rewrite.Types: curFun :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) (Id, SrcSpan)
- Clash.Rewrite.Types: extra :: forall extra_a3VQV extra_a3VYH. Lens (RewriteState extra_a3VQV) (RewriteState extra_a3VYH) extra_a3VQV extra_a3VYH
+ Clash.Rewrite.Types: extra :: forall extra_a4iUn extra_a4j29. Lens (RewriteState extra_a4iUn) (RewriteState extra_a4j29) extra_a4iUn extra_a4j29
- Clash.Rewrite.Types: globalHeap :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) PrimHeap
+ Clash.Rewrite.Types: globalHeap :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) PrimHeap
- Clash.Rewrite.Types: nameCounter :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) Int
+ Clash.Rewrite.Types: nameCounter :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) Int
- Clash.Rewrite.Types: transformCounter :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) Word
+ Clash.Rewrite.Types: transformCounter :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) Word
- Clash.Rewrite.Types: transformCounters :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) (HashMap Text Word)
+ Clash.Rewrite.Types: transformCounters :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) (HashMap Text Word)
- Clash.Rewrite.Types: uniqSupply :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) Supply
+ Clash.Rewrite.Types: uniqSupply :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) Supply
- Clash.Rewrite.Types: workFreeBinders :: forall extra_a3VQV. Lens' (RewriteState extra_a3VQV) (VarEnv Bool)
+ Clash.Rewrite.Types: workFreeBinders :: forall extra_a4iUn. Lens' (RewriteState extra_a4iUn) (VarEnv Bool)

Files

CHANGELOG.md view
@@ -1,8 +1,147 @@ # Changelog for the Clash project++## 1.8.0++Release highlights:++* Support for GHC 9.2, 9.4, 9.6 and 9.8. While GHC 9.2 is supported, we recommend users to skip this version as there is a severe degradation of error message quality. With this change, Clash now supports GHC versions 8.6 through 9.8.+* Major overhaul of the clocking functionality in `Clash.Xilinx.ClockGen` and `Clash.Intel.ClockGen`, see their respective entries below+* `mealyS` function (and several variations) to make writing state machines using the strict `State` monad easier+* Overhaul of `resetGlitchFilter`, see its respective entries below.++Added:++* `altpllSync` and `alteraPllSync` in `Clash.Intel.ClockGen`. These replace the deprecated functions without the `Sync` suffix. Unlike the old functions, these functions are safe to use and have a reset signal for each output domain that can be used to keep the domain in reset while the clock output stabilizes. All PLL functions now also support multiple clock outputs like the old `alteraPll` did. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)+*  A new clock type `DiffClock` is introduced to signify a differential clock signal that is passed to the design on two ports in antiphase. This is used by the differential Xilinx clock wizards in `Clash.Xilinx.ClockGen`. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)+* `Clash.Explicit.Testbench.clockToDiffClock`, to create a differential clock signal in a test bench. It is not suitable for synthesizing a differential output in hardware. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)+* `resetGlitchFilterWithReset`, which accomplishes the same task as `resetGlitchFilter` in domains with unknown initial values by adding a power-on reset input to reset the glitch filter itself. [#2544](https://github.com/clash-lang/clash-compiler/pull/2544)+* Convenience functions: `noReset`, `andReset`, `orReset` plus their unsafe counterparts [#2539](https://github.com/clash-lang/clash-compiler/pull/2539)+* Convenience constraint aliases: `HasSynchronousReset`, `HasAsynchronousReset`, and `HasDefinedInitialValues` [#2539](https://github.com/clash-lang/clash-compiler/pull/2539)+* `Clash.Prelude.Mealy.mealyS` and `Clash.Explicit.Mealy.mealyS` and their bundled equivalents `mealySB` which make writing state machines using the strict `State` monad easier. The tutorial has also been simplified by using this change. [#2484](https://github.com/clash-lang/clash-compiler/pull/2484)+* An experimental feature allowing clocks to vary their periods over time, called "dynamic clocks". Given that this is an experimental feature, it is not part of the public API. [#2295](https://github.com/clash-lang/clash-compiler/pull/2295)+* The prelude now exports `+>>.` and `.<<+`, which can be used to shift in a bit into a `BitVector` from the left or right respectively - similar to `+>>` and `<<+` for `Vec`s. [#2307](https://github.com/clash-lang/clash-compiler/pull/2307)+* `Clash.DataFiles.tclConnector` and the executable `static-files` in `clash-lib`. They provide the Tcl Connector, a Tcl script that allows Vivado to interact with the metadata generated by Clash (Quartus support will be added later). See `Clash.DataFiles.tclConnector` for further information. More documentation about the Tcl Connector and the Clash<->Tcl API will be made available later. [#2335](https://github.com/clash-lang/clash-compiler/pull/2335)+* Add `BitPack`, `NFDataX` and `ShowX` instances for `Ordering` [#2366](https://github.com/clash-lang/clash-compiler/pull/2366)+* Verilog users can now influence the "precision" part of the generated `timescale` pragma using `-fclash-timescale-precision`. [#2353](https://github.com/clash-lang/clash-compiler/pull/2353)+* Clash now includes blackboxes for `integerToFloat#`, `integerToDouble#` [#2342](https://github.com/clash-lang/clash-compiler/issues/2342)+* Instances `Arbitrary (Erroring a)`, `Arbitrary (Saturating a)`, `Arbitrary (Saturating a)`, and `Arbitrary (Zeroing a)` [#2356](https://github.com/clash-lang/clash-compiler/pull/2356)+* `Clash.Magic.clashSimulation`, a way to differentiate between Clash simulation and generating HDL. [#2473](https://github.com/clash-lang/clash-compiler/pull/2473)+* `Clash.Magic.clashCompileError`: make HDL generation error out with a custom error message. Simulation in Clash will also error when the function is evaluated, including a call stack. HDL generation unfortunately does not include a call stack. [#2399](https://github.com/clash-lang/clash-compiler/pull/2399)+* Added `Clash.XException.MaybeX`, a data structure with smart constructors that can help programmers deal with `XException` values in their blackbox model implementations [#2442](https://github.com/clash-lang/clash-compiler/pull/2442)+*  `Clash.Magic.SimOnly`, A container for data you only want to have around during simulation and is ignored during synthesis. Useful for carrying around things such as: a map of simulation/vcd traces, co-simulation state or meta-data, etc. [#2464](https://github.com/clash-lang/clash-compiler/pull/2464)+* `KnownNat (DomainPeriod dom)` as an implied constraint to `KnownDomain dom`. This reduces the amount of code needed to write - for example - clock speed dependent code. [#2541](https://github.com/clash-lang/clash-compiler/pull/2541)+* `Clash.Annotations.SynthesisAttributes.annotate`: a term level way of annotating signals with synthesis attributes [#2547](https://github.com/clash-lang/clash-compiler/pull/2547)+* `Clash.Annotations.SynthesisAttributes.markDebug`: a way of marking a signals "debug", instructing synthesizers to leave the signal alone and offer debug features [#2547](https://github.com/clash-lang/clash-compiler/pull/2547)+* Add hex and octal BitVector parsing. [#1772](https://github.com/clash-lang/clash-compiler/pull/2505)+* `1 <= n => Foldable1 (Vec n)` instance (`base-4.18+` only) [#2563](https://github.com/clash-lang/clash-compiler/pull/2563)+* You can now use `~PERIOD`, `~ISSYNC`, `~ISINITDEFINED` and `~ACTIVEEDGE` on arguments of type `Clock`, `Reset`, `Enable`,`ClockN` and `DiffClock`. [#2590](https://github.com/clash-lang/clash-compiler/pull/2590)++Removed:++* Deprecated module `Clash.Prelude.BitIndex`: functions have been moved to `Clash.Class.BitPack` [#2555](https://github.com/clash-lang/clash-compiler/pull/2555)+* Deprecated module `Clash.Prelude.BitReduction`: functions have been moved to `Clash.Class.BitPack` [#2555](https://github.com/clash-lang/clash-compiler/pull/2555)+* Deprecated function `Clash.Explicit.Signal.enable`: function has been renamed to `andEnable` [#2555](https://github.com/clash-lang/clash-compiler/pull/2555)+* The module `Clash.Clocks.Deriving` has been removed. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)++Deprecated:++* `unsafeFromLowPolarity`, `unsafeFromHighPolarity`, `unsafeToLowPolarity`, `unsafeToHighPolarity` have been replaced by `unsafeFromActiveLow`, `unsafeFromActiveHigh`, `unsafeToActiveLow`, `unsafeToActiveHigh`. While former ones will continue to exist, a deprecation warning has been added pointing to the latter ones. [#2540](https://github.com/clash-lang/clash-compiler/pull/2540)+* The functions `altpll` and `alteraPll` in `Clash.Intel.ClockGen` have been deprecated because they are unsafe to use while this is not apparent from the name. The `locked` output signal of these functions is an asynchronous signal which needs to be synchronized before it can be used (something the examples did in fact demonstrate). For the common use case, new functions are available, named `altpllSync` and `alteraPllSync`. These functions are safe. For advanced use cases, the old functionality can be obtained through `unsafeAltpll` and `unsafeAlteraPll`. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)++Changed:++* The wizards in `Clash.Xilinx.ClockGen` have been completely overhauled. The original functions were unsafe and broken in several ways. See the documentation in `Clash.Xilinx.ClockGen` for how to use the new functions. Significant changes are:+  * `clockWizard` and `clockWizardDifferential` now output a `Clock` and a `Reset` which can be directly used by logic. Previously, it outputted a clock and an asynchronous `locked` signal which first needed to be synchronized before it could be used (hence the old function being unsafe). Additionally, the original `locked` signal was strange: it mistakenly was an `Enable` instead of a `Signal dom Bool` and there was a polarity mismatch between Clash simulation and HDL. The `locked` signal was also not resampled to the output domain in Clash simulation.+  * There are new functions `unsafeClockWizard` and `unsafeClockWizardDifferential` for advanced use cases which directly expose the `locked` output of the wizard.+  * All clock generators now have the option to output multiple clocks from a single instance.+  * `clockWizardDifferential` now gets its input clock as a `DiffClock` type; use `clockToDiffClock` to generate this in your test bench if needed. Previously, the function received two clock inputs, but this generated `create_clock` statements in the top-level SDC file for both phases which is incorrect.+  * A constraint was removed: The _output_ clock domain no longer requires asynchronous resets. This was originally intended to signal that the outgoing lock signal is an asynchronous signal. The constraint does not convey this  information at all and is wrong; it also prevents using synchronous resets in the circuit as recommended by Xilinx. Note that if you use the `unsafe` functions, it is still necessary to synchronize the `locked` output in your design.+  * The port names of the primitives in HDL are now correctly lower case.+  * Add Tcl generation. This moves the responsibility of MMCM component generation from the user to `clashConnector.tcl`, which can be found in [`clash-lib:Clash.DataFiles`](https://hackage.haskell.org/package/clash-lib-1.8.0/docs/Clash-DataFiles.html).+  * The wizards now use the user-provided name as the name of the _instance_ rather than the name of the _IP core_. This change was also done for `Clash.Intel.ClockGen` in Clash v1.2.0 in March 2020, when Clash started generating Intel Qsys files. Before that, the user needed to generate a Qsys component manually. Now, in Clash v1.8.0, we also generate the Tcl for Xilinx wizards. When the user is responsible for creating the IP core, it makes sense to always set the component name to the user-provided value. But when that is also generated by Clash, that is no longer needed. Allowing users to set the instance name instead makes it possible to match on the instance in SDC files and such.+  [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)+* The IP core generators in `Clash.Intel.ClockGen` now declare that their input domain needs to have asynchronous resets (`HasAsynchronousReset`), as the functions react asynchronously to their reset input and thus need to be glitch-free. The functions marked `unsafe` do not have this constraint; instead, the function documentation calls attention to the requirement. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)+* `resetGlitchFilter` now uses a counter instead of shift register, allowing glitch filtering over much larger periods. [#2374](https://github.com/clash-lang/clash-compiler/pull/2374)+* `resetGlitchFilter` now filters glitches symmetrically, only deasserting the reset after the incoming reset has stabilized. For more information, read [#2374](https://github.com/clash-lang/clash-compiler/pull/2374).+* `resetGlitchFilter` does not support domains with unknown initial values anymore. Its previous behavior could lead to unstable circuits. Domains not supporting initial values should consider using `resetGlitchFilterWithReset` or `holdReset`. The previous behavior can still be attained through the new `unsafeResetGlitchFilter`. [#2544](https://github.com/clash-lang/clash-compiler/pull/2544)+* `fromJustX` now uses `deepErrorX` instead of `errorX`. This adds `NFDataX` constraints to `blockRam` like functions, `asyncRam` and `writeToBiSignal`. [#2113](https://github.com/clash-lang/clash-compiler/pull/2113)+*  All memory functions now use `deepErrorX` for `XException`s. This adds `NFDataX` constraints to `asyncRom`, `asyncRomPow2` and `asyncRom#`. [#2113](https://github.com/clash-lang/clash-compiler/pull/2113)+* Before this release, `scanl1` was re-exported from the Haskell Prelude. Clash's Prelude now exports a `Vec` specialized version. [#2172](https://github.com/clash-lang/clash-compiler/pull/2172)+* When generating (System)Verilog, Clash now sets the default net type to `none`. This means any implicitly declared signal in the design will trigger an error when elaborating the design. [#2174](https://github.com/clash-lang/clash-compiler/pull/2174)+* Blackbox templates no longer have the `outputReg` key, it has been replaced with the more general `outputUsage` which specifies how signals are used in terms of whether writes are++    * continuous (i.e. a concurrent context)+    * procedural non-blocking (i.e. `signal` in a VHDL process)+    * procedural blocking (i.e. `variable` in a VHDL process)++  The `~OUTPUTWIREREG` tag continues to work for backwards compatibility, but there is also a new `~OUTPUTUSAGE` tag which is recommended. In the future, the `~OUTPUTWIREREG` tag may be removed. [#2230](https://github.com/clash-lang/clash-compiler/pull/2230)+* `Clash.Explicit.Testbench.outputVerifier` now takes an additional clock as an argument: the clock used by the circuit under test. If your tests use the same domain for the test circuit and design under test, consider using `Clash.Explicit.Testbench.outputVerifier'`. [#2295](https://github.com/clash-lang/clash-compiler/pull/2295)+* `Clash.Explicit.Signal.veryUnsafeSynchronizer` now accepts either a static clock period or a dynamic one. If you don't use dynamic clocks, convert your calls to use `Left`. [#2295](https://github.com/clash-lang/clash-compiler/pull/2295)+* `SDomainConfiguration` is now a record, easing field access. [#2349](https://github.com/clash-lang/clash-compiler/pull/2349)+*  Generalized the return types of `periodToHz` and `hzToPeriod`. Use a type application (`periodToHz @(Ratio Natural)`, `hzToPeriod @Natural`) to get the old behavior back, in case type errors arise. [#2436](https://github.com/clash-lang/clash-compiler/pull/2436)+* `periodToHz` and `hzToPeriod` now throw an `ErrorCall` with call stack when called with the argument 0 (zero), instead of a `RatioZeroDenominator :: ArithException`. [#2436](https://github.com/clash-lang/clash-compiler/pull/2436)+* `hasX` now needs an `NFDataX` constraint, in addition to an `NFData` one. This API change was made to fix an issue where `hasX` would hide error calls in certain situations, see [#2450](https://github.com/clash-lang/clash-compiler/issues/2450).+* Clock generators now wait at least 100 ns before producing their first tick. This change has been implemented to account for Xilinx's GSR in clock synchronization primitives. This change does not affect Clash simulation. See [#2455](https://github.com/clash-lang/clash-compiler/issues/2455).+* From GHC 9.4.1 onwards the following types: `BiSignalOut`, `Index`, `Signed`, `Unsigned`, `File`, `Ref`, and `SimIO` are all encoded as `newtype` instead of `data` now that [#2511](https://github.com/clash-lang/clash-compiler/pull/2511) is merged. This means you can once again use `Data.Coerce.coerce` to coerce between these types and their underlying representation. [#2535](https://github.com/clash-lang/clash-compiler/pull/2535)+* The `Foldable (Vec n)` instance and `Traversable (Vec n)` instance no longer have the `1 <= n` constraint. `Foldable.{foldr1,foldl1,maximum,minimum}` functions now throw an error at run-/simulation-time, and also at HDL-generation time, for vectors of length zero. [#2563](https://github.com/clash-lang/clash-compiler/pull/2563)+* The `maximum` and `minimum` functions exported by `Clash.Prelude` work on non-empty vectors, instead of the more generic version from `Data.Foldable`. [#2563](https://github.com/clash-lang/clash-compiler/pull/2563)+* `unsafeToReset` and `invertReset` now have a KnownDomain constraint This was done in preparation for [Remove KnownDomain #2589](https://github.com/clash-lang/clash-compiler/pull/2589)++Fixed:++* `altpll` and `alteraPll` in `Clash.Intel.ClockGen` now account for the input domain's `ResetPolarity`. Before this fix, the reset was always interpreted as an active-high signal. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)+* Fix `alteraPll` `qsys` generation. PR [#2417](https://github.com/clash-lang/clash-compiler/pull/2417) (included in Clash v1.6.5) caused a bug in the generation of the `qsys` file: it generated a spurious extra output clock which was completely unused otherwise. [#2587](https://github.com/clash-lang/clash-compiler/pull/2587)+* Files in `clash-manifest.json` are now (correctly) listed in reverse topological order [#2334](https://github.com/clash-lang/clash-compiler/issues/2334)+* Dependencies in `clash-manifest.json` are now listed in reverse topological ordering [#2325](https://github.com/clash-lang/clash-compiler/issues/2325)+* Clash now renders undefined bits set via `-fclash-force-undefined` correctly [#2360](https://github.com/clash-lang/clash-compiler/issues/2360)+* `resetGen`'s documentation now mentions it is non-synthesizable ([#2375](https://github.com/clash-lang/clash-compiler/issues/2375))+* `trueDualPortBlockRam` now handles undefined values in its input correctly  [#2350](https://github.com/clash-lang/clash-compiler/issues/2350)+* `trueDualPortBlockRam` now correctly handles port enables when clock edges coincide [#2351](https://github.com/clash-lang/clash-compiler/issues/2351)+* `Clash.Primitives.DSL.deconstructProduct` now projects fields out of a product [#2469](https://github.com/clash-lang/clash-compiler/issues/2469)+* BiSignal test does not look through `Annotate` [#2472](https://github.com/clash-lang/clash-compiler/issues/2472)+* Port size not rendered when type has more than one `Annotate` [#2475](https://github.com/clash-lang/clash-compiler/pull/2475)+* Clash now preserves `NOINLINE` of functions being specialized [#2502](https://github.com/clash-lang/clash-compiler/issues/2502)+* When `convertReset` was used with two domains that had a different reset polarity, the polarity of the signal was not changed.+* Functional arguments of primitives cannot have 0-bit results [#2549](https://github.com/clash-lang/clash-compiler/issues/2549)+* If the source reset of `convertReset` is synchronous, a flip-flop in the source domain is inserted to filter glitches from the source reset. [#2573](https://github.com/clash-lang/clash-compiler/pull/2573)+* SystemVerilog backend: Assignment patterns for unpacked arrays now have an index for every element; improves QuestaSim compatibility. [#2595](https://github.com/clash-lang/clash-compiler/pull/2595)+* Name duplication in generated Verilog involving reset synchronizer [#2598](https://github.com/clash-lang/clash-compiler/issues/2598)++Internal added:++* `Clash.Primitives.DSL.instDecl` now accepts `TExpr`s instead of `LitHDL`s as generics/parameters. This allows for VHDL black boxes to use all possible generic types. To ease transition, `litTExpr` has been added to `Clash.Primitives.DSL`. [#2471](https://github.com/clash-lang/clash-compiler/issues/2471)+* `Clash.Core.TermLiteral.deriveTermToData` now works on records [#2270](https://github.com/clash-lang/clash-compiler/pull/2270)+* `Clash.Primitives.getVec` tries to get all elements in a Vector from an expression [#2483](https://github.com/clash-lang/clash-compiler/pull/2483)+* Added `Clash.Primitives.DSL.deconstructMaybe`. This DSL function makes it easy to deconstruct a `Maybe` into its constructor bit and data. This is often useful for primitives taking 'enable' and 'data' signals. [#2202](https://github.com/clash-lang/clash-compiler/pull/2202)+* Added `unsafeToActiveHigh` and `unsafeToActiveLow` to `Clash.Primitives.DSL`. [#2270](https://github.com/clash-lang/clash-compiler/pull/2270)+* Added `TermLiteral` instance for `Either` [#2329](https://github.com/clash-lang/clash-compiler/pull/2329)+* `Clash.Primitives.DSL.declareN`, a companion to `declare` which declares multiple signals in one go. [#2592](https://github.com/clash-lang/clash-compiler/pull/2592)++Internal changes:++* `Clash.Primitives.DSL.boolFromBit` is now polymorphic in its HDL backend. [#2202](https://github.com/clash-lang/clash-compiler/pull/2202)+* `Clash.Primitives.DSL.unsignedFromBitVector` is now polymorphic in its HDL backend. [#2202](https://github.com/clash-lang/clash-compiler/pull/2202)+* `Clash.Primitives.DSL.fromBV` now converts some `BitVector` expression into some type. [#2202](https://github.com/clash-lang/clash-compiler/pull/2202)+* Add `CompDecl` to `Clash.Netlist.Types.Declaration` to accomodate VHDL's `component` declarations.+* Black box functions declare their usage, necessary for implicit netlist usage analysis implemented in [#2230](https://github.com/clash-lang/clash-compiler/pull/2230)+* Added `showsTypePrec` to `TermLiteral` to make `TermLiteral SNat` work as expected. Deriving an instance is now a bit simpler. Instances which previously had to be defined as:++  ```haskell+  instance TermLiteral Bool where+    termToData = $(deriveTermToData ''Bool)+  ```++  can now be defined using:++  ```haskell+  deriveTermLiteral ''Bool+  ```+  [#2329](https://github.com/clash-lang/clash-compiler/pull/2329)+ ## 1.6.6 *Oct 2nd 2023* -* Support Aeson 2.2 [#2578](https://github.com/clash-lang/clash-compiler/pull/2578)-* Drop the snap package [#2439](https://github.com/clash-lang/clash-compiler/pull/2439)+* Support Aeson 2.2+* Dropped the snap package      The Clash snap package has not been a recommended way to use Clash for quite some time, and it is a hassle to support. @@ -63,7 +202,6 @@ Internal change:   * Clash now always generates non-extended identifiers for port names, so that generated names play nicer with different vendor tools. [#2142](https://github.com/clash-lang/clash-compiler/pull/2142)   * Top entity name available in netlist context. Top entity name used in generated name for include files. [#2146](https://github.com/clash-lang/clash-compiler/pull/2146)-  ## 1.6.2 *Feb 25th 2022* Fixed:
README.md view
@@ -10,9 +10,8 @@  Features of Clash: -  * Strongly typed (like VHDL), yet with a very high degree of type inference,-    enabling both safe and fast prototying using consise descriptions (like-    Verilog).+  * Strongly typed, but with a very high degree of type inference, enabling both+    safe and fast prototyping using concise descriptions.    * Interactive REPL: load your designs in an interpreter and easily test all     your component without needing to setup a test bench.
clash-lib.cabal view
@@ -1,6 +1,6 @@ Cabal-version:        2.2 Name:                 clash-lib-Version:              1.6.6+Version:              1.8.0 Synopsis:             Clash: a functional hardware description language - As a library Description:   Clash is a functional hardware description language that borrows both its@@ -51,7 +51,7 @@ Maintainer:           QBayLogic B.V. <devops@qbaylogic.com> Copyright:            Copyright © 2012-2016, University of Twente,                                   2016-2019, Myrtle Software Ltd,-                                  2017-2019, QBayLogic B.V., Google Inc.+                                  2017-2023, QBayLogic B.V., Google Inc. Category:             Hardware Build-type:           Simple @@ -61,6 +61,7 @@   src/ClashDebug.h  Data-files:+  data-files/tcl/clashConnector.tcl   prims/common/*.primitives.yaml,   prims/commonverilog/*.primitives.yaml,   prims/verilog/*.primitives.yaml,@@ -84,6 +85,18 @@   default: True   manual: True +flag doctests+  description:+    You can disable testing with doctests using `-f-doctests`.+  default: True+  manual: True++flag workaround-ghc-mmap-crash+  description:+    Only use this flag when hit by GHC bug #19421. See clash-compiler PR #2444.+  default: False+  manual: True+ common common-options   default-language:   Haskell2010   default-extensions: BangPatterns@@ -100,6 +113,7 @@                       InstanceSigs                       KindSignatures                       NoStarIsType+                      PostfixOperators                       ScopedTypeVariables                       StandaloneDeriving                       TupleSections@@ -129,7 +143,7 @@   Build-depends:      aeson                   >= 0.6.2.0  && < 2.3,                       attoparsec-aeson        >= 2.1      && < 2.3,                       aeson-pretty            >= 0.8      && < 0.9,-                      ansi-terminal           >= 0.8.0.0  && < 0.12,+                      ansi-terminal           >= 0.8.0.0  && < 1.1,                       array,                       async                   >= 2.2.0    && < 2.3,                       attoparsec              >= 0.10.4.0 && < 0.15,@@ -137,31 +151,33 @@                       base16-bytestring       >= 0.1.1    && < 1.1,                       binary                  >= 0.8.5    && < 0.11,                       bytestring              >= 0.10.0.2 && < 0.12,-                      clash-prelude           == 1.6.6,+                      clash-prelude           == 1.8.0,                       concurrent-supply       >= 0.1.7    && < 0.2,                       containers              >= 0.5.0.0  && < 0.7,                       cryptohash-sha256       >= 0.11     && < 0.12,                       data-binary-ieee754     >= 0.4.4    && < 0.6,                       data-default            >= 0.7      && < 0.8,-                      deepseq                 >= 1.3.0.2  && < 1.5,+                      deepseq                 >= 1.3.0.2  && < 1.6,                       dlist                   >= 0.8      && < 1.1,                       directory               >= 1.2.0.1  && < 1.4,                       exceptions              >= 0.8.3    && < 0.11.0,                       extra                   >= 1.6.17   && < 1.8,                       filepath                >= 1.3.0.1  && < 1.5,-                      ghc                     >= 8.6.0    && < 9.1,+                      ghc                     >= 8.6.0    && < 9.9,                       ghc-boot-th,                       hashable                >= 1.2.1.0  && < 1.5,                       haskell-src-meta        >= 0.8      && < 0.9,                       hint                    >= 0.7      && < 0.10,-                      interpolate             >= 0.2.0    && < 1.0,+                      infinite-list           ^>= 0.1,                       lens                    >= 4.10     && < 5.3,-                      mtl                     >= 2.1.2    && < 2.3,+                      mtl                     >= 2.1.2    && < 2.4,                       ordered-containers      >= 0.2      && < 0.3,                       prettyprinter           >= 1.2.0.1  && < 1.8,+                      prettyprinter-interp    ^>= 0.2,                       pretty-show             >= 1.9      && < 2.0,                       primitive               >= 0.5.0.1  && < 1.0,-                      template-haskell        >= 2.8.0.0  && < 2.18,+                      string-interpolate      ^>= 0.3,+                      template-haskell        >= 2.8.0.0  && < 2.22,                       temporary               >= 1.2.1    && < 1.4,                       terminal-size           >= 0.3      && < 0.4,                       text                    >= 1.2.2    && < 2.1,@@ -173,8 +189,11 @@                       unordered-containers    >= 0.2.3.3  && < 0.3,                       yaml                    >= 0.11     && < 0.12, +  if impl(ghc < 9.4.0)+    build-depends:+   if impl(ghc >= 9.0.0)-    build-depends:     ghc-bignum >=1.0 && <1.3+    build-depends:     ghc-bignum >=1.0 && <1.4   else     build-depends:     integer-gmp >=1.0 && <1.1 @@ -185,6 +204,7 @@                       Clash.Backend                       Clash.Backend.SystemVerilog                       Clash.Backend.Verilog+                      Clash.Backend.Verilog.Time                       Clash.Backend.VHDL                        Clash.Core.DataCon@@ -212,6 +232,10 @@                       Clash.Core.Var                       Clash.Core.VarEnv +                      Clash.Data.UniqMap++                      Clash.DataFiles+                       Clash.Debug                        Clash.Driver@@ -225,6 +249,7 @@                       Clash.Netlist.BlackBox.Parser                       Clash.Netlist.BlackBox.Types                       Clash.Netlist.BlackBox.Util+                      Clash.Netlist.Expr                       Clash.Netlist.Id                       Clash.Netlist.Id.Common                       Clash.Netlist.Id.Internal@@ -258,14 +283,17 @@                       Clash.Primitives.Types                       Clash.Primitives.Util +                      Clash.Primitives.Annotations.SynthesisAttributes                       Clash.Primitives.GHC.Int                       Clash.Primitives.GHC.Literal                       Clash.Primitives.GHC.Word                       Clash.Primitives.Intel.ClockGen+                      Clash.Primitives.Magic                       Clash.Primitives.Sized.ToInteger                       Clash.Primitives.Sized.Signed                       Clash.Primitives.Sized.Vector                       Clash.Primitives.Verification+                      Clash.Primitives.Xilinx.ClockGen                        Clash.Rewrite.Combinators                       Clash.Rewrite.Types@@ -288,6 +316,9 @@                       -- Used in clash-cores                       Data.Text.Prettyprint.Doc.Extra +                      -- Used in clash-ghc+                      GHC.BasicTypes.Extra+   Other-Modules:      Clash.Annotations.TopEntity.Extra                       Data.IntMap.Extra                       Data.List.Extra@@ -296,7 +327,6 @@                       Data.Primitive.ByteArray.Extra                       Data.Set.Ordered.Extra                       Data.Text.Extra-                      GHC.BasicTypes.Extra                       GHC.SrcLoc.Extra                       Paths_clash_lib @@ -320,12 +350,49 @@   GHC-Options:        -Wall -Wcompat   default-language:   Haskell2010 +executable static-files+  Main-Is:            tools/static-files.hs+  Build-Depends:+    base,+    clash-lib,+    directory,+    docopt                  ^>= 0.7,+    extra,+    filepath+  GHC-Options:        -Wall -Wcompat+  default-language:   Haskell2010+  if impl(ghc >= 9.2.0)+    buildable: False+++test-suite doctests+  type:             exitcode-stdio-1.0+  default-language: Haskell2010+  main-is:          doctests.hs+  ghc-options:      -Wall -Wcompat -threaded+  hs-source-dirs:   tests++  if !flag(doctests)+    buildable: False+  else+    build-depends:+      base,+      clash-lib,+      doctest-parallel >= 0.2 && < 0.4,+      filepath+ test-suite unittests   import:           common-options   type:             exitcode-stdio-1.0   default-language: Haskell2010   main-is:          unittests.hs-  ghc-options:      -Wall -Wcompat -threaded -with-rtsopts=-N+  ghc-options:      -Wall -Wcompat -threaded+  -- Note that multiple -with-rtsopts are not cumulative, so we can't add the+  -- common RTS options in the unconditional GHC-Options+  if flag(workaround-ghc-mmap-crash)+    GHC-Options: "-with-rtsopts=-N -xm20000000"+  else+    GHC-Options: -with-rtsopts=-N   hs-source-dirs:   tests    if !flag(unittests)@@ -352,9 +419,10 @@       lens,       pretty-show,       quickcheck-text,-      tasty         >= 1.2      && < 1.5,+      tasty         >= 1.2      && < 1.6,       tasty-hunit,       tasty-quickcheck,+      tasty-th,       template-haskell,       text,       transformers,@@ -362,6 +430,8 @@    Other-Modules: Clash.Tests.Core.FreeVars                  Clash.Tests.Core.Subst+                 Clash.Tests.Core.TermLiteral+                 Clash.Tests.Core.TermLiteral.Types                  Clash.Tests.Driver.Manifest                  Clash.Tests.Netlist.Id                  Clash.Tests.Util.Interpolate
+ data-files/tcl/clashConnector.tcl view
@@ -0,0 +1,606 @@+# Copyright  :  (C) 2021-2022, QBayLogic B.V.,+#                   2022     , Google Inc.,+# License    :  BSD2 (see the file LICENSE)+# Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>+#+# Script to parse output generated by Clash to use in the synthesis tool.+#+# TODO: More user documentation++package require json++namespace eval clash {+    variable metadata {}+    variable topEntity++    # Set verbosity level. Range is 0-4, where 0 means "silent". Example:+    #     set clash::verbosity 3+    variable verbosity 1++    # Dry run can be enabled by+    #     set clash::dryRun true+    variable dryRun false++    # Invoke with $topEntityDir set to the path where the manifest file of+    # your top entity is. Read all the metadata generated by Tcl: manifests+    # and Tcl interface scripts, for the top entity and its dependencies.+    proc readMetadata topEntityDir {+        variable metadata+        variable topEntity++        # If we are called multiple times, we will remove the results of+        # earlier invocations.+        set metadata [dict create]+        if {[namespace exists tclIface]} {+            namespace delete tclIface+        }++        set topEntity [ParseManifest $topEntityDir true]+        Log 1 "Top entity is $topEntity"+        return+    }++    # Issue "read_vhdl" / "read_verilog" for all HDL files generated by Clash+    proc readHdl {} {+        variable metadata+        variable topEntity++        CheckMetadataExists+        set libs [dict get $metadata $topEntity dependencies]+        lappend libs $topEntity+        foreach lib $libs {+            foreach hdlFile [dict get $metadata $lib hdlFiles] {+                if {[string match {*.vhdl} $hdlFile]} {+                    PerformAction {+                        read_vhdl -library } -var lib { } -var hdlFile+                } elseif {[string match {*.v} $hdlFile]} {+                    PerformAction {+                        read_verilog } -var hdlFile+                } elseif {[string match {*.sv} $hdlFile]} {+                    PerformAction {+                        read_verilog -sv } -var hdlFile+                } else {+                    error "Error: Unknown extension on HDL file $hdlFile"+                }+            }+        }+        return+    }++    # Issue "read_xdc" for all constraint files generated by Clash for the top+    # entity, and all constraint files managed by the Clash<->Tcl API (not just+    # for the top entity, but for all libraries).+    proc readXdc orders {+        variable metadata+        variable topEntity++        CheckMetadataExists+        foreach order $orders {+            if {$order ni {early normal late}} {+                error "Error: readXdc: Invalid order $order"+            }+        }+        unset order++        set early {}+        set normal {}+        set late {}+        foreach tclIface [GetAllTclIfaces {purposes readXdc}] {+            namespace upvar ${tclIface} order order+            lappend $order $tclIface+        }++        if {{early} in $orders} {+            foreach tclIface $early {+                ReadManagedXdc $tclIface+            }+        }+        if {{normal} in $orders} {+            ReadUnmanagedXdc+            foreach tclIface $normal {+                ReadManagedXdc $tclIface+            }+        }+        if {{late} in $orders} {+            foreach tclIface $late {+                ReadManagedXdc $tclIface+            }+        }+        return+    }++    # Invoke all Clash-generated Tcl interfaces that specify a "createIp"+    # purpose, which will call Vivado's "create_ip" with any additional+    # arguments passed to this function (hint: "createIp -dir yourdir" will+    # create the IP in the subdirectory named "yourdir"). Following that, the+    # IP is configured.+    #+    # Also see "createAndReadIp" below; call it or use its code as+    # inspiration. It is suggested to call it like "createAndReadIp -dir ip"+    # so you keep the files in a separate directory named "ip". The directory+    # will need to exist already.+    proc createIp args {+        CheckMetadataExists+        # Identical names means identical IP, only one run needed even if it+        # occurs in multiple HDL directories.+        set seen {}+        foreach tclIface [GetAllTclIfaces {purposes createIp}] {+            namespace upvar ${tclIface} ipName ipName+            if {$ipName in $seen} {+                continue+            }+            PerformAction -var tclIface {::createIp } -var ipName { } \+                    -varexpand args+            LogProc 3 {    } ${tclIface}::createIp+            lappend seen $ipName+        }+        return $seen+    }++    # Convenience method to create the IP in a temporary in-memory project and+    # then read in the results in non-project mode. Finally, targets are+    # created for the IP.+    #+    # NOTE WELL: since this switches into and out of project mode, it should+    # probably be the very first thing you call in setting up the design.+    proc createAndReadIp args {+        CheckMetadataExists+        if {![llength [GetAllTclIfaces {purposes createIp}]]} {+            return+        }+        PerformAction {+            create_project -in_memory+        }+        set ips [createIp {*}$args]+        PerformAction {+            set ipFiles [get_property IP_FILE [get_ips } -var ips {]]+            close_project+            read_ip $ipFiles+            set_property GENERATE_SYNTH_CHECKPOINT false [get_files $ipFiles]+            generate_target {synthesis simulation} [get_ips } -var ips {]+        }+        return+    }++    #---------------------------------------------------------------------------+    # Private definitions+    #---------------------------------------------------------------------------++    proc Log {level msg} {+        variable verbosity++        if {$verbosity >= $level} {+            puts "Clash \[$level\]: $msg"+        }+        return+    }++    proc LogDry {level msg} {+        variable dryRun++        if {$dryRun} {+            puts "Clash \[$level\]: \[DRY-RUN\] $msg"+        } else {+            Log $level $msg+        }+        return+    }++    # Remove leading and trailing lines with just spaces+    proc TrimLines msg {+        return [regsub {^( *\n)*(.*?)\n?( *\n?)*$} $msg {\2}]+    }++    proc GetCommonIndent msg {+        set indent -1+        foreach line [split $msg \n] {+            regexp -indices {^ *} $line blanks+            if {[lindex $blanks 1] == [string length $line] - 1} {+                # Empty line or line of all blanks; ignore+                continue+            }+            set leader [expr {[lindex $blanks 1] - [lindex $blanks 0] + 1}]+            if {$indent < 0 || $leader < $indent} {+                set indent $leader+            }+        }+        if {$indent < 0} {+            return 0+        }+        return $indent+    }++    proc LogProc {level leader procName} {+        Log $level "${leader}proc [namespace tail $procName]\+                {[info args $procName]} \{"+        set body [TrimLines [info body $procName]]+        set outdent [GetCommonIndent $body]+        foreach line [split $body \n] {+            Log $level "$leader    [string range $line $outdent end]"+        }+        Log $level $leader\}+        return+    }++    proc PerformAction args {+        variable dryRun++        set action {}+        set trace {}+        set argsLen [llength $args]+        for {set i 0} {$i < $argsLen} {incr i} {+            set fragment [lindex $args $i]+            if {$fragment ni {-var -varexpand}} {+                set action $action$fragment+                set trace $trace$fragment+                continue+            }+            incr i+            if {$i == $argsLen} {+                error "Error: $fragment requires an argument"+            }+            set varName [lindex $args $i]+            upvar $varName var+            switch $fragment {+                -var {+                    set action "$action\${$varName}"+                    set trace $trace$var+                }+                -varexpand {+                    set action "$action{*}\${$varName}"+                    set trace $trace$var+                }+            }+        }+        set trace [TrimLines $trace]+        set outdent [GetCommonIndent $trace]+        foreach line [split $trace \n] {+            LogDry 2 [string range $line $outdent end]+        }+        if {$dryRun} {+            return+        }+        catch {+            uplevel 1 $action+        } msg opts+        dict incr opts -level+        return {*}$opts $msg+    }++    proc WriteIntVar {def gname name1 _name2 _op} {+        upvar $name1 var+        if {![string is integer -strict $var]} {+            set var $def+            error "Error: $gname: Only integer values are accepted;\+                    reset to default: $def"+        }+        return+    }++    proc WriteBoolVar {def gname name1 _name2 _op} {+        upvar $name1 var+        if {![string is boolean -strict $var]} {+            set var $def+            error "Error: $gname: Only {0 1 false true no yes off on} are\+                    accepted; reset to default: $def"+        }+        return+    }++    proc TraceWrite {varName cmd args} {+        set ns [namespace current]+        set commandPrefix [linsert $args 0 ${ns}::$cmd]+        lappend commandPrefix ${ns}::$varName+        uplevel 1 [list trace remove variable $varName write $commandPrefix]+        uplevel 1 [list trace add variable $varName write $commandPrefix]+        return+    }++    proc CheckMetadataExists {} {+        variable metadata+        if {![dict size $metadata]} {+            error "Error: Please invoke clash::readMetadata first."+        }+        return+    }++    proc GetNsVar {ns varName} {+        if {![llength [uplevel 1 [list info vars ${ns}::$varName]]]} {+            error "Error: $ns doesn't provide \"$varName\"\+                    variable."+        }+        return [uplevel 1 [list set ${ns}::$varName]]+    }++    proc ParseManifest {entityDir withDeps} {+        variable metadata++        set manC [open [file join $entityDir clash-manifest.json] r]+        set manifest [json::json2dict [read $manC]]+        close $manC+        set lib [dict get $manifest top_component name]+        Log 1 "New top component: $lib"+        # Clash sometimes lists files multiple times, process them only once+        set seen {}+        set topConstraintName [file join $entityDir "${lib}.sdc"]+        dict set metadata $lib hdlFiles {}+        dict set metadata $lib constraintFiles {}+        foreach fileEntry [dict get $manifest files] {+            set name [file join $entityDir [dict get $fileEntry name]]+            if {$name in $seen} {+                continue+            }+            lappend seen $name+            if {$name eq $topConstraintName} {+                dict set metadata $lib topConstraintFile $name+            } elseif {+                   [string match {*.vhdl} $name]+                || [string match {*.v} $name]+                || [string match {*.sv} $name]+            } then {+                Log 3 "Adding HDL file: $name"+                dict with metadata $lib {+                    lappend hdlFiles $name+                }+            } elseif {+                   [string match {*.sdc} $name]+                || [string match {*.xdc} $name]+            } then {+                Log 3 "Adding constraint file: $name"+                dict with metadata $lib {+                    lappend constraintFiles $name+                }+            } elseif {[string match {*.clash.tcl} $name]} {+                Log 3 "Adding Clash<->Tcl API file: $name"+                LoadTclIface $lib $name+            }+        }+        RemoveManagedFiles $lib++        if {!$withDeps} {+            return $lib+        }++        set dependencies {}+        foreach dependency [dict get $manifest dependencies transitive] {+            set dependencyDir [file join [file dirname $entityDir] $dependency]+            lappend dependencies [ParseManifest $dependencyDir false]+        }+        dict set metadata $lib dependencies $dependencies+        return $lib+    }++    # Populate a namespace with a Clash-generated Tcl interface.+    # Namespace is clash::tclIface::${lib}::$baseName+    proc LoadTclIface {lib tclIfaceFile} {+        set fileName [file tail $tclIfaceFile]+        # Strip all extensions+        set baseName [string range $fileName 0 [string first . $fileName]-1]+        set tclIface [namespace current]::tclIface::${lib}::$baseName+        # Evaluate script code inside temporary throwaway namespace to+        # separate its code from ours and reduce the chance of accidentally+        # corrupting our code.+        namespace eval tmp {}+        set tmp::tclIfaceFile $tclIfaceFile+        set tmp::tclIface $tclIface+        namespace eval tmp {+            # -notrace is a Vivado specific option inhibiting the printing of+            # the script to stdout+            source -notrace $tclIfaceFile+        }+        if {![namespace exists $tclIface]} {+            error "Error: $tclIfaceFile did not create the requested namespace\+                    specified by the \$tclIface variable. The Tcl script does\+                    not conform to the defined Clash<->Tcl API."+        }+        namespace delete tmp+        VerifyTclIface $tclIface $tclIfaceFile true+        return+    }++    # Verify that the read interface file is strictly something we support.+    proc VerifyTclIface {tclIface tclIfaceFile isRoot} {+        set api [GetNsVar $tclIface api]+        if {$api ne {1}} {+            error "Error: $tclIface doesn't implement an API we support:\+                    api = \"$api\"."+        }+        set purpose [GetNsVar $tclIface scriptPurpose]+        Log 3 "  API level / purpose: $api/$purpose"+        if {$purpose eq {multipleScripts}} {+            if {!$isRoot} {+                error "Error: ${tclIface}::scriptPurpose = \"multipleScripts\",\+                        nested use not allowed."+            }+            if {![namespace exists ${tclIface}::multipleScripts]} {+                error "Error: ${tclIface}::multipleScripts does not exist."+            }+            set children [namespace children ${tclIface}::multipleScripts]+            if {![llength $children]} {+                error "Error: ${tclIface}::multipleScripts doesn't provide any\+                        scripts."+            }+            foreach child $children {+                if {[llength [info vars ${child}::api]]} {+                    error "Error: $child cannot specify api: it is specified by\+                            parent script."+                }+                set ${child}::api $api+                VerifyTclIface $child $tclIfaceFile false+            }++        } elseif {$purpose eq {createIp}} {+            Log 3 "    IP name: [GetNsVar $tclIface ipName]"+            # In Tcl, you can call procedures with a partial name. So an+            # invocation of "createIp" could call "createIpAlt" if+            # "createIp" did not exist. Let's be strict here to prevent+            # confusion: only accept the exact name "createIp".+            if {![llength [info procs ${tclIface}::createIp]]} {+                error "Error: $tclIface doesn't provide \"createIp\"\+                        procedure."+            }+            LogProc 4 {    } ${tclIface}::createIp++        } elseif {$purpose eq {readXdc}} {+            set order [GetNsVar $tclIface order]+            if {$order ni {early normal late}} {+                error "Error: ${tclIface}::order bogus value \"$order\"."+            }+            set usedIn [GetNsVar $tclIface usedIn]+            foreach stage $usedIn {+                if {$stage ni {synthesis implementation}} {+                    error "Error: ${tclIface}::usedIn bogus value \"$stage\"."+                }+            }+            set xdcFile [GetNsVar $tclIface xdcFile]+            # "file join" also correctly handles an absolute $xdcFile+            set resolvedFile [file join [file dirname $tclIfaceFile] $xdcFile]+            # "file isfile" also positively matches a symlink to a regular+            # file+            if {![file isfile $resolvedFile]} {+                error "Error: ${tclIface}::xdcFile = \"$xdcFile\" does not\+                        refer to an existing file."+            }+            set ${tclIface}::xdcFile $resolvedFile+            Log 3 "    Constraint file: $resolvedFile"+            Log 4 "    Order: $order"+            if {[llength [info vars ${tclIface}::scopeRef]]} {+                namespace upvar ${tclIface} scopeRef scopeRef+                Log 4 "    Scoped to ref: $scopeRef"+            }+            Log 4 "    Used in: $usedIn"++        } else {+            error "Error: ${tclIface}::scriptPurpose bogus value \"$purpose\"."+        }+        return+    }++    # Remove constraint files that are managed by a Tcl interface script from+    # the list of constraint files for the library.+    proc RemoveManagedFiles lib {+        variable metadata++        foreach tclIface [GetAllTclIfaces {libs $lib purposes readXdc}] {+            namespace upvar ${tclIface} xdcFile xdcFile+            set constraintFiles [dict get $metadata $lib constraintFiles]+            if {[lsearch -exact $constraintFiles $xdcFile] >= 0} {+                Log 3 "Marking as managed by the Clash<->Tcl API: $xdcFile"+                set filtered [lsearch -all -inline -exact -not \+                        $constraintFiles $xdcFile]+                dict set metadata $lib constraintFiles $filtered+            }+        }+        return+    }++    # Return all the Tcl interface namespaces+    #+    # They can optionally be filtered by specifying a list of libraries to+    # consider, a list of interface names to consider, or a list of script+    # purposes to consider. The sole argument of the function is a dictionary of+    # options, with the possible keys "libs", "ifaces" and "purposes".+    #+    # For example, if these two interfaces exist:+    #   - ::clash::tclIface::libA::ifaceX+    #   - ::clash::tclIface::libB::ifaceX+    #+    # Then "GetAllTclIfaces {libs libA}" would only return the first, but+    # "GetAllTclIfaces {ifaces ifaceX}" would return both since the interface+    # names both match.+    proc GetAllTclIfaces {{opts {}}} {+        if {![namespace exists tclIface]} {+            # There are no scripts+            return+        }++        if {[dict exists $opts libs]} {+            set walkLibs {}+            foreach lib [dict get $opts libs] {+                if {[namespace exists tclIface::$lib]} {+                    lappend walkLibs tclIface::$lib+                }+            }+        } else {+            set walkLibs [namespace children tclIface]+        }+        set tclIfaces {}+        set hasIfaces [dict exists $opts ifaces]+        if {$hasIfaces} {+            set ifaces [dict get $opts ifaces]+        }+        set hasPurposes [dict exists $opts purposes]+        if {$hasPurposes} {+            set purposes [dict get $opts purposes]+        }+        foreach libNs $walkLibs {+            foreach tclIface [namespace children $libNs] {+                if {$hasIfaces && [namespace tail $tclIface] ni $ifaces} {+                    continue+                }+                namespace upvar ${tclIface} scriptPurpose purpose+                if {$purpose ne {multipleScripts}} {+                    if {(!$hasPurposes) || $purpose in $purposes} {+                        lappend tclIfaces $tclIface+                    }+                    continue+                }+                set childIfaces \+                        [namespace children ${tclIface}::multipleScripts]+                foreach childIface $childIfaces {+                    namespace upvar ${childIface} scriptPurpose purpose+                    if {(!$hasPurposes) || $purpose in $purposes} {+                        lappend tclIfaces $childIface+                    }+                }+            }+        }+        return $tclIfaces+    }++    # If Clash generates constraint files without an accompanying tclIface, they+    # fall into two categories. Given $lib as the name of the top component in a+    # library, ${lib}.sdc contains the "create_clock" statements. We only read+    # that for the top entity. All other constraint files are passed to Vivado+    # as-is and should match on unique identifiers in the HDL, such that they+    # can be read for all libraries without worrying about `current_instance` or+    # similar scoping mechanisms.+    proc ReadUnmanagedXdc {} {+        variable metadata+        variable topEntity++        if {[dict exists $metadata $topEntity topConstraintFile]} {+            set topConstraintFile \+                    [dict get $metadata $topEntity topConstraintFile]+            PerformAction {+                read_xdc } -var topConstraintFile+        }+        set libs [dict get $metadata $topEntity dependencies]+        lappend libs $topEntity+        foreach lib $libs {+            set constraintFiles [dict get $metadata $lib constraintFiles]+            foreach constraintFile $constraintFiles {+                PerformAction {+                    read_xdc } -var constraintFile+            }+        }+    }++    proc ReadManagedXdc tclIface {+        namespace upvar $tclIface xdcFile xdcFile usedIn usedIn+        if {[llength [info vars ${tclIface}::scopeRef]]} {+            namespace upvar ${tclIface} scopeRef scopeRef+            set scopeRefArg [list -ref $scopeRef]+        } else {+            set scopeRefArg {}+        }+        PerformAction {+            read_xdc } -varexpand scopeRefArg { } -var xdcFile {+            set_property USED_IN } -var usedIn { [get_files } -var xdcFile {]+        }+        return+    }++    TraceWrite verbosity WriteIntVar 1+    TraceWrite dryRun WriteBoolVar false+}
prims/common/Clash_Explicit_Signal.primitives.yaml view
@@ -3,9 +3,22 @@     kind: Expression     type: |-       veryUnsafeSynchronizer-        :: Int                         -- ARG[0]-        -> Int                         -- ARG[1]-        -> Signal dom1 a               -- ARG[2]+        :: Either Int (Signal dom1 Int) -- ARG[0]+        -> Either Int (Signal dom2 Int) -- ARG[1]+        -> Signal dom1 a                -- ARG[2]         -> Signal dom2 a     template: ~ARG[2]+    workInfo: Never+- BlackBox:+    name: Clash.Explicit.Signal.unsafeSynchronizer+    kind: Expression+    type: |-+      unsafeSynchronizer+        :: ( KnownDomain dom1    -- ARG[0]+           , KnownDomain dom2 )  -- ARG[1]+        => Clock dom1            -- ARG[2]+        -> Clock dom2            -- ARG[3]+        -> Signal dom1 a         -- ARG[4]+        -> Signal dom2 a+    template: ~ARG[4]     workInfo: Never
prims/common/Clash_Intel_ClockGen.primitives.yaml view
@@ -1,5 +1,5 @@ - BlackBox:-    name: Clash.Intel.ClockGen.altpll+    name: Clash.Intel.ClockGen.unsafeAltpll     format: Haskell     includes:     - name: altpll@@ -10,7 +10,7 @@     templateFunction: Clash.Primitives.Intel.ClockGen.altpllTF     workInfo: Always - BlackBox:-    name: Clash.Intel.ClockGen.alteraPll+    name: Clash.Intel.ClockGen.unsafeAlteraPll     format: Haskell     includes:     - name: altera_pll
prims/common/Clash_Magic.primitives.yaml view
@@ -16,3 +16,9 @@ - Primitive:     name: Clash.Magic.setName     primType: Function+- BlackBox:+    name: Clash.Magic.SimOnly+    kind: Expression+    type: 'SimOnly :: a -> SimOnly a'+    template: ~ERRORO+    workInfo: Constant
prims/common/Clash_XException.primitives.yaml view
@@ -22,8 +22,7 @@ - BlackBox:     name: Clash.XException.deepseqX     kind: Expression-    type: 'deepseqX :: Undefined-      a => a -> b -> b'+    type: 'deepseqX :: NFDataX a => a -> b -> b'     template: ~ARG[2]     workInfo: Never - BlackBox:
+ prims/common/Clash_Xilinx_ClockGen.primitives.yaml view
@@ -0,0 +1,22 @@+- BlackBox:+    name: Clash.Xilinx.ClockGen.unsafeClockWizard+    kind: Declaration+    format: Haskell+    templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardTF+    includes:+      - name: clk_wiz+        extension: clash.tcl+        format: Haskell+        templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardTclTF+    workInfo: Always+- BlackBox:+    name: Clash.Xilinx.ClockGen.unsafeClockWizardDifferential+    kind: Declaration+    format: Haskell+    templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardDifferentialTF+    includes:+      - name: clk_wiz+        extension: clash.tcl+        format: Haskell+        templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardDifferentialTclTF+    workInfo: Always
prims/common/GHC_Prim.primitives.yaml view
@@ -18,20 +18,84 @@       Int# -> Int#'     template: ~ARG[0] + ~ARG[1] - BlackBox:+    name: GHC.Prim.plusInt8#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:+    name: GHC.Prim.plusInt16#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:+    name: GHC.Prim.plusInt32#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:+    name: GHC.Prim.plusInt64#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:     name: GHC.Prim.-#     kind: Expression     type: '(-#) :: Int# ->       Int# -> Int#'     template: ~ARG[0] - ~ARG[1] - BlackBox:+    name: GHC.Prim.subInt8#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subInt16#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subInt32#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subInt64#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:     name: GHC.Prim.plusWord#     kind: Expression     type: 'plusWord# :: Word#       -> Word# -> Word#'     template: ~ARG[0] + ~ARG[1] - BlackBox:+    name: GHC.Prim.plusWord8#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:+    name: GHC.Prim.plusWord16#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:+    name: GHC.Prim.plusWord32#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:+    name: GHC.Prim.plusWord64#+    kind: Expression+    template: ~ARG[0] + ~ARG[1]+- BlackBox:     name: GHC.Prim.minusWord#     kind: Expression     type: 'minusWord# :: Word#       -> Word# -> Word#'+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subWord8#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subWord16#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subWord32#+    kind: Expression+    template: ~ARG[0] - ~ARG[1]+- BlackBox:+    name: GHC.Prim.subWord64#+    kind: Expression     template: ~ARG[0] - ~ARG[1]
+ prims/common/GHC_Prim_Panic.primitives.yaml view
@@ -0,0 +1,7 @@+- BlackBox:+    name: GHC.Prim.Panic.absentError+    kind: Expression+    type: 'absentError ::+      Addr# -> a'+    template: ~ERRORO+    workInfo: Constant
prims/common/GHC_TypeNats.primitives.yaml view
@@ -7,6 +7,11 @@     workInfo: Never - Primitive:     name: GHC.TypeNats.someNatVal-    primType: Functions+    primType: Function     type: 'someNatVal :: Natural -> SomeNat'+    workInfo: Never+- Primitive:+    name: GHC.TypeNates.withSomeSNat+    primType: Function+    type: 'withSomeSNat :: forall rep (r :: TYPE rep). Natural -> (forall n. SNat n -> r) -> r'     workInfo: Never
prims/common/GHC_Types.primitives.yaml view
@@ -2,3 +2,17 @@     name: GHC.Types.MkCoercible     primType: Constructor     workInfo: Never+- BlackBox:+    name: GHC.Types.I#+    kind: Expression+    comment: Needed to make the evaluator handle this constructor strictly+    type: 'I# :: Int# -> Int'+    template: ~ARG[0]+    workInfo: Never+- BlackBox:+    name: GHC.Types.W#+    kind: Expression+    comment: Needed to make the evaluator handle this constructor strictly+    type: 'W# :: Word# -> Word'+    template: ~ARG[0]+    workInfo: Never
prims/commonverilog/Clash_Explicit_SimIO.primitives.yaml view
@@ -29,6 +29,7 @@     name: Clash.Explicit.SimIO.writeReg     kind: Declaration     renderVoid: RenderVoid+    outputUsage: Blocking     template: ~ARG[0] = ~ARG[1]; - BlackBox:     name: Clash.Explicit.SimIO.openFile@@ -51,6 +52,7 @@ - BlackBox:     name: Clash.Explicit.SimIO.getLine     kind: Declaration+    outputUsage: Blocking     template: ~RESULT = $fgets(~ARG[2],~ARG[1]); - BlackBox:     name: Clash.Explicit.SimIO.isEOF@@ -64,10 +66,12 @@ - BlackBox:     name: Clash.Explicit.SimIO.seek     kind: Declaration+    outputUsage: Blocking     template: ~RESULT = $fseek(~ARG[0],~ARG[1],~ARG[2]); - BlackBox:     name: Clash.Explicit.SimIO.rewind     kind: Declaration+    outputUsage: Blocking     template: ~RESULT = $rewind(~ARG[0]); - BlackBox:     name: Clash.Explicit.SimIO.tell
prims/commonverilog/Clash_Explicit_Testbench.primitives.yaml view
@@ -5,3 +5,7 @@       Enable dom'     template: assign ~RESULT = 1'b1;     workInfo: Always+- BlackBox:+    name: Clash.Explicit.Testbench.clockToDiffClock+    kind: Expression+    template: '{~ARG[1], ~ ~ARG[1]}'
prims/commonverilog/Clash_Signal_Internal.primitives.yaml view
@@ -9,6 +9,6 @@     name: Clash.Signal.Internal.unsafeToReset     kind: Expression     type: 'unsafeToReset ::-      Signal dom Bool -> Reset dom'-    template: ~ARG[0]+      KnownDomain dom => Signal dom Bool -> Reset dom'+    template: ~ARG[1]     workInfo: Never
− prims/commonverilog/Clash_Xilinx_ClockGen.primitives.yaml
@@ -1,42 +0,0 @@-- BlackBox:-    name: Clash.Xilinx.ClockGen.clockWizard-    kind: Declaration-    type: |--      clockWizard-        :: ( KnownDomain domIn confIn       -- ARG[0]-           , KnownDomain domOut confOut )   -- ARG[1]-        => SSymbol name                    -- ARG[2]-        -> Clock  pllIn                    -- ARG[3]-        -> Reset pllIn                     -- ARG[4]-        -> (Clock pllOut, Enable pllOut)-    template: |--      // clockWizard begin-      ~NAME[2] ~GENSYM[clockWizard_inst][2]-      (.CLK_IN1  (~ARG[3])-      ,.RESET    (~IF ~ISACTIVEHIGH[0] ~THEN ~ELSE ! ~FI ~ARG[4])-      ,.CLK_OUT1 (~RESULT[1])-      ,.LOCKED   (~RESULT[0]));-      // clockWizard end-    workInfo: Always-- BlackBox:-    name: Clash.Xilinx.ClockGen.clockWizardDifferential-    kind: Declaration-    type: |--      clockWizardDifferential-        :: ( KnownDomain domIn confIn       -- ARG[0]-           , KnownDomain domOut confOut )   -- ARG[1]-        :: SSymbol name                    -- ARG[2]-        -> Clock  pllIn                    -- ARG[3]-        -> Clock  pllIn                    -- ARG[4]-        -> Reset pllIn                     -- ARG[5]-        -> (Clock pllOut, Enable pllOut)-    template: |--      // clockWizardDifferential begin-      ~NAME[2] ~GENSYM[clockWizardDifferential_inst][2]-      (.CLK_IN1_D_clk_n (~ARG[3])-      ,.CLK_IN1_D_clk_n (~ARG[4])-      ,.RESET           (~IF ~ISACTIVEHIGH[0] ~THEN ~ELSE ! ~FI ~ARG[5])-      ,.CLK_OUT1        (~RESULT[1])-      ,.LOCKED          (~RESULT[0]));-      // clockWizardDifferential end-    workInfo: Always
prims/commonverilog/GHC_Num_Integer.primitives.yaml view
@@ -173,6 +173,14 @@       but fixed-length after synthesis. Use carefully.'     workInfo: Never - BlackBox:+    name: GHC.Num.Integer.integerToInt64#+    kind: Expression+    type: 'integerToInt64#:: Integer -> Int64#'+    template: ~ARG[0]+    warning: 'GHC.Num.Integer.integerToInt64#: Integers are dynamically sized in+      simulation, but fixed-length after synthesis. Use carefully.'+    workInfo: Never+- BlackBox:     name: GHC.Num.Integer.integerToWord64#     comment: only used by 32 bit GHC     kind: Declaration@@ -183,6 +191,14 @@       simulation, but fixed-length after synthesis. Use carefully.'     workInfo: Never - BlackBox:+    name: GHC.Num.Integer.integerFromWord64#+    kind: Declaration+    type: 'integerFromWord64# :: Word64# -> Integer'+    template: assign ~RESULT = $signed(~ARG[0]);+    warning: 'GHC.Num.Integer.integerFromWord64#: Integers are dynamically sized in+      simulation, but fixed-length after synthesis. Use carefully.'+    workInfo: Never+- BlackBox:     name: GHC.Num.Integer.integerBit#     kind: Expression     type: 'integerBit# ::@@ -279,3 +295,12 @@     template: ~ARG[0] / ~ARG[1]     warning: 'GHC.Num.Integer.integerQuot: Integers are dynamically sized in simulation,       but fixed-length after synthesis. Use carefully.'+- BlackBox:+    name: GHC.Num.Integer.$wintegerFromInt64#+    kind: Declaration+    type: '$wintegerFromInt64# :: Int64# -> Int#'+    template: |-+      // wintegerFromInt64 begin+      assign ~RESULT = ~ARG[0];+      // wintegerFromInt64 end+    workInfo: Never
prims/commonverilog/GHC_Prim.primitives.yaml view
@@ -432,3 +432,619 @@     type: 'quotWord# :: Word#       -> Word# -> Word#'     template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.int8ToInt#+    kind: Declaration+    template: |-+      // int8ToInt begin+      assign ~RESULT = ~ARG[0];+      // int8ToInt end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt8#+    kind: Declaration+    template: |-+      // intToInt8 begin+      assign ~RESULT = ~ARG[0];+      // intToInt8 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt8#+    kind: Expression+    template: -(~ARG[0])+- BlackBox:+    name: GHC.Prim.timesInt8#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotInt8#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remInt8#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLInt8#+    kind: Expression+    template: ~ARG[0] <<< ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRAInt8#+    kind: Expression+    template: ~ARG[0] >>> ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLInt8#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.int8ToWord8#+    kind: Expression+    template: $unsigned(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt8#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geInt8#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtInt8#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leInt8#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltInt8#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neInt8#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.word8ToWord#+    kind: Declaration+    template: |-+      // word8ToWord begin+      assign ~RESULT = ~ARG[0];+      // word8ToWord end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord8#+    kind: Declaration+    template: |-+      // wordToWord8 begin+      assign ~RESULT = ~ARG[0];+      // wordToWord8 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord8#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotWord8#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remWord8#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.andWord8#+    kind: Expression+    template: ~ARG[0] & ~ARG[1]+- BlackBox:+    name: GHC.Prim.orWord8#+    kind: Expression+    template: ~ARG[0] | ~ARG[1]+- BlackBox:+    name: GHC.Prim.xorWord8#+    kind: Expression+    template: ~ARG[0] ^ ~ARG[1]+- BlackBox:+    name: GHC.Prim.notWord8#+    kind: Expression+    template: ~ ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLWord8#+    kind: Expression+    template: ~ARG[0] << ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLWord8#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.word8ToInt8#+    kind: Expression+    template: $signed(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord8#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geWord8#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtWord8#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leWord8#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltWord8#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neWord8#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.int16ToInt#+    kind: Declaration+    template: |-+      // int16ToInt begin+      assign ~RESULT = ~ARG[0];+      // int16ToInt end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt16#+    kind: Declaration+    template: |-+      // intToInt16 begin+      assign ~RESULT = ~ARG[0];+      // intToInt16 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt16#+    kind: Expression+    template: -(~ARG[0])+- BlackBox:+    name: GHC.Prim.timesInt16#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotInt16#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remInt16#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLInt16#+    kind: Expression+    template: ~ARG[0] <<< ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRAInt16#+    kind: Expression+    template: ~ARG[0] >>> ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLInt16#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.int16ToWord16#+    kind: Expression+    template: $unsigned(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt16#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geInt16#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtInt16#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leInt16#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltInt16#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neInt16#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.word16ToWord#+    kind: Declaration+    template: |-+      // word16ToWord begin+      assign ~RESULT = ~ARG[0];+      // word16ToWord end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord16#+    kind: Declaration+    template: |-+      // wordToWord16 begin+      assign ~RESULT = ~ARG[0];+      // wordToWord16 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord16#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotWord16#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remWord16#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.andWord16#+    kind: Expression+    template: ~ARG[0] & ~ARG[1]+- BlackBox:+    name: GHC.Prim.orWord16#+    kind: Expression+    template: ~ARG[0] | ~ARG[1]+- BlackBox:+    name: GHC.Prim.xorWord16#+    kind: Expression+    template: ~ARG[0] ^ ~ARG[1]+- BlackBox:+    name: GHC.Prim.notWord16#+    kind: Expression+    template: ~ ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLWord16#+    kind: Expression+    template: ~ARG[0] << ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLWord16#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.word16ToInt16#+    kind: Expression+    template: $signed(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord16#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geWord16#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtWord16#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leWord16#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltWord16#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neWord16#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.int32ToInt#+    kind: Declaration+    template: |-+      // int32ToInt begin+      assign ~RESULT = ~ARG[0];+      // int32ToInt end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt32#+    kind: Declaration+    template: |-+      // intToInt32 begin+      assign ~RESULT = ~ARG[0];+      // intToInt32 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt32#+    kind: Expression+    template: -(~ARG[0])+- BlackBox:+    name: GHC.Prim.timesInt32#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotInt32#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remInt32#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLInt32#+    kind: Expression+    template: ~ARG[0] <<< ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRAInt32#+    kind: Expression+    template: ~ARG[0] >>> ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLInt32#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.int32ToWord32#+    kind: Expression+    template: $unsigned(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt32#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geInt32#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtInt32#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leInt32#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltInt32#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neInt32#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.word32ToWord#+    kind: Declaration+    template: |-+      // word32ToWord begin+      assign ~RESULT = ~ARG[0];+      // word32ToWord end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord32#+    kind: Declaration+    template: |-+      // wordToWord32 begin+      assign ~RESULT = ~ARG[0];+      // wordToWord32 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord32#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotWord32#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remWord32#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.andWord32#+    kind: Expression+    template: ~ARG[0] & ~ARG[1]+- BlackBox:+    name: GHC.Prim.orWord32#+    kind: Expression+    template: ~ARG[0] | ~ARG[1]+- BlackBox:+    name: GHC.Prim.xorWord32#+    kind: Expression+    template: ~ARG[0] ^ ~ARG[1]+- BlackBox:+    name: GHC.Prim.notWord32#+    kind: Expression+    template: ~ ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLWord32#+    kind: Expression+    template: ~ARG[0] << ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLWord32#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.word32ToInt32#+    kind: Expression+    template: $signed(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord32#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geWord32#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtWord32#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leWord32#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltWord32#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neWord32#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.int64ToInt#+    kind: Declaration+    template: |-+      // int64ToInt begin+      assign ~RESULT = ~ARG[0];+      // int64ToInt end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt64#+    kind: Declaration+    template: |-+      // intToInt64 begin+      assign ~RESULT = ~ARG[0];+      // intToInt64 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt64#+    kind: Expression+    template: -(~ARG[0])+- BlackBox:+    name: GHC.Prim.timesInt64#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotInt64#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remInt64#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedIShiftL64#+    kind: Expression+    template: ~ARG[0] <<< ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedIShiftRA64#+    kind: Expression+    template: ~ARG[0] >>> ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedIShiftRL64#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.int64ToWord64#+    kind: Expression+    template: $unsigned(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt64#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geInt64#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtInt64#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leInt64#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltInt64#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neInt64#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.word64ToWord#+    kind: Declaration+    template: |-+      // word64ToWord begin+      assign ~RESULT = ~ARG[0];+      // word64ToWord end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord64#+    kind: Declaration+    template: |-+      // wordToWord64 begin+      assign ~RESULT = ~ARG[0];+      // wordToWord64 end+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord64#+    kind: Expression+    template: ~ARG[0] * ~ARG[1]+- BlackBox:+    name: GHC.Prim.quotWord64#+    kind: Expression+    template: ~ARG[0] / ~ARG[1]+- BlackBox:+    name: GHC.Prim.remWord64#+    kind: Expression+    template: ~ARG[0] % ~ARG[1]+- BlackBox:+    name: GHC.Prim.and64#+    kind: Expression+    template: ~ARG[0] & ~ARG[1]+- BlackBox:+    name: GHC.Prim.or64#+    kind: Expression+    template: ~ARG[0] | ~ARG[1]+- BlackBox:+    name: GHC.Prim.xor64#+    kind: Expression+    template: ~ARG[0] ^ ~ARG[1]+- BlackBox:+    name: GHC.Prim.not64#+    kind: Expression+    template: ~ ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftL64#+    kind: Expression+    template: ~ARG[0] << ~ARG[1]+- BlackBox:+    name: GHC.Prim.uncheckedShiftRL64#+    kind: Expression+    template: ~ARG[0] >> ~ARG[1]+- BlackBox:+    name: GHC.Prim.word64ToInt64#+    kind: Expression+    template: $signed(~ARG[0])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord64#+    kind: Expression+    template: "(~ARG[0] == ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.geWord64#+    kind: Expression+    template: "(~ARG[0] >= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.gtWord64#+    kind: Expression+    template: "(~ARG[0] > ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.leWord64#+    kind: Expression+    template: "(~ARG[0] <= ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.ltWord64#+    kind: Expression+    template: "(~ARG[0] < ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"+- BlackBox:+    name: GHC.Prim.neWord64#+    kind: Expression+    template: "(~ARG[0] != ~ARG[1]) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0"
prims/systemverilog/Clash_Explicit_BlockRam.primitives.yaml view
@@ -5,7 +5,7 @@       blockRam#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> Vec n a         -- init, ARG[5]@@ -50,7 +50,7 @@       blockRamU#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> SNat n          -- len,  ARG[5]@@ -92,7 +92,7 @@       blockRam1#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> SNat n          -- len,  ARG[5]@@ -131,60 +131,3 @@       end~FI       assign ~RESULT = ~FROMBV[~SYM[2]][~TYP[10]];       // blockRam1 end-- BlackBox:-    name: Clash.Explicit.BlockRam.trueDualPortBlockRam#-    kind: Declaration-    type: |--      trueDualPortBlockRam# ::-        forall nAddrs domA domB a .-        ( HasCallStack           ~ARG[0]-        , KnownNat nAddrs        ~ARG[1]-        , KnownDomain domA       ~ARG[2]-        , KnownDomain domB       ~ARG[3]-        , NFDataX a              ~ARG[4]-        ) =>--        Clock domA ->                   ~ARG[5]-        Signal domA Bool ->             ~ARG[6]-        Signal domA Bool ->             ~ARG[7]-        Signal domA (Index nAddrs) ->   ~ARG[8]-        Signal domA a ->                ~ARG[9]--        Clock domB ->                   ~ARG[10]-        Signal domB Bool ->             ~ARG[11]-        Signal domB Bool ->             ~ARG[12]-        Signal domB (Index nAddrs) ->   ~ARG[13]-        Signal domB a ->                ~ARG[14]-        (Signal domA a, Signal domB a)-    template: |--      // trueDualPortBlockRam begin-      // Shared memory-      logic [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0];--      ~SIGD[~GENSYM[data_slow][1]][9];-      ~SIGD[~GENSYM[data_fast][2]][14];--      // Port A-      always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin-          if(~ARG[6]) begin-              ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI];-              if(~ARG[7]) begin-                  ~SYM[1] <= ~ARG[9];-                  ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9];-              end-          end-      end--      // Port B-      always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin-          if(~ARG[11]) begin-              ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI];-              if(~ARG[12]) begin-                  ~SYM[2] <= ~ARG[14];-                  ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14];-              end-          end-      end--      assign ~RESULT = {~SYM[1], ~SYM[2]};-      // end trueDualPortBlockRam
prims/systemverilog/Clash_Explicit_DDR.primitives.yaml view
@@ -4,7 +4,7 @@     type: |-       ddrIn# :: forall a slow fast n pFast gated synchronous.                  ( HasCallStack          -- ARG[0]-                 , Undefined a           -- ARG[1]+                 , NFDataX a             -- ARG[1]                  , KnownConfi~ fast domf -- ARG[2]                  , KnownConfi~ slow doms -- ARG[3]               => Clock slow              -- ARG[4], clk@@ -47,9 +47,10 @@ - BlackBox:     name: Clash.Explicit.DDR.ddrOut#     kind: Declaration+    outputUsage: Blocking     type: |--      ddrOut# :: ( HasCallStack               -- ARG[0]-                  , Undefined a                -- ARG[1]+      ddrOut# :: ( HasCallStack                -- ARG[0]+                  , NFDataX a                  -- ARG[1]                   , KnownConfi~ fast domf      -- ARG[2]                   , KnownConfi~ slow doms      -- ARG[3]                => Clock slow                   -- ARG[4]
prims/systemverilog/Clash_Explicit_ROM.primitives.yaml view
@@ -4,7 +4,7 @@     type: |-       rom# :: ( KnownDomain dom        ARG[0]                , KnownNat n    --       ARG[1]-               , Undefined a ) --       ARG[2]+               , NFDataX a )   --       ARG[2]             => Clock dom       -- clk,  ARG[3]             => Enable dom      -- en,   ARG[4]             -> Vec n a         -- init, ARG[5]
prims/systemverilog/Clash_Explicit_Testbench.primitives.yaml view
@@ -53,66 +53,4 @@       // pragma translate_on       assign ~RESULT = ~ARG[7];       // assertBitVector end-- BlackBox:-    name: Clash.Explicit.Testbench.tbClockGen-    kind: Declaration-    type: |--      tbClockGen-        :: KnownDomain dom     -- ARG[0]-        => Signal dom Bool      -- ARG[1]-        -> Clock dom-    template: |--      // tbClockGen begin-      // pragma translate_off-      // 1 = 0.1ps-      localparam ~GENSYM[half_period][0] = (~PERIOD[0]0 / 2);-      always begin-        ~RESULT = ~IF~ACTIVEEDGE[Rising][0]~THEN 0 ~ELSE 1 ~FI;-        `ifndef VERILATOR-        #~LONGESTPERIOD0 forever begin-          if (~ ~ARG[1]) begin-            $finish;-          end-          ~RESULT = ~ ~RESULT;-          #~SYM[0];-          ~RESULT = ~ ~RESULT;-          #~SYM[0];-        end-        `else-        ~RESULT = $c("this->~GENSYM[tb_clock_gen][1](",~SYM[0],",~IF~ACTIVEEDGE[Rising][0]~THENtrue~ELSEfalse~FI,",(~ ~ARG[1]),")");-        `endif-      end -      `ifdef VERILATOR-        `systemc_interface-        CData ~SYM[1](vluint32_t half_period, bool active_rising, bool result_rec) {-          static vluint32_t init_wait = ~LONGESTPERIOD0;-          static vluint32_t to_wait = 0;-          static CData clock = active_rising ? 0 : 1;--          if(init_wait == 0) {-            if(result_rec) {-              std::exit(0);-            }-            else {-              if(to_wait == 0) {-                to_wait = half_period - 1;-                clock = clock == 0 ? 1 : 0;-              }-              else {-                to_wait = to_wait - 1;-              }-            }-          }-          else {-            init_wait = init_wait - 1;-          }--          return clock;-        }-        `verilog-      `endif-      // pragma translate_on-      // tbClockGen end-    warning: Clash.Signal.Internal.tbClockGen is not synthesizable!-    workInfo: Always
prims/systemverilog/Clash_Prelude_ROM.primitives.yaml view
@@ -2,14 +2,16 @@     name: Clash.Prelude.ROM.asyncRom#     kind: Declaration     type: |--      asyncRom# :: KnownNat n -- ^ ARG[0]-                 => Vec n a    -- ^ ARG[1]-                 -> Int        -- ^ ARG[2]-                 -> a+      asyncRom#+        :: ( KnownNat n  -- ARG[0]+           , NFDataX a)  -- ARG[1]+        => Vec n a       -- ARG[2]+        -> Int           -- ARG[3]+        -> a     template: |-       // asyncRom begin-      ~SIGD[~GENSYM[ROM][0]][1];-      assign ~SYM[0] = ~CONST[1];+      ~SIGD[~GENSYM[ROM][0]][2];+      assign ~SYM[0] = ~CONST[2]; -      assign ~RESULT = ~FROMBV[~SYM[0][\~ARG[2]\]][~TYPO];+      assign ~RESULT = ~FROMBV[~SYM[0][\~ARG[3]\]][~TYPO];       // asyncRom end
prims/systemverilog/Clash_Signal_Internal.primitives.yaml view
@@ -1,10 +1,11 @@ - BlackBox:     name: Clash.Signal.Internal.delay#     kind: Declaration+    outputUsage: NonBlocking     type: |-       delay#         :: ( KnownDomain dom        -- ARG[0]-           , Undefined a )          -- ARG[1]+           , NFDataX a )            -- ARG[1]         => Clock dom                -- ARG[2]         -> Enable dom               -- ARG[3]         -> a                        -- ARG[4]@@ -28,6 +29,7 @@ - BlackBox:     name: Clash.Signal.Internal.asyncRegister#     kind: Declaration+    outputUsage: NonBlocking     type: |-       asyncRegister#         :: ( KnownDomain dom        -- ARG[0]@@ -56,10 +58,11 @@ - BlackBox:     name: Clash.Signal.Internal.register#     kind: Declaration+    outputUsage: NonBlocking     type: |-       register#         :: ( KnownDomain dom        -- ARG[0]-           , Undefined a )          -- ARG[1]+           , NFDataX a )            -- ARG[1]         => Clock dom                -- ARG[2]         -> Reset dom                -- ARG[3]         -> Enable dom               -- ARG[4]@@ -82,14 +85,16 @@       end       // register end - BlackBox:-    name: Clash.Signal.Internal.clockGen+    name: Clash.Signal.Internal.tbClockGen     kind: Declaration+    outputUsage: Blocking     type: |--      clockGen+      tbClockGen         :: KnownDomain dom     -- ARG[0]-        => Clock dom+        => Signal dom Bool     -- ARG[1]+        -> Clock dom     template: |--      // clockGen begin+      // tbClockGen begin       // pragma translate_off       // 1 = 0.1ps       localparam ~GENSYM[half_period][0] = (~PERIOD[0]0 / 2);@@ -97,30 +102,40 @@         ~RESULT = ~IF~ACTIVEEDGE[Rising][0]~THEN 0 ~ELSE 1 ~FI;         `ifndef VERILATOR         #~LONGESTPERIOD0 forever begin+          ~IF~ISACTIVEENABLE[1]~THEN+          if (~ ~ARG[1]) begin+            $finish;+          end+          ~ELSE~FI           ~RESULT = ~ ~RESULT;           #~SYM[0];           ~RESULT = ~ ~RESULT;           #~SYM[0];         end         `else-        ~RESULT = $c("this->~GENSYM[tb_clock_gen][1](",~SYM[0],",~IF~ACTIVEEDGE[Rising][0]~THENtrue~ELSEfalse~FI)");+        ~RESULT = $c("this->~GENSYM[tb_clock_gen][1](",~SYM[0],",~IF~ACTIVEEDGE[Rising][0]~THENtrue~ELSEfalse~FI,",(~ ~ARG[1]),")");         `endif       end        `ifdef VERILATOR         `systemc_interface-        CData ~SYM[1](vluint32_t half_period, bool active_rising) {+        CData ~SYM[1](vluint32_t half_period, bool active_rising, bool result_rec) {           static vluint32_t init_wait = ~LONGESTPERIOD0;           static vluint32_t to_wait = 0;           static CData clock = active_rising ? 0 : 1;            if(init_wait == 0) {-            if(to_wait == 0) {-              to_wait = half_period - 1;-              clock = clock == 0 ? 1 : 0;+            if(result_rec) {+              std::exit(0);             }             else {-              to_wait = to_wait - 1;+              if(to_wait == 0) {+                to_wait = half_period - 1;+                clock = clock == 0 ? 1 : 0;+              }+              else {+                to_wait = to_wait - 1;+              }             }           }           else {@@ -131,14 +146,50 @@         }         `verilog       `endif+      // pragma translate_on+      // tbClockGen end+    warning: Clash.Signal.Internal.tbClockGen is not synthesizable!+    workInfo: Always+- BlackBox:+    name: Clash.Signal.Internal.tbDynamicClockGen+    kind: Declaration+    outputUsage: Blocking+    type: |-+      tbDynamicClockGen+        :: KnownDomain dom     -- ARG[0]+        -> Signal dom Natural  -- ARG[1]+        -> Signal dom Bool     -- ARG[2]+        => Clock dom+    template: |-+      // tbDynamicClockGen begin+      // pragma translate_off+      // 1 = 0.1ps+      time ~GENSYM[half_period][0];+      always begin+        ~RESULT = ~IF~ACTIVEEDGE[Rising][0]~THEN 0 ~ELSE 1 ~FI;+        #~LONGESTPERIOD0 forever begin+          ~IF~ISACTIVEENABLE[2]~THEN+          if (~ ~ARG[2]) begin+            $finish;+          end+          ~ELSE~FI+          // 1 = 0.1ps+          ~SYM[0] = (~VAR[periods][1] / 2); +          ~RESULT = ~ ~RESULT;+          #(~SYM[0] * 0.01);+          ~RESULT = ~ ~RESULT;+          #(~SYM[0] * 0.01);+        end+      end       // pragma translate_on-      // clockGen end-    warning: Clash.Signal.Internal.clockGen is not synthesizable!+      // tbDynamicClockGen end+    warning: Clash.Signal.Internal.tbDynamicClockGen is not synthesizable!     workInfo: Always - BlackBox:     name: Clash.Signal.Internal.resetGenN     kind: Declaration+    outputUsage: Blocking     type: 'resetGenN :: (KnownDomain       dom, 1 <= n) => SNat n -> Reset dom'     template: |-@@ -180,4 +231,5 @@       `endif       // pragma translate_on       // resetGen end+    warning: Clash.Signal.Internal.resetGenN can not be synthesized to hardware!     workInfo: Always
prims/systemverilog/Clash_Sized_Internal_BitVector.primitives.yaml view
@@ -1,6 +1,7 @@ - BlackBox:     name: Clash.Sized.Internal.BitVector.replaceBit#     kind: Declaration+    outputUsage: Blocking     type: |-       replaceBit# :: KnownNat n  -- ARG[0]                    => BitVector n -- ARG[1]@@ -17,6 +18,7 @@ - BlackBox:     name: Clash.Sized.Internal.BitVector.setSlice#     kind: Declaration+    outputUsage: Blocking     type: |-       setSlice# :: SNat (m + 1 + i)                  -> BitVector (m + 1 + i) -- ARG[1]
prims/systemverilog/Clash_Sized_Vector.primitives.yaml view
@@ -241,6 +241,7 @@ - BlackBox:     name: Clash.Sized.Vector.replace_int     kind: Declaration+    outputUsage: Blocking     type: 'replace_int ::       KnownNat n => Vec n a -> Int -> a -> Vec n a'     template: |-
prims/systemverilog/GHC_Base.primitives.yaml view
@@ -5,12 +5,24 @@       Int -> Int'     template: |-       // divInt begin-      // divide (rounds towards zero)-      ~SIGD[~GENSYM[quot_res][0]][0];-      assign ~SYM[0] = ~VAR[dividend][0] / ~VAR[divider][1];+      logic ~GENSYM[resultPos][1];+      logic ~GENSYM[dividerNeg][2];+      logic signed [~SIZE[~TYPO]:0] ~GENSYM[dividend2][3];+      logic signed [~SIZE[~TYPO]:0] ~GENSYM[dividendE][4];+      logic signed [~SIZE[~TYPO]:0] ~GENSYM[dividerE][5];+      logic signed [~SIZE[~TYPO]:0] ~GENSYM[quot_res][6]; -      // round toward minus infinity-      assign ~RESULT = (~VAR[dividend][0][~SIZE[~TYPO]-1] == ~VAR[divider][1][~SIZE[~TYPO]-1]) ? ~SYM[0] : ~SYM[0] - ~SIZE[~TYPO]'sd1;+      assign ~SYM[1] = ~VAR[dividend][0][~SIZE[~TYPO]-1] == ~VAR[divider][1][~SIZE[~TYPO]-1];+      assign ~SYM[2] = ~VAR[divider][1][~SIZE[~TYPO]-1] == 1'b1;+      assign ~SYM[4] = $signed({{~VAR[dividend][0][~SIZE[~TYPO]-1]},~VAR[dividend][0]});  // sign extension+      assign ~SYM[5] = $signed({{~VAR[divider][1][~SIZE[~TYPO]-1]} ,~VAR[divider][1]} );  // sign extension++      assign ~SYM[3] = ~SYM[1] ? ~SYM[4]+                               : (~SYM[2] ? (~SYM[4] - ~SYM[5] - ~SIZE[~TYPO]'sd1)+                                          : (~SYM[4] - ~SYM[5] + ~SIZE[~TYPO]'sd1));++      assign ~SYM[6] = ~SYM[3] / ~SYM[5];+      assign ~RESULT = $signed(~SYM[6][~SIZE[~TYPO]-1:0]);       // divInt end - BlackBox:     name: GHC.Base.modInt
prims/systemverilog/GHC_Prim.primitives.yaml view
@@ -1424,3 +1424,87 @@       ~FI       assign ~RESULT = $unsigned(~SYM[7]);       // ctz end+- BlackBox:+    name: GHC.Prim.quotRemInt8#+    kind: Declaration+    type: 'quotRemInt8# ::+      Int8# -> Int8# -> (#Int8#, Int8##)'+    template: |-+      // quotRemInt8 begin+      ~SIGD[~GENSYM[quot_res][0]][0];+      ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemInt8 end+- BlackBox:+    name: GHC.Prim.quotRemWord8#+    kind: Declaration+    type: 'quotRemWord8# ::+      Word8# -> Word8# -> (#Word8#, Word8##)'+    template: |-+      // quotRemWord8 begin+      ~SIGD[~GENSYM[quot_res][0]][0];+      ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemWord8 end+- BlackBox:+    name: GHC.Prim.quotRemInt16#+    kind: Declaration+    type: 'quotRemInt16# ::+      Int16# -> Int16# -> (#Int16#, Int16##)'+    template: |-+      // quotRemInt16 begin+      ~SIGD[~GENSYM[quot_res][0]][0];+      ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemInt16 end+- BlackBox:+    name: GHC.Prim.quotRemWord16#+    kind: Declaration+    type: 'quotRemWord16# ::+      Word16# -> Word16# -> (#Word16#, Word16##)'+    template: |-+      // quotRemWord16 begin+      ~SIGD[~GENSYM[quot_res][0]][0];+      ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemWord16 end+- BlackBox:+    name: GHC.Prim.quotRemInt32#+    kind: Declaration+    type: 'quotRemInt32# ::+      Int32# -> Int32# -> (#Int32#, Int32##)'+    template: |-+      // quotRemInt32 begin+      ~SIGD[~GENSYM[quot_res][0]][0];+      ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemInt32 end+- BlackBox:+    name: GHC.Prim.quotRemWord32#+    kind: Declaration+    type: 'quotRemWord32# ::+      Word32# -> Word32# -> (#Word32#, Word32##)'+    template: |-+      // quotRemWord32 begin+      ~SIGD[~GENSYM[quot_res][0]][0];+      ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemWord32 end
prims/verilog/Clash_Explicit_BlockRam.primitives.yaml view
@@ -1,12 +1,12 @@ - BlackBox:     name: Clash.Explicit.BlockRam.blockRam#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       blockRam#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         => Enable dom      -- en,   ARG[4]         -> Vec n a         -- init, ARG[5]@@ -52,12 +52,12 @@ - BlackBox:     name: Clash.Explicit.BlockRam.blockRamU#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       blockRamU#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> SNat n          -- len,  ARG[5]@@ -95,12 +95,12 @@ - BlackBox:     name: Clash.Explicit.BlockRam.blockRam1#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       blockRam1#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> SNat n          -- len,  ARG[5]@@ -142,61 +142,3 @@         ~RESULT <= ~SYM[0][~ARG[7]];       end~FI       // blockRam1 end-- BlackBox:-    name: Clash.Explicit.BlockRam.trueDualPortBlockRam#-    kind: Declaration-    type: |--      trueDualPortBlockRam# ::-        forall nAddrs domA domB a .-        ( HasCallStack           ~ARG[0]-        , KnownNat nAddrs        ~ARG[1]-        , KnownDomain domA       ~ARG[2]-        , KnownDomain domB       ~ARG[3]-        , NFDataX a              ~ARG[4]-        ) =>--        Clock domA ->                   ~ARG[5]-        Signal domA Bool ->             ~ARG[6]-        Signal domA Bool ->             ~ARG[7]-        Signal domA (Index nAddrs) ->   ~ARG[8]-        Signal domA a ->                ~ARG[9]--        Clock domB ->                   ~ARG[10]-        Signal domB Bool ->             ~ARG[11]-        Signal domB Bool ->             ~ARG[12]-        Signal domB (Index nAddrs) ->   ~ARG[13]-        Signal domB a ->                ~ARG[14]-        (Signal domA a, Signal domB a)-    template: |--      // trueDualPortBlockRam begin-      // Shared memory-      reg [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0];--      reg ~SIGD[~GENSYM[data_slow][1]][9];-      reg ~SIGD[~GENSYM[data_fast][2]][14];--      // Port A-      always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin-          if(~ARG[6]) begin-              ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI];-              if(~ARG[7]) begin-                  ~SYM[1] <= ~ARG[9];-                  ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9];-              end-          end-      end--      // Port B-      always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin-          if(~ARG[11]) begin-              ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI];-              if(~ARG[12]) begin-                  ~SYM[2] <= ~ARG[14];-                  ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14];-              end-          end-      end--      assign ~RESULT = {~SYM[1], ~SYM[2]};--      // end trueDualPortBlockRam
prims/verilog/Clash_Explicit_BlockRam_Blob.primitives.yaml view
@@ -1,7 +1,7 @@ - BlackBox:     name: Clash.Explicit.BlockRam.Blob.blockRamBlob#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       blockRamBlob#         :: KnownDomain dom           --       ARG[0]
prims/verilog/Clash_Explicit_BlockRam_File.primitives.yaml view
@@ -1,7 +1,7 @@ - BlackBox:     name: Clash.Explicit.BlockRam.File.blockRamFile#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       blockRamFile#         :: ( KnownDomain dom         --       ARG[0]
prims/verilog/Clash_Explicit_DDR.primitives.yaml view
@@ -4,7 +4,7 @@     type: |-       ddrIn# :: forall a slow fast n pFast gated synchronous.                  ( HasCallStack          -- ARG[0]-                 , Undefined a           -- ARG[1]+                 , NFDataX a             -- ARG[1]                  , KnownConfi~ fast domf -- ARG[2]                  , KnownConfi~ slow doms -- ARG[3]               => Clock slow              -- ARG[4]@@ -48,8 +48,8 @@     name: Clash.Explicit.DDR.ddrOut#     kind: Declaration     type: |--      ddrOut# :: ( HasCallStack               -- ARG[0]-                  , Undefined a                -- ARG[1]+      ddrOut# :: ( HasCallStack                -- ARG[0]+                  , NFDataX a                  -- ARG[1]                   , KnownConfi~ fast domf      -- ARG[2]                   , KnownConfi~ slow doms      -- ARG[3]                => Clock slow                   -- ARG[4]@@ -63,6 +63,7 @@       // ddrOut begin       reg ~SIGD[~GENSYM[data_Pos][1]][7];       reg ~SIGD[~GENSYM[data_Neg][2]][7];+      ~IF ~VIVADO ~THENreg ~SIGDO[~GENSYM[ddrOut][3]];~ELSE~FI       always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[4]~IF~ISSYNC[3]~THEN)~ELSE or ~IF~ISACTIVEHIGH[2]~THENposedge~ELSEnegedge~FI ~ARG[5])~FI begin : ~GENSYM[~COMPNAME_ddrOut_pos][5]         if (~IF~ISACTIVEHIGH[2]~THEN~ARG[5]~ELSE! ~ARG[5]~FI) begin           ~SYM[1] <= ~ARG[7];@@ -78,6 +79,14 @@         end       end -      assign ~RESULT = ~ARG[4] ? ~IF~ACTIVEEDGE[Rising][2]~THEN~SYM[1] : ~SYM[2]~ELSE~SYM[2] : ~SYM[1]~FI;+      ~IF ~VIVADO ~THENalways @(*) begin+        if (~ARG[4]) begin+          ~SYM[3] = ~IF~ACTIVEEDGE[Rising][2]~THEN~SYM[1]~ELSE~SYM[2]~FI;+        end else begin+          ~SYM[3] = ~IF~ACTIVEEDGE[Rising][2]~THEN~SYM[2]~ELSE~SYM[1]~FI;+        end+      end+      assign ~RESULT = ~SYM[3];~ELSE+      assign ~RESULT = ~ARG[4] ? ~IF~ACTIVEEDGE[Rising][2]~THEN~SYM[1] : ~SYM[2]~ELSE~SYM[2] : ~SYM[1]~FI;~FI        // ddrOut end
prims/verilog/Clash_Explicit_ROM.primitives.yaml view
@@ -1,11 +1,11 @@ - BlackBox:     name: Clash.Explicit.ROM.rom#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       rom# :: ( KnownDomain dom        ARG[0]                , KnownNat n    --       ARG[1]-               , Undefined a ) --       ARG[2]+               , NFDataX a )   --       ARG[2]             => Clock dom       -- clk,  ARG[3]             -> Enable dom      -- en,   ARG[4]             -> Vec n a         -- init, ARG[5]
prims/verilog/Clash_Explicit_ROM_Blob.primitives.yaml view
@@ -1,7 +1,7 @@ - BlackBox:     name: Clash.Explicit.ROM.Blob.romBlob#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       romBlob#         :: KnownDomain dom  --       ARG[0]
prims/verilog/Clash_Explicit_ROM_File.primitives.yaml view
@@ -1,7 +1,7 @@ - BlackBox:     name: Clash.Explicit.ROM.File.romFile#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       romFile# :: ( KnownNat m             --       ARG[0]                    , KnownDomain dom      ) --       ARG[1]
prims/verilog/Clash_Explicit_Testbench.primitives.yaml view
@@ -53,70 +53,3 @@       // pragma translate_on       assign ~RESULT = ~ARG[7];       // assertBitVector end-- BlackBox:-    name: Clash.Explicit.Testbench.tbClockGen-    kind: Declaration-    type: |--      tbClockGen-        :: KnownDomain dom     -- ARG[0]-        => Signal dom Bool      -- ARG[1]-        -> Clock dom-    template: |--      // tbClockGen begin-      // pragma translate_off-      reg ~TYPO ~GENSYM[clk][0];-      // 1 = 0.1ps-      localparam ~GENSYM[half_period][1] = (~PERIOD[0]0 / 2);-      always begin-        // Delay of 1 mitigates race conditions (https://github.com/steveicarus/iverilog/issues/160)-        #1 ~SYM[0] = ~IF~ACTIVEEDGE[Rising][0]~THEN 0 ~ELSE 1 ~FI;-        `ifndef VERILATOR-        #~LONGESTPERIOD0 forever begin-          if (~ ~ARG[1]) begin-            $finish(0);-          end-          ~SYM[0] = ~ ~SYM[0];-          #~SYM[1];-          ~SYM[0] = ~ ~SYM[0];-          #~SYM[1];-        end-        `else-        ~SYM[0] = $c("this->~GENSYM[tb_clock_gen][2](",~SYM[1],",~IF~ACTIVEEDGE[Rising][0]~THENtrue~ELSEfalse~FI,",(~ ~ARG[1]),")");-        `endif-      end--      `ifdef VERILATOR-        `systemc_interface-        CData ~SYM[2](vluint32_t half_period, bool active_rising, bool result_rec) {-          static vluint32_t init_wait = ~LONGESTPERIOD0;-          static vluint32_t to_wait = 0;-          static CData clock = active_rising ? 0 : 1;--          if(init_wait == 0) {-            if(result_rec) {-              std::exit(0);-            }-            else {-              if(to_wait == 0) {-                to_wait = half_period - 1;-                clock = clock == 0 ? 1 : 0;-              }-              else {-                to_wait = to_wait - 1;-              }-            }-          }-          else {-            init_wait = init_wait - 1;-          }--          return clock;-        }-        `verilog-      `endif--      assign ~RESULT = ~SYM[0];-      // pragma translate_on-      // tbClockGen end-    warning: Clash.Signal.Internal.tbClockGen is not synthesizable!-    workInfo: Always
prims/verilog/Clash_Prelude_ROM.primitives.yaml view
@@ -2,16 +2,18 @@     name: Clash.Prelude.ROM.asyncRom#     kind: Declaration     type: |--      asyncRom# :: KnownNat n -- ^ ARG[0]-                 => Vec n a    -- ^ ARG[1]-                 -> Int        -- ^ ARG[2]-                 -> a+      asyncRom#+        :: ( KnownNat n  -- ARG[0]+           , NFDataX a)  -- ARG[1]+        => Vec n a       -- ARG[2]+        -> Int           -- ARG[3]+        -> a     template: |-       // asyncRom begin       wire ~TYPO ~GENSYM[ROM][0] [0:~LIT[0]-1]; -      wire ~TYP[1] ~GENSYM[romflat][1];-      assign ~SYM[1] = ~CONST[1];+      wire ~TYP[2] ~GENSYM[romflat][1];+      assign ~SYM[1] = ~CONST[2];       genvar ~GENSYM[i][2];       ~GENERATE       for (~SYM[2]=0; ~SYM[2] < ~LIT[0]; ~SYM[2]=~SYM[2]+1) begin : ~GENSYM[mk_array][3]@@ -19,5 +21,5 @@       end       ~ENDGENERATE -      assign ~RESULT = ~SYM[0][~ARG[2]];+      assign ~RESULT = ~SYM[0][~ARG[3]];       // asyncRom end
prims/verilog/Clash_Signal_Internal.primitives.yaml view
@@ -1,11 +1,11 @@ - BlackBox:     name: Clash.Signal.Internal.delay#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       delay#         :: ( KnownDomain dom        -- ARG[0]-           , Undefined a )          -- ARG[1]+           , NFDataX a )            -- ARG[1]         => Clock dom                -- ARG[2]         -> Enable dom               -- ARG[3]         -> a                        -- ARG[4]@@ -29,7 +29,7 @@ - BlackBox:     name: Clash.Signal.Internal.asyncRegister#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       asyncRegister#         :: ( KnownDomain dom        -- ARG[0]@@ -58,11 +58,11 @@ - BlackBox:     name: Clash.Signal.Internal.register#     kind: Declaration-    outputReg: true+    outputUsage: NonBlocking     type: |-       register#         :: ( KnownDomain dom        -- ARG[0]-           , Undefined a )          -- ARG[1]+           , NFDataX a )            -- ARG[1]         => Clock dom                -- ARG[2]         -> Reset dom                -- ARG[3]         -> Enable dom               -- ARG[4]@@ -85,14 +85,15 @@       end       // register end - BlackBox:-    name: Clash.Signal.Internal.clockGen+    name: Clash.Signal.Internal.tbClockGen     kind: Declaration     type: |--      clockGen+      tbClockGen         :: KnownDomain dom     -- ARG[0]-        => Clock dom+        => Signal dom Bool     -- ARG[1]+        -> Clock dom     template: |--      // clockGen begin+      // tbClockGen begin       // pragma translate_off       reg ~TYPO ~GENSYM[clk][0];       // 1 = 0.1ps@@ -102,30 +103,40 @@         #1 ~SYM[0] = ~IF~ACTIVEEDGE[Rising][0]~THEN 0 ~ELSE 1 ~FI;         `ifndef VERILATOR         #~LONGESTPERIOD0 forever begin+          ~IF~ISACTIVEENABLE[1]~THEN+          if (~ ~ARG[1]) begin+            $finish(0);+          end+          ~ELSE~FI           ~SYM[0] = ~ ~SYM[0];           #~SYM[1];           ~SYM[0] = ~ ~SYM[0];           #~SYM[1];         end         `else-        ~SYM[0] = $c("this->~GENSYM[tb_clock_gen][2](",~SYM[1],",~IF~ACTIVEEDGE[Rising][0]~THENtrue~ELSEfalse~FI)");+        ~SYM[0] = $c("this->~GENSYM[tb_clock_gen][2](",~SYM[1],",~IF~ACTIVEEDGE[Rising][0]~THENtrue~ELSEfalse~FI,",(~ ~ARG[1]),")");         `endif       end        `ifdef VERILATOR         `systemc_interface-        CData ~SYM[2](vluint32_t half_period, bool active_rising) {+        CData ~SYM[2](vluint32_t half_period, bool active_rising, bool result_rec) {           static vluint32_t init_wait = ~LONGESTPERIOD0;           static vluint32_t to_wait = 0;           static CData clock = active_rising ? 0 : 1;            if(init_wait == 0) {-            if(to_wait == 0) {-              to_wait = half_period - 1;-              clock = clock == 0 ? 1 : 0;+            if(result_rec) {+              std::exit(0);             }             else {-              to_wait = to_wait - 1;+              if(to_wait == 0) {+                to_wait = half_period - 1;+                clock = clock == 0 ? 1 : 0;+              }+              else {+                to_wait = to_wait - 1;+              }             }           }           else {@@ -139,8 +150,46 @@        assign ~RESULT = ~SYM[0];       // pragma translate_on-      // clockGen end-    warning: Clash.Signal.Internal.clockGen is not synthesizable!+      // tbClockGen end+    warning: Clash.Signal.Internal.tbClockGen is not synthesizable!+    workInfo: Always+- BlackBox:+    name: Clash.Signal.Internal.tbDynamicClockGen+    kind: Declaration+    type: |-+      clockGen+        :: KnownDomain dom     -- ARG[0]+        -> Signal dom Int64    -- ARG[1]+        -> Signal dom Bool     -- ARG[2]+        => Clock dom+    template: |-+      // tbDynamicClockGen begin+      // pragma translate_off+      reg ~TYPO ~GENSYM[clk][0];+      time ~GENSYM[half_period][1];+      always begin+        // Delay of 1 mitigates race conditions (https://github.com/steveicarus/iverilog/issues/160)+        #1 ~SYM[0] = ~IF~ACTIVEEDGE[Rising][0]~THEN 0 ~ELSE 1 ~FI;+        #~LONGESTPERIOD0 forever begin+          ~IF~ISACTIVEENABLE[2]~THEN+          if (~ ~ARG[2]) begin+            $finish(0);+          end+          ~ELSE~FI+          // 1 = 0.1ps+          ~SYM[1] = (~VAR[periods][1] / 2);++          ~SYM[0] = ~ ~SYM[0];+          #(~SYM[1] * 0.01);+          ~SYM[0] = ~ ~SYM[0];+          #(~SYM[1] * 0.01);+        end+      end++      assign ~RESULT = ~SYM[0];+      // pragma translate_on+      // tbDynamicClockGen end+    warning: Clash.Signal.Internal.tbDynamicClockGen is not synthesizable!     workInfo: Always - BlackBox:     name: Clash.Signal.Internal.resetGenN
prims/verilog/Clash_Sized_Internal_BitVector.primitives.yaml view
@@ -1,7 +1,7 @@ - BlackBox:     name: Clash.Sized.Internal.BitVector.replaceBit#     kind: Declaration-    outputReg: true+    outputUsage: Blocking     type: |-       replaceBit# :: KnownNat n  -- ARG[0]                    => BitVector n -- ARG[1]@@ -18,7 +18,7 @@ - BlackBox:     name: Clash.Sized.Internal.BitVector.setSlice#     kind: Declaration-    outputReg: true+    outputUsage: Blocking     type: |-       setSlice# :: SNat (m + 1 + i)                  -> BitVector (m + 1 + i) -- ARG[1]
prims/verilog/Clash_Sized_Vector.primitives.yaml view
@@ -97,7 +97,7 @@       for (~SYM[1]=0; ~SYM[1] < ~LENGTH[~TYPO]; ~SYM[1] = ~SYM[1] + 1) begin : ~GENSYM[map][2]~IF~SIZE[~TYP[1]]~THEN         wire ~TYPEL[~TYP[1]] ~GENSYM[map_in][3];         assign ~SYM[3] = ~VAR[vec][1][~SYM[1]*~SIZE[~TYPEL[~TYP[1]]]+:~SIZE[~TYPEL[~TYP[1]]]];~ELSE ~FI-        ~OUTPUTWIREREG[0] ~TYPEL[~TYPO] ~GENSYM[map_out][4];+        ~OUTPUTUSAGE[0] ~TYPEL[~TYPO] ~GENSYM[map_out][4];         ~INST 0           ~OUTPUT <= ~SYM[4]~ ~TYPEL[~TYPO]~           ~INPUT  <= ~SYM[3]~ ~TYPEL[~TYP[1]]~@@ -120,7 +120,7 @@         wire [~SIZE[~INDEXTYPE[~LIT[0]]]-1:0] ~GENSYM[map_index][3];~IF~SIZE[~TYP[2]]~THEN         wire ~TYPEL[~TYP[2]] ~GENSYM[map_in][4];         assign ~SYM[4] = ~VAR[vec][2][~SYM[1]*~SIZE[~TYPEL[~TYP[2]]]+:~SIZE[~TYPEL[~TYP[2]]]];~ELSE ~FI-        ~OUTPUTWIREREG[1] ~TYPEL[~TYPO] ~GENSYM[map_out][5];+        ~OUTPUTUSAGE[1] ~TYPEL[~TYPO] ~GENSYM[map_out][5];          assign ~SYM[3] = ~SIZE[~INDEXTYPE[~LIT[0]]]'d~MAXINDEX[~TYPO] - ~SYM[1][0+:~SIZE[~INDEXTYPE[~LIT[0]]]];         ~INST 1@@ -146,7 +146,7 @@         wire ~TYP[0] ~GENSYM[map_index][3];~IF~SIZE[~TYP[2]]~THEN         wire ~TYPEL[~TYP[2]] ~GENSYM[map_in][4];         assign ~SYM[4] = ~VAR[vec][2][~SYM[1]*~SIZE[~TYPEL[~TYP[2]]]+:~SIZE[~TYPEL[~TYP[2]]]];~ELSE ~FI-        ~OUTPUTWIREREG[1] ~TYPEL[~TYPO] ~GENSYM[map_out][5];+        ~OUTPUTUSAGE[1] ~TYPEL[~TYPO] ~GENSYM[map_out][5];          assign ~SYM[3] = ~SIZE[~TYP[0]]'d~MAXINDEX[~TYPO] - ~SYM[1][0+:~SIZE[~TYP[0]]] + ~ARG[0];         ~INST 1@@ -173,7 +173,7 @@         assign ~SYM[3] = ~VAR[vec1][1][~SYM[2]*~SIZE[~TYPEL[~TYP[1]]]+:~SIZE[~TYPEL[~TYP[1]]]];~ELSE ~FI~IF~SIZE[~TYP[2]]~THEN         wire ~TYPEL[~TYP[2]] ~GENSYM[zipWith_in2][4];         assign ~SYM[4] = ~VAR[vec2][2][~SYM[2]*~SIZE[~TYPEL[~TYP[2]]]+:~SIZE[~TYPEL[~TYP[2]]]];~ELSE ~FI-        ~OUTPUTWIREREG[0] ~TYPEL[~TYPO] ~SYM[5];+        ~OUTPUTUSAGE[0] ~TYPEL[~TYPO] ~SYM[5];         ~INST 0           ~OUTPUT <= ~SYM[5]~ ~TYPEL[~TYPO]~           ~INPUT  <= ~SYM[3]~ ~TYPEL[~TYP[1]]~@@ -200,7 +200,7 @@         wire ~TYPEL[~TYP[2]] ~GENSYM[foldr_in1][5];         assign ~SYM[5] = ~VAR[xs][2][(~LENGTH[~TYP[2]]-1-~SYM[3])*~SIZE[~TYPEL[~TYP[2]]]+:~SIZE[~TYPEL[~TYP[2]]]];~ELSE ~FI         wire ~TYPO ~GENSYM[foldr_in2][6];-        ~OUTPUTWIREREG[0] ~TYPO ~GENSYM[foldr_out][7];+        ~OUTPUTUSAGE[0] ~TYPO ~GENSYM[foldr_out][7];          assign ~SYM[6] = ~SYM[0][~SYM[3]+1];         ~INST 0
prims/verilog/GHC_Base.primitives.yaml view
@@ -5,12 +5,24 @@       Int -> Int'     template: |-       // divInt begin-      // divide (rounds towards zero)-      wire ~SIGD[~GENSYM[quot_res][0]][0];-      assign ~SYM[0] = ~VAR[dividend][0] / ~VAR[divider][1];+      wire ~GENSYM[resultPos][1];+      wire ~GENSYM[dividerNeg][2];+      wire signed [~SIZE[~TYPO]:0] ~GENSYM[dividend2][3];+      wire signed [~SIZE[~TYPO]:0] ~GENSYM[dividendE][4];+      wire signed [~SIZE[~TYPO]:0] ~GENSYM[dividerE][5];+      wire signed [~SIZE[~TYPO]:0] ~GENSYM[quot_res][6]; -      // round toward minus infinity-      assign ~RESULT = (~VAR[dividend][0][~SIZE[~TYPO]-1] == ~VAR[divider][1][~SIZE[~TYPO]-1]) ? ~SYM[0] : ~SYM[0] - ~SIZE[~TYPO]'sd1;+      assign ~SYM[1] = ~VAR[dividend][0][~SIZE[~TYPO]-1] == ~VAR[divider][1][~SIZE[~TYPO]-1];+      assign ~SYM[2] = ~VAR[divider][1][~SIZE[~TYPO]-1] == 1'b1;+      assign ~SYM[4] = $signed({{~VAR[dividend][0][~SIZE[~TYPO]-1]},~VAR[dividend][0]});  // sign extension+      assign ~SYM[5] = $signed({{~VAR[divider][1][~SIZE[~TYPO]-1]} ,~VAR[divider][1]} );  // sign extension++      assign ~SYM[3] = ~SYM[1] ? ~SYM[4]+                               : (~SYM[2] ? (~SYM[4] - ~SYM[5] - ~SIZE[~TYPO]'sd1)+                                          : (~SYM[4] - ~SYM[5] + ~SIZE[~TYPO]'sd1));++      assign ~SYM[6] = ~SYM[3] / ~SYM[5];+      assign ~RESULT = $signed(~SYM[6][~SIZE[~TYPO]-1:0]);       // divInt end - BlackBox:     name: GHC.Base.modInt
prims/verilog/GHC_Prim.primitives.yaml view
@@ -1472,3 +1472,87 @@       ~FI       assign ~RESULT = $unsigned(~SYM[7]);       // ctz end+- BlackBox:+    name: GHC.Prim.quotRemInt8#+    kind: Declaration+    type: 'quotRemInt8# ::+      Int8# -> Int8# -> (#Int8#, Int8##)'+    template: |-+      // quotRemInt8 begin+      wire ~SIGD[~GENSYM[quot_res][0]][0];+      wire ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemInt8 end+- BlackBox:+    name: GHC.Prim.quotRemWord8#+    kind: Declaration+    type: 'quotRemWord8# ::+      Word8# -> Word8# -> (#Word8#, Word8##)'+    template: |-+      // quotRemWord8 begin+      wire ~SIGD[~GENSYM[quot_res][0]][0];+      wire ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemWord8 end+- BlackBox:+    name: GHC.Prim.quotRemInt16#+    kind: Declaration+    type: 'quotRemInt16# ::+      Int16# -> Int16# -> (#Int16#, Int16##)'+    template: |-+      // quotRemInt16 begin+      wire ~SIGD[~GENSYM[quot_res][0]][0];+      wire ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemInt16 end+- BlackBox:+    name: GHC.Prim.quotRemWord16#+    kind: Declaration+    type: 'quotRemWord16# ::+      Word16# -> Word16# -> (#Word16#, Word16##)'+    template: |-+      // quotRemWord16 begin+      wire ~SIGD[~GENSYM[quot_res][0]][0];+      wire ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemWord16 end+- BlackBox:+    name: GHC.Prim.quotRemInt32#+    kind: Declaration+    type: 'quotRemInt32# ::+      Int32# -> Int32# -> (#Int32#, Int32##)'+    template: |-+      // quotRemInt32 begin+      wire ~SIGD[~GENSYM[quot_res][0]][0];+      wire ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemInt32 end+- BlackBox:+    name: GHC.Prim.quotRemWord32#+    kind: Declaration+    type: 'quotRemWord32# ::+      Word32# -> Word32# -> (#Word32#, Word32##)'+    template: |-+      // quotRemWord32 begin+      wire ~SIGD[~GENSYM[quot_res][0]][0];+      wire ~SIGD[~GENSYM[rem_res][1]][0];+      assign ~SYM[0] = ~ARG[0] / ~ARG[1];+      assign ~SYM[1] = ~ARG[0] % ~ARG[1];++      assign ~RESULT = {~SYM[0],~SYM[1]};+      // quotRemWord32 end
prims/vhdl/Clash_Explicit_BlockRam.primitives.yaml view
@@ -1,11 +1,12 @@ - BlackBox:     name: Clash.Explicit.BlockRam.blockRam#     kind: Declaration+    outputUsage: NonBlocking     type: |-       blockRam#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> Vec n a         -- init, ARG[5]@@ -56,11 +57,12 @@ - BlackBox:     name: Clash.Explicit.BlockRam.blockRamU#     kind: Declaration+    outputUsage: NonBlocking     type: |-       blockRamU#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> SNat n          -- len,  ARG[5]@@ -113,11 +115,12 @@ - BlackBox:     name: Clash.Explicit.BlockRam.blockRam1#     kind: Declaration+    outputUsage: NonBlocking     type: |-       blockRam1#         :: ( KnownDomain dom        ARG[0]            , HasCallStack  --       ARG[1]-           , Undefined a ) --       ARG[2]+           , NFDataX a )   --       ARG[2]         => Clock dom       -- clk,  ARG[3]         -> Enable dom      -- en,   ARG[4]         -> SNat n          -- len,  ARG[5]@@ -168,67 +171,3 @@         end process; ~FI       end block;       --end blockRam1-- BlackBox:-    name: Clash.Explicit.BlockRam.trueDualPortBlockRam#-    kind: Declaration-    type: |--      trueDualPortBlockRam# ::-        forall nAddrs domA domB a .-        ( HasCallStack           ~ARG[0]-        , KnownNat nAddrs        ~ARG[1]-        , KnownDomain domA       ~ARG[2]-        , KnownDomain domB       ~ARG[3]-        , NFDataX a              ~ARG[4]-        ) =>--        Clock domA ->                   ~ARG[5]-        Signal domA Bool ->             ~ARG[6]-        Signal domA Bool ->             ~ARG[7]-        Signal domA (Index nAddrs) ->   ~ARG[8]-        Signal domA a ->                ~ARG[9]--        Clock domB ->                   ~ARG[10]-        Signal domB Bool ->             ~ARG[11]-        Signal domB Bool ->             ~ARG[12]-        Signal domB (Index nAddrs) ->   ~ARG[13]-        Signal domB a ->                ~ARG[14]-        (Signal domA a, Signal domB a)-    template: |--      -- trueDualPortBlockRam begin-      ~GENSYM[~RESULT_trueDualPortBlockRam][1] : block-        -- Shared memory-        type mem_type is array ( ~LIT[1]-1 downto 0 ) of ~TYP[9];-        shared variable mem : mem_type;-        signal ~GENSYM[a_dout][2] : ~TYP[9];-        signal ~GENSYM[b_dout][3] : ~TYP[14];-      begin--        -- Port A-        process(~ARG[5])-        begin-            if(rising_edge(~ARG[5])) then-                  if(~ARG[6]) then-                    if(~ARG[7]) then-                        mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI) := ~ARG[9];-                    end if;-                    ~SYM[2] <= mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI);-                end if;-            end if;-        end process;--        -- Port B-        process(~ARG[10])-        begin-            if(rising_edge(~ARG[10])) then-                if(~ARG[11]) then-                    if(~ARG[12]) then-                        mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI) := ~ARG[14];-                    end if;-                    ~SYM[3] <= mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI);-                end if;-            end if;-        end process;--        ~RESULT <= (~SYM[2], ~SYM[3]);-      end block;-      -- end trueDualPortBlockRam
prims/vhdl/Clash_Explicit_BlockRam_Blob.primitives.yaml view
@@ -1,6 +1,7 @@ - BlackBox:     name: Clash.Explicit.BlockRam.Blob.blockRamBlob#     kind: Declaration+    outputUsage: NonBlocking     type: |-       blockRamBlob#         :: KnownDomain dom           --       ARG[0]
prims/vhdl/Clash_Explicit_BlockRam_File.primitives.yaml view
@@ -1,6 +1,7 @@ - BlackBox:     name: Clash.Explicit.BlockRam.File.blockRamFile#     kind: Declaration+    outputUsage: NonBlocking     type: |-       blockRamFile#         :: ( KnownDomain dom        -- ARG[0]
prims/vhdl/Clash_Explicit_DDR.primitives.yaml view
@@ -4,7 +4,7 @@     type: |-       ddrIn# :: forall a slow fast n pFast enabled synchronous.                  ( HasCallStack           -- ARG[0]-                 , Undefined a            -- ARG[1]+                 , NFDataX a              -- ARG[1]                  , KnownConfi~ fast domf  -- ARG[2]                  , KnownConfi~ slow doms  -- ARG[3]               => Clock slow               -- ARG[4]@@ -94,8 +94,8 @@     name: Clash.Explicit.DDR.ddrOut#     kind: Declaration     type: |--      ddrOut# :: ( HasCallStack               -- ARG[0]-                  , Undefined a                -- ARG[1]+      ddrOut# :: ( HasCallStack                -- ARG[0]+                  , NFDataX a                  -- ARG[1]                   , KnownConfi~ fast domf      -- ARG[2]                   , KnownConfi~ slow doms      -- ARG[3]                => Clock slow                   -- ARG[4]
prims/vhdl/Clash_Explicit_ROM.primitives.yaml view
@@ -1,10 +1,11 @@ - BlackBox:     name: Clash.Explicit.ROM.rom#     kind: Declaration+    outputUsage: NonBlocking     type: |-       rom# :: ( KnownDomain dom        ARG[0]                , KnownNat n    --       ARG[1]-               , Undefined a ) --       ARG[2]+               , NFDataX a )   --       ARG[2]             => Clock dom       -- clk,  ARG[3]             -> Enable dom      -- en,   ARG[4]             -> Vec n a         -- init, ARG[5]
prims/vhdl/Clash_Explicit_ROM_Blob.primitives.yaml view
@@ -1,6 +1,7 @@ - BlackBox:     name: Clash.Explicit.ROM.Blob.romBlob#     kind: Declaration+    outputUsage: NonBlocking     type: |-       romBlob#         :: KnownDomain dom  --       ARG[0]
prims/vhdl/Clash_Explicit_ROM_File.primitives.yaml view
@@ -1,6 +1,7 @@ - BlackBox:     name: Clash.Explicit.ROM.File.romFile#     kind: Declaration+    outputUsage: NonBlocking     type: |-       romFile# :: ( KnownNat m           --       ARG[0]                    , KnownDomain dom      --       ARG[1]
prims/vhdl/Clash_Explicit_Testbench.primitives.yaml view
@@ -149,41 +149,13 @@       end block;       -- assertBitVector end - BlackBox:-    name: Clash.Explicit.Testbench.tbClockGen-    comment: |--      ModelSim and Vivado seem to round time values to an integer number of picoseconds.-              Use two half periods to prevent rounding errors from affecting the full period.-    kind: Declaration-    type: |--      tbClockGen-        :: KnownDomain dom     -- ARG[0]-        => Signal dom Bool     -- ARG[1]-        -> Clock dom-    template: |--      -- tbClockGen begin-      -- pragma translate_off-      ~GENSYM[clkGen][0] : process is-        constant ~GENSYM[half_periodH][1] : time := ~PERIOD[0]000 fs / 2;-        constant ~GENSYM[half_periodL][2] : time := ~PERIOD[0]000 fs - ~SYM[1];-      begin-        ~RESULT <= ~IF~ACTIVEEDGE[Rising][0]~THEN'0'~ELSE'1'~FI;-        wait for ~LONGESTPERIOD ps;-        while ~ARG[1] loop-          ~RESULT <= not ~RESULT;-          wait for ~SYM[1];-          ~RESULT <= not ~RESULT;-          wait for ~SYM[2];-        end loop;-        wait;-      end process;-      -- pragma translate_on-      -- tbClockGen end-    warning: Clash.Signal.Internal.tbClockGen is not synthesizable!-    workInfo: Always-- BlackBox:     name: Clash.Explicit.Testbench.tbEnableGen     kind: Declaration     type: 'tbEnableGen ::       Enable dom'     template: ~RESULT <= true;     workInfo: Always+- BlackBox:+    name: Clash.Explicit.Testbench.clockToDiffClock+    kind: Expression+    template: (~ARG[1], not ~ARG[1])
prims/vhdl/Clash_Prelude_ROM.primitives.yaml view
@@ -2,19 +2,21 @@     name: Clash.Prelude.ROM.asyncRom#     kind: Declaration     type: |--      asyncRom# :: KnownNat n -- ^ ARG[0]-                 => Vec n a    -- ^ ARG[1]-                 -> Int        -- ^ ARG[2]-                 -> a+      asyncRom#+        :: ( KnownNat n  -- ARG[0]+           , NFDataX a)  -- ARG[1]+        => Vec n a       -- ARG[2]+        -> Int           -- ARG[3]+        -> a     template: |-       -- asyncRom begin       ~GENSYM[asyncRom][0] : block-        signal ~GENSYM[ROM][1] : ~TYP[1];+        signal ~GENSYM[ROM][1] : ~TYP[2];         signal ~GENSYM[rd][2] : integer range 0 to ~LIT[0]-1;       begin-        ~SYM[1] <= ~CONST[1];+        ~SYM[1] <= ~CONST[2]; -        ~SYM[2] <= to_integer(~VAR[rdI][2](31 downto 0))+        ~SYM[2] <= to_integer(~VAR[rdI][3](31 downto 0))         -- pragma translate_off                             mod ~LIT[0]         -- pragma translate_on
prims/vhdl/Clash_Signal_Internal.primitives.yaml view
@@ -1,10 +1,11 @@ - BlackBox:     name: Clash.Signal.Internal.delay#     kind: Declaration+    outputUsage: NonBlocking     type: |-       delay#         :: ( KnownDomain dom        -- ARG[0]-           , Undefined a )          -- ARG[1]+           , NFDataX a )            -- ARG[1]         => Clock dom                -- ARG[2]         -> Enable dom               -- ARG[3]         -> a                        -- ARG[4]@@ -34,6 +35,7 @@ - BlackBox:     name: Clash.Signal.Internal.asyncRegister#     kind: Declaration+    outputUsage: NonBlocking     type: |-       asyncRegister#         :: ( KnownDomain dom        -- ARG[0]@@ -69,6 +71,7 @@ - BlackBox:     name: Clash.Signal.Internal.register#     kind: Declaration+    outputUsage: NonBlocking     type: |-       register#         :: ( KnownDomain dom        -- ARG[0]@@ -126,17 +129,19 @@       end process;~FI~FI       -- register end - BlackBox:-    name: Clash.Signal.Internal.clockGen+    name: Clash.Signal.Internal.tbClockGen     comment: |-       ModelSim and Vivado seem to round time values to an integer number of picoseconds.               Use two half periods to prevent rounding errors from affecting the full period.     kind: Declaration+    outputUsage: NonBlocking     type: |--      clockGen+      tbClockGen         :: KnownDomain dom     -- ARG[0]-        => Clock dom+        => Signal dom Bool     -- ARG[1]+        -> Clock dom     template: |--      -- clockGen begin+      -- tbClockGen begin       -- pragma translate_off       ~GENSYM[clkGen][0] : process is         constant ~GENSYM[half_periodH][1] : time := ~PERIOD[0]000 fs / 2;@@ -144,7 +149,7 @@       begin         ~RESULT <= ~IF~ACTIVEEDGE[Rising][0]~THEN'0'~ELSE'1'~FI;         wait for ~LONGESTPERIOD ps;-        loop+        ~IF~ISACTIVEENABLE[1]~THENwhile ~ARG[1] ~ELSE~FIloop           ~RESULT <= not ~RESULT;           wait for ~SYM[1];           ~RESULT <= not ~RESULT;@@ -153,10 +158,50 @@         wait;       end process;       -- pragma translate_on-      -- clockGen end-    warning: Clash.Signal.Internal.clockGen is not synthesizable!+      -- tbClockGen end+    warning: Clash.Signal.Internal.tbClockGen is not synthesizable!     workInfo: Always - BlackBox:+    name: Clash.Signal.Internal.tbDynamicClockGen+    comment: |-+      ModelSim and Vivado seem to round time values to an integer number of picoseconds.+              Use two half periods to prevent rounding errors from affecting the full period.+    kind: Declaration+    outputUsage: NonBlocking+    type: |-+      tbDynamicClockGen+        :: KnownDomain dom     -- ARG[0]+        => Signal dom Int64    -- ARG[1]+        -> Signal dom Bool     -- ARG[2]+        -> Clock dom+    template: |-+      -- tbDynamicClockGen begin+      -- pragma translate_off+      ~GENSYM[dynClkGen][0] : process is+        variable ~GENSYM[whole_period][1] : time;+        variable ~GENSYM[half_periodH][2] : time;+        variable ~GENSYM[half_periodL][3] : time;+      begin+        ~RESULT <= ~IF~ACTIVEEDGE[Rising][0]~THEN'0'~ELSE'1'~FI;+        wait for ~LONGESTPERIOD ps;++        ~IF~ISACTIVEENABLE[2]~THENwhile ~ARG[2] ~ELSE~FIloop+          ~SYM[1] := to_integer(~VAR[periods][1]) * 1 fs;+          ~SYM[2] := ~SYM[1] / 2;+          ~SYM[3] := ~SYM[1] - ~SYM[2];++          ~RESULT <= not ~RESULT;+          wait for ~SYM[2];+          ~RESULT <= not ~RESULT;+          wait for ~SYM[3];+        end loop;+        wait;+      end process;+      -- pragma translate_on+      -- tbDynamicClockGen end+    warning: Clash.Signal.Internal.tbDynamicClockGen is not synthesizable!+    workInfo: Always+- BlackBox:     name: Clash.Signal.Internal.resetGenN     kind: Declaration     type: 'resetGenN :: (KnownDomain@@ -185,6 +230,6 @@     name: Clash.Signal.Internal.unsafeToReset     kind: Declaration     type: 'unsafeToReset ::-      Signal dom Bool -> Reset dom'-    template: ~RESULT <= '1' when ~ARG[0] = true else '0';+      KnownDomain dom => Signal dom Bool -> Reset dom'+    template: ~RESULT <= '1' when ~ARG[1] = true else '0';     workInfo: Never
prims/vhdl/Clash_Sized_Internal_BitVector.primitives.yaml view
@@ -252,6 +252,7 @@ - BlackBox:     name: Clash.Sized.Internal.BitVector.replaceBit#     kind: Declaration+    outputUsage: NonBlocking     type: |-       replaceBit# :: KnownNat n  -- ARG[0]                    => BitVector n -- ARG[1]@@ -282,6 +283,7 @@ - BlackBox:     name: Clash.Sized.Internal.BitVector.setSlice#     kind: Declaration+    outputUsage: NonBlocking     type: |-       setSlice# :: SNat (m + 1 + i)                  => BitVector (m + 1 + i) -- ARG[1]
prims/vhdl/Clash_Sized_Vector.primitives.yaml view
@@ -274,6 +274,7 @@ - BlackBox:     name: Clash.Sized.Vector.replace_int     kind: Declaration+    outputUsage: NonBlocking     type: 'replace_int ::       KnownNat n => Vec n a -> Int -> a -> Vec n a'     template: |-
− prims/vhdl/Clash_Xilinx_ClockGen.primitives.yaml
@@ -1,65 +0,0 @@-- BlackBox:-    name: Clash.Xilinx.ClockGen.clockWizard-    kind: Declaration-    type: |--      clockWizard-        :: ( KnownDomain domIn confIn       -- ARG[0]-           , KnownDomain domOut confOut )   -- ARG[1]-        => SSymbol name                    -- ARG[2]-        -> Clock  pllIn                    -- ARG[3]-        -> Reset pllIn                     -- ARG[4]-        -> (Clock pllOut, Enable pllOut)-    template: |--      -- clockWizard begin-      ~GENSYM[clockWizard][0] : block-        signal ~GENSYM[pllOut][1]  : std_logic;-        signal ~GENSYM[locked][2]  : std_logic;-        signal ~GENSYM[pllLock][3] : boolean;--        component ~NAME[2]-          port (CLK_IN1  : in std_logic;-                RESET    : in std_logic;-                CLK_OUT1 : out std_logic;-                LOCKED   : out std_logic);-        end component;-      begin-        ~GENSYM[clockWizard_inst][4] : component ~NAME[2] port map (~ARG[3],~IF ~ISACTIVEHIGH[0] ~THEN ~ARG[4] ~ELSE NOT(~ARG[4]) ~FI,~SYM[1],~SYM[2]);-        ~SYM[3] <= true when ~SYM[2] = '1' else false;-        ~RESULT <= (~SYM[1],~SYM[3]);-      end block;-      -- clockWizard end-    workInfo: Always-- BlackBox:-    name: Clash.Xilinx.ClockGen.clockWizardDifferential-    kind: Declaration-    type: |--      clockWizardDifferential-        :: ( KnownDomain domIn confIn       -- ARG[0]-           , KnownDomain domOut confOut )   -- ARG[1]-        => SSymbol name                    -- ARG[2]-        -> Clock pllIn                     -- ARG[3]-        -> Clock pllIn                     -- ARG[4]-        -> Reset pllIn                     -- ARG[5]-        -> (Clock pllOut, Enable pllOut)-    template: |--      -- clockWizardDifferential begin-      ~GENSYM[clockWizardDifferential][0] : block-        signal ~GENSYM[pllOut][1]  : std_logic;-        signal ~GENSYM[locked][2]  : std_logic;-        signal ~GENSYM[pllLock][3] : boolean;--        component ~NAME[2]-          port (CLK_IN1_D_clk_n : in std_logic;-                CLK_IN1_D_clk_p : in std_logic;-                RESET           : in std_logic;-                CLK_OUT1        : out std_logic;-                LOCKED          : out std_logic);-        end component;-      begin-        ~GENSYM[clockWizardDifferential_inst][4] : component ~NAME[2]-          port map (~ARG[3],~ARG[4],~IF ~ISACTIVEHIGH[0] ~THEN ~ARG[5] ~ELSE NOT(~ARG[5]) ~FI,~SYM[1],~SYM[2]);-        ~SYM[3] <= true when ~SYM[2] = '1' else false;-        ~RESULT <= (~SYM[1],~SYM[3]);-      end block;-      -- clockWizardDifferential end-    workInfo: Always
prims/vhdl/GHC_Base.primitives.yaml view
@@ -17,15 +17,22 @@     template: |-       -- divInt begin       ~GENSYM[divInt][0] : block-        signal ~GENSYM[quot_res][1] : ~TYP[1];+        signal ~GENSYM[resultPos][1] : boolean;+        signal ~GENSYM[dividerNeg][2] : boolean;+        signal ~GENSYM[dividend2][3] : signed(~SIZE[~TYPO] downto 0);+        signal ~GENSYM[quot_res][4] : signed(~SIZE[~TYPO] downto 0);       begin-        ~SYM[1] <= ~ARG[0] / ~ARG[1]+        ~SYM[1] <= ~VAR[dividend][0](~VAR[dividend][0]'high) = ~VAR[divider][1](~VAR[divider][1]'high);+        ~SYM[2] <= ~VAR[divider][1](~VAR[divider][1]'high) = '1';+        ~SYM[3] <= resize(~VAR[dividend][0],~SIZE[~TYPO]+1)   when ~SYM[1] else+                   (resize(~VAR[dividend][0],~SIZE[~TYPO]+1) - resize(~VAR[divider][1],~SIZE[~TYPO]+1) - 1)   when ~SYM[2] else+                   (resize(~VAR[dividend][0],~SIZE[~TYPO]+1) - resize(~VAR[divider][1],~SIZE[~TYPO]+1) + 1);+        ~SYM[4] <= ~SYM[3] / ~VAR[divider][1]             -- pragma translate_off-            when (ARG[1] /= 0) else (others => 'X')+            when (~VAR[divider][1] /= 0) else (others => 'X')             -- pragma translate_on             ;-        ~RESULT <= ~SYM[1] - 1 when ((~ARG[0] = abs ~ARG[0]) /= (~ARG[1] = abs ~ARG[1])) else-                   ~SYM[1];+        ~RESULT <= signed(~SYM[4](~SIZE[~TYPO]-1 downto 0));       end block;       -- divInt end - BlackBox:
prims/vhdl/GHC_Num_Integer.primitives.yaml view
@@ -291,6 +291,14 @@       but fixed-length after synthesis. Use carefully.'     workInfo: Never - BlackBox:+    name: GHC.Num.Integer.integerToInt64#+    kind: Expression+    type: 'integerToInt64# :: Integer -> Int64#'+    template: ~ARG[0]+    warning: 'GHC.Num.Integer.integerToInt64#: Integers are dynamically sized in+      simulation, but fixed-length after synthesis. Use carefully.'+    workInfo: Never+- BlackBox:     name: GHC.Num.Integer.integerToWord64#     comment: only used by 32 bit GHC     kind: Expression@@ -301,6 +309,14 @@       simulation, but fixed-length after synthesis. Use carefully.'     workInfo: Never - BlackBox:+    name: GHC.Num.Integer.integerFromWord64#+    kind: Expression+    type: 'integerFromWord64# :: Word64# -> Integer'+    template: signed(std_logic_vector(~ARG[0]))+    warning: 'GHC.Num.Integer.integerFromWord64#: Integers are dynamically sized in+      simulation, but fixed-length after synthesis. Use carefully.'+    workInfo: Never+- BlackBox:     name: GHC.Num.Integer.integerBit#     kind: Expression     type: 'integerBit :: Word#@@ -341,17 +357,17 @@     warning: 'GHC.Num.Integer.integerAnd: Integers are dynamically sized in simulation,       but fixed-length after synthesis. Use carefully.' - BlackBox:-    name: GHC.Num.Integer.integerSigmum+    name: GHC.Num.Integer.integerSignum     kind: Declaration-    type: 'integerSigmum ::+    type: 'integerSignum ::       Integer -> Integer'     template: |2 -      -- begin integerSigmum+      -- begin integerSignum       ~RESULT <= to_signed(-1, ~SIZE[~TYPO]) when ~ARG[0] < 0         else to_signed(0, ~SIZE[~TYPO])  when ~ARG[0] = 0         else to_signed(1, ~SIZE[~TYPO]);-      -- end integerSigmum+      -- end integerSignum     warning: 'GHC.Num.Integer.integerSignum: Integers are dynamically sized in simulation,       but fixed-length after synthesis. Use carefully.' - BlackBox:@@ -403,3 +419,9 @@           ;     warning: 'GHC.Num.Integer.integerQuot: Integers are dynamically sized in simulation,       but fixed-length after synthesis. Use carefully.'+- BlackBox:+    name: GHC.Num.Integer.$wintegerFromInt64#+    kind: Expression+    type: '$wintegerFromInt64# :: Int64# -> Int#'+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never
prims/vhdl/GHC_Prim.primitives.yaml view
@@ -1257,3 +1257,1003 @@           when (~ARG[1] /= 0) else (others => 'X')           -- pragma translate_on           ;+- BlackBox:+    name: GHC.Prim.int8ToInt#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt8#+    kind: Expression+    template: ~VAR[i][0](7 downto 0)+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt8#+    kind: Expression+    template: -~ARG[0]+- BlackBox:+    name: GHC.Prim.timesInt8#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotInt8#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remInt8#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemInt8#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.uncheckedShiftLInt8#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRAInt8#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftR][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_right(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLInt8#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.int8ToWord8#+    kind: Expression+    template: unsigned(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geInt8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtInt8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leInt8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltInt8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neInt8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.word8ToWord#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord8#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord8#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotWord8#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remWord8#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemWord8#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.andWord8#+    kind: Expression+    template: ~ARG[0] and ~ARG[1]+- BlackBox:+    name: GHC.Prim.orWord8#+    kind: Expression+    template: ~ARG[0] or ~ARG[1]+- BlackBox:+    name: GHC.Prim.xorWord8#+    kind: Expression+    template: ~ARG[0] xor ~ARG[1]+- BlackBox:+    name: GHC.Prim.notWord8#+    kind: Expression+    template: not ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLWord8#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLWord8#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.word8ToInt8#+    kind: Expression+    template: signed(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geWord8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtWord8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leWord8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltWord8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neWord8#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.int16ToInt#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt16#+    kind: Expression+    template: ~VAR[i][0](15 downto 0)+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt16#+    kind: Expression+    template: -~ARG[0]+- BlackBox:+    name: GHC.Prim.timesInt16#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotInt16#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remInt16#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemInt16#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.uncheckedShiftLInt16#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRAInt16#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftR][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_right(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLInt16#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.int16ToWord16#+    kind: Expression+    template: unsigned(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geInt16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtInt16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leInt16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltInt16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neInt16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.word16ToWord#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord16#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord16#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotWord16#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remWord16#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemWord16#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.andWord16#+    kind: Expression+    template: ~ARG[0] and ~ARG[1]+- BlackBox:+    name: GHC.Prim.orWord16#+    kind: Expression+    template: ~ARG[0] or ~ARG[1]+- BlackBox:+    name: GHC.Prim.xorWord16#+    kind: Expression+    template: ~ARG[0] xor ~ARG[1]+- BlackBox:+    name: GHC.Prim.notWord16#+    kind: Expression+    template: not ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLWord16#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLWord16#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.word16ToInt16#+    kind: Expression+    template: signed(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geWord16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtWord16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leWord16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltWord16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neWord16#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.int32ToInt#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt32#+    kind: Expression+    template: ~VAR[i][0](31 downto 0)+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt32#+    kind: Expression+    template: -~ARG[0]+- BlackBox:+    name: GHC.Prim.timesInt32#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotInt32#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remInt32#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemInt32#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.uncheckedShiftLInt32#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRAInt32#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftR][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_right(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLInt32#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.int32ToWord32#+    kind: Expression+    template: unsigned(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geInt32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtInt32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leInt32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltInt32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neInt32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.word32ToWord#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord32#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord32#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotWord32#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remWord32#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemWord32#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.andWord32#+    kind: Expression+    template: ~ARG[0] and ~ARG[1]+- BlackBox:+    name: GHC.Prim.orWord32#+    kind: Expression+    template: ~ARG[0] or ~ARG[1]+- BlackBox:+    name: GHC.Prim.xorWord32#+    kind: Expression+    template: ~ARG[0] xor ~ARG[1]+- BlackBox:+    name: GHC.Prim.notWord32#+    kind: Expression+    template: not ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftLWord32#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRLWord32#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.word32ToInt32#+    kind: Expression+    template: signed(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geWord32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtWord32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leWord32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltWord32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neWord32#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.int64ToInt#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.intToInt64#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.negateInt64#+    kind: Expression+    template: -~ARG[0]+- BlackBox:+    name: GHC.Prim.timesInt64#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotInt64#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remInt64#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemInt64#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.uncheckedIShiftL64#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedIShiftRA64#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftR][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_right(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedIShiftRL64#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.int64ToWord64#+    kind: Expression+    template: unsigned(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqInt64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geInt64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtInt64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leInt64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltInt64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neInt64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.word64ToWord#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.wordToWord64#+    kind: Expression+    template: resize(~ARG[0],~SIZE[~TYPO])+    workInfo: Never+- BlackBox:+    name: GHC.Prim.timesWord64#+    kind: Expression+    template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO])+- BlackBox:+    name: GHC.Prim.quotWord64#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] / ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.remWord64#+    kind: Declaration+    template: |-+      ~RESULT <= ~ARG[0] rem ~ARG[1]+          -- pragma translate_off+          when (~ARG[1] /= 0) else (others => 'X')+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.quotRemWord64#+    kind: Declaration+    template: |-+      ~RESULT <= (~ARG[0] / ~ARG[1], ~ARG[0] rem ~ARG[1])+          -- pragma translate_off+          when (~ARG[1] /= 0) else ((others => 'X'), (others => 'X'))+          -- pragma translate_on+          ;+- BlackBox:+    name: GHC.Prim.and64#+    kind: Expression+    template: ~ARG[0] and ~ARG[1]+- BlackBox:+    name: GHC.Prim.or64#+    kind: Expression+    template: ~ARG[0] or ~ARG[1]+- BlackBox:+    name: GHC.Prim.xor64#+    kind: Expression+    template: ~ARG[0] xor ~ARG[1]+- BlackBox:+    name: GHC.Prim.not64#+    kind: Expression+    template: not ~ARG[0]+- BlackBox:+    name: GHC.Prim.uncheckedShiftL64#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= shift_left(~ARG[0],~SYM[1])+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.uncheckedShiftRL64#+    kind: Declaration+    template: |-+      ~GENSYM[~RESULT_shiftRL][0] : block+        signal ~GENSYM[sh][1] : natural;+      begin+        ~SYM[1] <=+            -- pragma translate_off+            natural'high when (~VAR[shI][1](~SIZE[~TYP[1]]-1 downto 31) /= 0) else+            -- pragma translate_on+            to_integer(~VAR[shI][1]);+        ~RESULT <= ~ARG[0] srl ~SYM[1]+            -- pragma translate_off+            when (~ARG[1] >= 0) else (others => 'X')+            -- pragma translate_on+            ;+      end block;+- BlackBox:+    name: GHC.Prim.word64ToInt64#+    kind: Expression+    template: signed(std_logic_vector(~ARG[0]))+    workInfo: Never+- BlackBox:+    name: GHC.Prim.eqWord64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] = ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.geWord64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] >= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.gtWord64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] > ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.leWord64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] <= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.ltWord64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] < ~ARG[1] else to_signed(0,~SIZE[~TYPO]);+- BlackBox:+    name: GHC.Prim.neWord64#+    kind: Declaration+    template: ~RESULT <= to_signed(1,~SIZE[~TYPO]) when ~ARG[0] /= ~ARG[1] else to_signed(0,~SIZE[~TYPO]);
src/Clash/Backend.hs view
@@ -2,6 +2,7 @@   Copyright  :  (C) 2015-2016, University of Twente,                     2017     , Myrtle Software Ltd, Google Inc.,                     2021-2022, QBayLogic B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> -}@@ -13,6 +14,7 @@  import Data.HashMap.Strict                  (HashMap, empty) import Data.HashSet                         (HashSet)+import Control.Lens                         (Lens') import Data.Monoid                          (Ap) import Data.Text                            (Text) import qualified Data.Text.Lazy             as LT@@ -27,7 +29,7 @@  import Clash.Driver.Types (ClashOpts) import {-# SOURCE #-} Clash.Netlist.Types-  (Component, Declaration, Expr, HWType, Identifier, IdentifierSet, HasIdentifierSet)+  (Component, Declaration, Expr, HWType, Identifier, IdentifierSet, HasIdentifierSet, UsageMap) import Clash.Netlist.BlackBox.Types  import Clash.Signal.Internal                (VDomainConfiguration)@@ -87,7 +89,10 @@ emptyDomainMap :: DomainMap emptyDomainMap = empty -class HasIdentifierSet state => Backend state where+class HasUsageMap s where+  usageMap :: Lens' s UsageMap++class (HasUsageMap state, HasIdentifierSet state) => Backend state where   -- | Initial state for state monad   initBackend :: ClashOpts -> state @@ -108,7 +113,7 @@   extractTypes     :: state -> HashSet HWType    -- | Generate HDL for a Netlist component-  genHDL           :: ModName -> SrcSpan -> IdentifierSet -> Component -> Ap (State state) ((String, Doc),[(String,Doc)])+  genHDL           :: ClashOpts -> ModName -> SrcSpan -> IdentifierSet -> UsageMap -> Component -> Ap (State state) ((String, Doc),[(String,Doc)])   -- | Generate a HDL package containing type definitions for the given HWTypes   mkTyPackage      :: ModName -> [HWType] -> Ap (State state) [(String, Doc)]   -- | Convert a Netlist HWType to a target HDL type
src/Clash/Backend/SystemVerilog.hs view
@@ -1,7 +1,8 @@ {-|   Copyright   :  (C) 2015-2016, University of Twente,                      2017-2018, Google Inc.,-                     2021-2022, QBayLogic B.V.+                     2021-2023, QBayLogic B.V.,+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -48,18 +49,19 @@   (bitsToBits) import           Clash.Annotations.BitRepresentation.Util   (BitOrigin(Lit, Field), bitOrigins, bitRanges)-import           Clash.Core.Var                       (Attr'(..))+import           Clash.Annotations.SynthesisAttributes (Attr(..)) import           Clash.Debug                          (traceIf) import           Clash.Backend import           Clash.Backend.Verilog   (bits, bit_char, encodingNote, exprLit, include, noEmptyInit, uselibs)+import           Clash.Backend.Verilog.Time           (periodToString) import           Clash.Driver.Types                   (ClashOpts(..)) import           Clash.Explicit.BlockRam.Internal     (unpackNats) import           Clash.Netlist.BlackBox.Types         (HdlSyn (..)) import           Clash.Netlist.BlackBox.Util   (extractLiterals, renderBlackBox, renderFilePath) import qualified Clash.Netlist.Id                     as Id-import           Clash.Netlist.Types                  hiding (intWidth)+import           Clash.Netlist.Types                  hiding (intWidth, usages, _usages) import           Clash.Netlist.Util import           Clash.Signal.Internal                (ActiveEdge (..)) import           Clash.Util@@ -93,6 +95,7 @@     , _aggressiveXOptBB_ :: AggressiveXOptBB     , _renderEnums_ :: RenderEnums     , _domainConfigurations_ :: DomainMap+    , _usages :: UsageMap     }  makeLenses ''SystemVerilogState@@ -100,6 +103,9 @@ instance HasIdentifierSet SystemVerilogState where   identifierSet = idSeen +instance HasUsageMap SystemVerilogState where+  usageMap = usages+ instance Backend SystemVerilogState where   initBackend opts = SystemVerilogState     { _tyCache=HashSet.empty@@ -122,6 +128,7 @@     , _aggressiveXOptBB_=coerce (opt_aggressiveXOptBB opts)     , _renderEnums_=coerce (opt_renderEnums opts)     , _domainConfigurations_=emptyDomainMap+    , _usages=mempty     }   hdlKind         = const SystemVerilog   primDirs        = const $ do root <- primsRoot@@ -197,33 +204,40 @@  -- | Generate SystemVerilog for a Netlist component genSystemVerilog-  :: ModName+  :: ClashOpts+  -> ModName   -> SrcSpan   -> IdentifierSet+  -> UsageMap   -> Component   -> SystemVerilogM ((String, Doc), [(String, Doc)])-genSystemVerilog _ sp seen c = do+genSystemVerilog opts _ sp seen us c = do     -- Don't have type names conflict with module names or with previously     -- generated type names.     --     -- TODO: Collect all type names up front, to prevent relatively costly union.     -- TODO: Investigate whether type names / signal names collide in the first place-    Ap $ idSeen %= Id.union seen+    Ap $ do+      idSeen %= Id.union seen+      usages .= us+      setSrcSpan sp -    Ap $ setSrcSpan sp     v    <- verilog     incs <- Ap $ use includes     return ((TextS.unpack (Id.toText cName), v), incs)   where     cName   = componentName c     verilog = commentHeader <> line <>+              nettype <> line <>               timescale <> line <>               module_ c     commentHeader          = "/* AUTOMATICALLY GENERATED SYSTEMVERILOG-2005 SOURCE CODE."       <> line <> "** GENERATED BY CLASH " <> string (Text.pack clashVer) <> ". DO NOT MODIFY."       <> line <> "*/"-    timescale = "`timescale 100fs/100fs"+    nettype = "`default_nettype none"+    timescale = "`timescale 100fs/" <> string (Text.pack precision)+    precision = periodToString (opt_timescalePrecision opts)  -- | Generate a SystemVerilog package containing type definitions for the given HWTypes mkTyPackage_ :: TextS.Text -> [HWType] -> SystemVerilogM [(String,Doc)]@@ -316,6 +330,7 @@ normaliseType ty@(Sum _ _) = return (BitVector (typeSize ty)) normaliseType ty@(CustomSum _ _ _ _) = return (BitVector (typeSize ty)) normaliseType (Clock _) = return Bit+normaliseType (ClockN _) = return Bit normaliseType (Reset _) = return Bit normaliseType (Enable _) = return Bool normaliseType (BiDirectional dir ty) = BiDirectional dir <$> normaliseType ty@@ -380,6 +395,7 @@       Product {} -> (ns, verilogType t)       Vector {}  -> error $ $(curLoc) ++ "impossible"       Clock {}   -> (ns, verilogType t)+      ClockN {}  -> (ns, verilogType t)       Reset {}   -> (ns, "logic")       Enable {}  -> (ns, "logic")       Bool       -> (ns, "logic")@@ -522,13 +538,21 @@   modEnding  = "endmodule"    inPorts  = sequence [ sigPort (Nothing,isBiSignalIn ty) (i,ty) Nothing | (i,ty)  <- inputs c  ]-  outPorts = sequence [ sigPort (Just wr,False) p iEM | (wr, p, iEM) <- outputs c ]+  outPorts = sequence [ sigPort (Just u,False) p iEM | (u, p, iEM) <- outputs c ] +  -- NOTE [net types and data types]+  --+  -- SystemVerilog makes a distinction between the type of a net and the data+  -- type of a signal. For output ports / inout ports this is fine, as there+  -- is only one possible type. For input ports when using `default_nettype none+  -- we have to specify the net type as wire explicitly (or vendor tools will+  -- claim the net from the port declaration is implicitly defined).+   wr2ty (Nothing,isBidirectional)     | isBidirectional-    = "inout"+    = "inout" -- no net type here, it gets added by verilogType.     | otherwise-    = "input"+    = "input wire" -- See NOTE [net types and data types]   wr2ty (Just _,_)     = "output" @@ -574,6 +598,7 @@     RTree {}      -> pvrType     Signed n      -> logicOrWire <+> "signed" <+> brackets (int (n-1) <> colon <> int 0)     Clock _       -> "logic"+    ClockN _      -> "logic"     Reset _       -> "logic"     Enable _      -> "logic"     Bit           -> "logic"@@ -623,6 +648,7 @@  tyName t@(SP _ _) = "logic_vector_" <> int (typeSize t) tyName (Clock _)  = "logic"+tyName (ClockN _) = "logic" tyName (Reset _)  = "logic" tyName (Enable _) = "logic" tyName t =  error $ $(curLoc) ++ "tyName: " ++ show t@@ -665,35 +691,34 @@       _  -> punctuate' semi (A.pure dsDoc)  decl :: Declaration -> SystemVerilogM (Maybe Doc)-decl (NetDecl' noteM _ id_ tyE iEM) =+decl (NetDecl' noteM id_ tyE iEM) =   Just A.<$> maybe id addNote noteM (addAttrs attrs (typ tyE))   where-    typ (Left  ty) = stringS ty <+> pretty id_ <> iE-    typ (Right ty) = sigDecl (pretty id_) ty <> iE+    typ ty = sigDecl (pretty id_) ty <> iE     addNote n = mappend ("//" <+> stringS n <> line)-    attrs = fromMaybe [] (hwTypeAttrs A.<$> either (const Nothing) Just tyE)+    attrs = fromMaybe [] (hwTypeAttrs A.<$> Just tyE)     iE = maybe emptyDoc (noEmptyInit . expr_ False) iEM  decl _ = return Nothing  -- | Convert single attribute to systemverilog syntax-renderAttr :: Attr' -> Text.Text-renderAttr (StringAttr'  key value) = Text.pack $ concat [key, " = ", show value]-renderAttr (IntegerAttr' key value) = Text.pack $ concat [key, " = ", show value]-renderAttr (BoolAttr'    key True ) = Text.pack $ concat [key, " = ", "1"]-renderAttr (BoolAttr'    key False) = Text.pack $ concat [key, " = ", "0"]-renderAttr (Attr'        key      ) = Text.pack $ key+renderAttr :: Attr TextS.Text -> TextS.Text+renderAttr (StringAttr  key value) = TextS.concat [key, " = ", TextS.pack (show value)]+renderAttr (IntegerAttr key value) = TextS.concat [key, " = ", TextS.pack (show value)]+renderAttr (BoolAttr    key True ) = TextS.concat [key, " = ", "1"]+renderAttr (BoolAttr    key False) = TextS.concat [key, " = ", "0"]+renderAttr (Attr        key      ) = key  -- | Add attribute notation to given declaration addAttrs-  :: [Attr']+  :: [Attr TextS.Text]   -> SystemVerilogM Doc   -> SystemVerilogM Doc addAttrs []     t = t addAttrs attrs' t =   "(*" <+> attrs'' <+> "*)" <+> t     where-      attrs'' = string $ Text.intercalate ", " (map renderAttr attrs')+      attrs'' = stringS $ TextS.intercalate ", " (map renderAttr attrs')  insts :: [Declaration] -> SystemVerilogM Doc insts [] = emptyDoc@@ -777,7 +802,9 @@ inst_ :: Declaration -> SystemVerilogM (Maybe Doc) inst_ (TickDecl {}) = return Nothing -inst_ (Assignment id_ e) = fmap Just $+inst_ (CompDecl {}) = return Nothing++inst_ (Assignment id_ Cont e) = fmap Just $   "assign" <+> pretty id_ <+> equals <+> align (expr_ False e <> semi)  inst_ (CondAssignment id_ ty scrut _ [(Just (BoolLit b), l),(_,r)]) = fmap Just $ do@@ -868,6 +895,9 @@ inst_ (ConditionalDecl cond ds) = Just <$>   "`ifdef" <+> pretty cond <> line <> indent 2 (insts ds) <> line <> "`endif" +inst_ d =+  error ("inst_: " ++ show d)+ -- | Render a data constructor application for data constructors having a -- custom bit representation. customReprDataCon@@ -952,8 +982,9 @@           "end") <:> conds es'  seq_ (SeqDecl sd) = case sd of-  Assignment id_ e ->-    pretty id_ <+> equals <+> expr_ False e <> semi+  Assignment id_ (Proc b) e ->+    let sym = case b of { Blocking -> equals; NonBlocking -> "<=" }+     in pretty id_ <+> sym <+> expr_ False e <> semi    BlackBoxD {} ->     fromMaybe <$> emptyDoc <*> inst_ sd@@ -1116,10 +1147,10 @@  expr_ _ (DataCon ty@(Vector 0 _) _ _) = verilogTypeErrValue ty -expr_ _ (DataCon (Vector 1 elTy) _ [e]) = "'" <> braces (toSLV elTy e)+expr_ _ (DataCon (Vector 1 elTy) _ [e]) = "'" <> braces (int 0 <> colon <+> toSLV elTy e)  expr_ _ e@(DataCon ty@(Vector _ elTy) _ [e1,e2]) = case vectorChain e of-  Just es -> "'" <> listBraces (mapM (toSLV elTy) es)+  Just es -> "'" <> listBraces (zipWithM (\i e3 -> int i <> colon <+> toSLV elTy e3) [0..] es)   Nothing -> verilogTypeMark ty <> "_cons" <> parens (expr_ False e1 <> comma <+> expr_ False e2)  expr_ _ (DataCon (MemBlob n m) _ [n0, m0, _, runs, _, ends])@@ -1190,9 +1221,9 @@ expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.BitVector.fromInteger##"   , [Literal _ m, Literal _ i] <- extractLiterals bbCtx-  = let NumLit m' = m-        NumLit i' = i-    in exprLitSV (Just (Bit,1)) (BitLit $ toBit m' i')+  , NumLit m' <- m+  , NumLit i' <- i+  = exprLitSV (Just (Bit,1)) (BitLit $ toBit m' i')  expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.Index.fromInteger#"
src/Clash/Backend/VHDL.hs view
@@ -1,7 +1,8 @@ {-|   Copyright   :  (C) 2015-2016, University of Twente,                      2017-2018, Google Inc.,-                     2021-2022, QBayLogic B.V.+                     2021-2023, QBayLogic B.V.+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -20,7 +21,9 @@ module Clash.Backend.VHDL (VHDLState) where  import           Control.Arrow                        (second)+#if !MIN_VERSION_base(4,18,0) import           Control.Applicative                  (liftA2)+#endif import           Control.Lens                         hiding (Indexed, Empty) import           Control.Monad                        (forM,join,zipWithM) import           Control.Monad.State                  (State, StateT)@@ -35,7 +38,7 @@ import           Data.HashSet                         (HashSet) import qualified Data.HashSet                         as HashSet import           Data.List-  (mapAccumL, nub, nubBy, intersperse, group, sort)+  (mapAccumL, nub, nubBy, partition, intersperse, group, sort) import           Data.List.Extra                      ((<:>), equalLength, zipEqual) import           Data.Maybe                           (catMaybes,mapMaybe) import           Data.Monoid                          (Ap(Ap))@@ -62,8 +65,8 @@   (bitsToBits) import           Clash.Annotations.BitRepresentation.Util   (BitOrigin(Lit, Field), bitOrigins, bitRanges)+import           Clash.Annotations.SynthesisAttributes (Attr(..)) import           Clash.Backend-import           Clash.Core.Var                       (Attr'(..),attrName) import           Clash.Debug                          (traceIf) import           Clash.Driver.Types                   (ClashOpts(..)) import           Clash.Explicit.BlockRam.Internal     (unpackNats)@@ -71,7 +74,7 @@ import           Clash.Netlist.BlackBox.Util   (extractLiterals, renderBlackBox, renderFilePath) import qualified Clash.Netlist.Id                     as Id-import           Clash.Netlist.Types                  hiding (intWidth)+import           Clash.Netlist.Types                  hiding (intWidth, usages, _usages) import           Clash.Netlist.Util import           Clash.Util   (SrcSpan, noSrcSpan, clogBase, curLoc, makeCached, indexNote)@@ -115,6 +118,7 @@   , _aggressiveXOptBB_ :: AggressiveXOptBB   , _renderEnums_ :: RenderEnums   , _domainConfigurations_ :: DomainMap+  , _usages :: UsageMap   }  makeLenses ''VHDLState@@ -122,6 +126,9 @@ instance HasIdentifierSet VHDLState where   identifierSet = idSeen +instance HasUsageMap VHDLState where+  usageMap = usages+ instance Backend VHDLState where   initBackend opts = VHDLState     { _tyCache=mempty@@ -144,6 +151,7 @@     , _aggressiveXOptBB_=coerce (opt_aggressiveXOptBB opts)     , _renderEnums_=coerce (opt_renderEnums opts)     , _domainConfigurations_=emptyDomainMap+    , _usages=mempty     }   hdlKind         = const VHDL   primDirs        = const $ do root <- primsRoot@@ -169,6 +177,7 @@       if enums then pure UserType else pure SynonymType      Clock {} -> pure SynonymType+    ClockN {} -> pure SynonymType     Reset {} -> pure SynonymType     Enable {} -> pure SynonymType     Index {} -> pure SynonymType@@ -242,20 +251,28 @@   blockDecl nm ds = do     decs <- decls ds     let attrs = [ (id_, attr)-                | NetDecl' _ _ id_ (Right hwtype) _ <- ds+                | NetDecl' _ id_ hwtype _ <- ds                 , attr <- hwTypeAttrs hwtype]     if isEmpty decs-       then insts ds+       then insts ids        else nest 2               (pretty nm <+> colon <+> "block" <> line <>                pure decs <>-               if null attrs+               (if null attrs                 then emptyDoc-                else line <> line <> renderAttrs (TextS.pack "signal") attrs) <> line <>-            nest 2-              ("begin" <> line <>-                insts ds) <> line <>+                else line <> line <> renderAttrs (TextS.pack "signal") attrs) <>+               if null cds+                then emptyDoc+                else line <> line <> insts cds) <> line <> "begin" <>+            nest 2 (line <> insts ids)+            <> line <>             "end block" <> semi+   where+     (cds, ids) = partition isCompDecl ds++     isCompDecl (CompDecl {}) = True+     isCompDecl _             = False+   addIncludes inc = includes %= (inc++)   addLibraries libs = libraries %= (libs ++)   addImports imps = packages %= (imps ++)@@ -282,7 +299,7 @@  -- | Generate unique (partial) names for product fields. Example: ----- >>> productFieldNames [Unsigned 6, Unsigned 6, Bit, Bool]+-- > productFieldNames Nothing [Unsigned 6, Unsigned 6, Bit, Bool] -- ["unsigned6_0", "unsigned6_1", "bit", "boolean"] productFieldNames   :: HasCallStack@@ -296,7 +313,9 @@   hFields <- zipWithM hName labels1 fields    let grouped = group $ sort $ hFields-      counted = HashMapS.fromList (map (\(g:gs) -> (g, succ (length gs))) grouped)+      countGroup [] = error "productFIeldNames.countGroup: group of zero elements"+      countGroup (g:gs) = (g, succ (length gs))+      counted = HashMapS.fromList (map countGroup grouped)       names   = snd $ mapAccumL (name' counted) HashMapS.empty hFields    return names@@ -373,20 +392,24 @@  -- | Generate VHDL for a Netlist component genVHDL-  :: ModName+  :: ClashOpts+  -> ModName   -> SrcSpan   -> IdentifierSet+  -> UsageMap   -> Component   -> VHDLM ((String, Doc), [(String, Doc)])-genVHDL nm sp seen c = do+genVHDL _ nm sp seen us c = do     -- Don't have type names conflict with module names or with previously     -- generated type names.     --     -- TODO: Collect all type names up front, to prevent relatively costly union.     -- TODO: Investigate whether type names / signal names collide in the first place-    Ap $ idSeen %= Id.union seen+    Ap $ do+      idSeen %= Id.union seen+      usages .= us+      setSrcSpan sp -    Ap $ setSrcSpan sp     v <- vhdl     i <- Ap $ use includes     Ap $ libraries .= []@@ -579,6 +602,7 @@      -- Type aliases:     Clock _           -> typAliasDec hwty+    ClockN _          -> typAliasDec hwty     Reset _           -> typAliasDec hwty     Enable _          -> typAliasDec hwty     Index _           -> typAliasDec hwty@@ -721,8 +745,9 @@                             parens ("p." <> tyName t <> selectProductField labels elTys i))      argLengths = map typeSize elTys-    starts     = 0 : snd (mapAccumL ((join (,) .) . (+)) 0 argLengths)-    ends       = map (subtract 1) (tail starts)+    starts1    = snd (mapAccumL ((join (,) .) . (+)) 0 argLengths)+    starts     = 0 : starts1+    ends       = map (subtract 1) starts1      elTyFromSLV = forM (zip starts ends)                        (\(s,e) -> "fromSLV" <>@@ -940,7 +965,7 @@     rattrs      = renderAttrs (TextS.pack "signal") attrs     attrs       = inputAttrs ++ outputAttrs     inputAttrs  = [(id_, attr) | (id_, hwtype) <- inputs c, attr <- hwTypeAttrs hwtype]-    outputAttrs = [(id_, attr) | (_wireOrReg, (id_, hwtype), _) <- outputs c, attr <- hwTypeAttrs hwtype]+    outputAttrs = [(id_, attr) | (_, (id_, hwtype), _) <- outputs c, attr <- hwTypeAttrs hwtype]   architecture :: Component -> VHDLM Doc@@ -961,46 +986,52 @@   }  where    netdecls    = filter isNetDecl (declarations c)-   declAttrs   = [(id_, attr) | NetDecl' _ _ id_ (Right hwtype) _ <- netdecls, attr <- hwTypeAttrs hwtype]+   declAttrs   = [(id_, attr) | NetDecl' _ id_ hwtype _ <- netdecls, attr <- hwTypeAttrs hwtype]    inputAttrs  = [(id_, attr) | (id_, hwtype) <- inputs c, attr <- hwTypeAttrs hwtype]-   outputAttrs = [(id_, attr) | (_wireOrReg, (id_, hwtype), _) <- outputs c, attr <- hwTypeAttrs hwtype]+   outputAttrs = [(id_, attr) | (_, (id_, hwtype), _) <- outputs c, attr <- hwTypeAttrs hwtype]     isNetDecl :: Declaration -> Bool-   isNetDecl (NetDecl' _ _ _ (Right _) _) = True-   isNetDecl _                            = False+   isNetDecl NetDecl'{} = True+   isNetDecl _          = False -attrType-  :: t ~ HashMap T.Text T.Text-  => t-  -> Attr'-  -> t+attrType ::+  HashMap TextS.Text TextS.Text ->+  Attr TextS.Text ->+  HashMap TextS.Text TextS.Text attrType types attr =   case HashMap.lookup name' types of     Nothing    -> HashMap.insert name' type' types     Just type'' | type'' == type' -> types                 | otherwise -> error $-                      $(curLoc) ++ unwords [ T.unpack name', "already assigned"-                                           , T.unpack type'', "while we tried to"-                                           , "add", T.unpack type' ]+                      $(curLoc) ++ unwords [ TextS.unpack name', "already assigned"+                                           , TextS.unpack type'', "while we tried to"+                                           , "add", TextS.unpack type' ]  where-  name' = T.pack $ attrName attr-  type' = T.pack $ case attr of-            BoolAttr' _ _    -> "boolean"-            IntegerAttr' _ _ -> "integer"-            StringAttr' _ _  -> "string"-            Attr' _          -> "bool"+  name' = attrName attr+  type' = case attr of+            BoolAttr _ _    -> "boolean"+            IntegerAttr _ _ -> "integer"+            StringAttr _ _  -> "string"+            Attr _          -> "boolean" +attrName :: Attr a -> a+attrName = \case+  BoolAttr a _ -> a+  IntegerAttr a _ -> a+  StringAttr a _ -> a+  Attr a -> a+ -- | Create 'attrname -> type' mapping for given attributes. Will err if multiple -- types are assigned to the same name.-attrTypes :: [Attr'] -> HashMap T.Text T.Text+attrTypes :: [Attr TextS.Text] -> HashMap TextS.Text TextS.Text attrTypes = foldl attrType HashMap.empty  -- | Create a 'attrname -> (type, [(signalname, value)]). Will err if multiple -- types are assigned to the same name. attrMap   :: forall t-   . t ~ HashMap T.Text (T.Text, [(TextS.Text, T.Text)])-  => [(Identifier, Attr')]+   . t ~ HashMap TextS.Text (TextS.Text, [(TextS.Text, TextS.Text)])+  => [(Identifier, Attr TextS.Text)]   -> t attrMap attrs0 = foldl go empty' attrs1  where@@ -1010,56 +1041,57 @@            [(k, (types HashMap.! k, [])) | k <- HashMap.keys types]   types = attrTypes (map snd attrs1) -  go :: t -> (TextS.Text, Attr') -> t-  go map' attr = HashMap.adjust-                   (go' attr)-                   (T.pack $ attrName $ snd attr)-                   map'+  go :: t -> (TextS.Text, Attr TextS.Text) -> t+  go map' attr = HashMap.adjust (go' attr) (attrName $ snd attr) map'    go'-    :: (TextS.Text, Attr')-    -> (T.Text, [(TextS.Text, T.Text)])-    -> (T.Text, [(TextS.Text, T.Text)])+    :: (TextS.Text, Attr TextS.Text)+    -> (TextS.Text, [(TextS.Text, TextS.Text)])+    -> (TextS.Text, [(TextS.Text, TextS.Text)])   go' (signalName, attr) (typ, elems) =     (typ, (signalName, renderAttr attr) : elems)  renderAttrs   :: TextS.Text-  -> [(Identifier, Attr')]+  -> [(Identifier, Attr TextS.Text)]   -> VHDLM Doc renderAttrs what (attrMap -> attrs) =   vcat $ sequence $ intersperse " " $ map renderAttrGroup (HashMap.toList attrs)  where   renderAttrGroup-    :: (T.Text, (T.Text, [(TextS.Text, T.Text)]))+    :: (TextS.Text, (TextS.Text, [(TextS.Text, TextS.Text)]))     -> VHDLM Doc   renderAttrGroup (attrname, (typ, elems)) =-    ("attribute" <+> string attrname <+> colon <+> string typ <> semi)+    ("attribute" <+> stringS attrname <+> colon <+> stringS typ <> semi)     <> line <>     (vcat $ sequence $ map (renderAttrDecl attrname) elems)    renderAttrDecl-    :: T.Text-    -> (TextS.Text, T.Text)+    :: TextS.Text+    -> (TextS.Text, TextS.Text)     -> VHDLM Doc   renderAttrDecl attrname (signalName, value) =         "attribute"-    <+> string attrname+    <+> stringS attrname     <+> "of"     <+> stringS signalName -- or component name     <+> colon     <+> stringS what <+> "is" -- "signal is" or "component is"-    <+> string value+    <+> stringS value     <> semi  -- | Convert single attribute to VHDL syntax-renderAttr :: Attr' -> T.Text-renderAttr (StringAttr'  _key value) = T.replace "\\\"" "\"\"" $ T.pack $ show value-renderAttr (IntegerAttr' _key value) = T.pack $ show value-renderAttr (BoolAttr'    _key True ) = T.pack $ "true"-renderAttr (BoolAttr'    _key False) = T.pack $ "false"-renderAttr (Attr'        _key      ) = T.pack $ "true"+renderAttr :: Attr TextS.Text -> TextS.Text+renderAttr (StringAttr  _key value) = wrap '"' $ TextS.replace "\"" "\"\"" value+renderAttr (IntegerAttr _key value) = TextS.pack (show value)+renderAttr (BoolAttr    _key True ) = "true"+renderAttr (BoolAttr    _key False) = "false"+renderAttr (Attr        _key      ) = "true" +-- | Prepend and append a character to a string+wrap :: Char -> TextS.Text -> TextS.Text+wrap c = cons c . (`snoc` c)+ sigDecl :: VHDLM Doc -> HWType -> VHDLM Doc sigDecl d t = d <+> colon <+> sizedQualTyName t @@ -1173,6 +1205,9 @@     Clock nm0 ->       let nm1 = "clk_" `TextS.append` nm0 in       Ap $ makeCached (t, False) nameCache (userTyName "clk" nm1 t)+    ClockN nm0 ->+      let nm1 = "clk_n_" `TextS.append` nm0 in+      Ap $ makeCached (t, False) nameCache (userTyName "clk" nm1 t)     Reset nm0 ->       let nm1 = "rst_" `TextS.append` nm0 in       Ap $ makeCached (t, False) nameCache (userTyName "rst" nm1 t)@@ -1225,6 +1260,7 @@    -- Simple types, for which a subtype (without qualifiers) will be made in VHDL:   Clock _           -> Bit+  ClockN _          -> Bit   Reset _           -> Bit   Enable _          -> Bool   Index _           -> Unsigned (typeSize hwty)@@ -1248,6 +1284,7 @@   Integer           -> hwty   Bit               -> hwty   Clock _           -> hwty+  ClockN _          -> hwty   Reset _           -> hwty   Enable _          -> hwty   Index _           -> hwty@@ -1275,8 +1312,8 @@       (map (second filterTransparent) constrs)    -- Transparent types:-  Annotated _ elTy -> elTy-  BiDirectional _ elTy -> elTy+  Annotated _ elTy -> filterTransparent elTy+  BiDirectional _ elTy -> filterTransparent elTy    Void {} -> hwty   KnownDomain {} -> hwty@@ -1326,6 +1363,7 @@   else     qualTyName t <> "'" <> parens (int 0 <+> "to" <+> int (typeSize t - 1) <+> rarrow <+> singularErrValue) sizedQualTyNameErrValue (Clock _)  = singularErrValue+sizedQualTyNameErrValue (ClockN _) = singularErrValue sizedQualTyNameErrValue (Reset _)  = singularErrValue sizedQualTyNameErrValue (Enable _) = singularErrValue sizedQualTyNameErrValue (Void {})  =@@ -1360,8 +1398,8 @@       _  -> vcat (pure dsDoc)  decl :: Int ->  Declaration -> VHDLM (Maybe (Doc,Int))-decl l (NetDecl' noteM _ id_ ty iEM) = Just <$> (,fromIntegral (TextS.length (Id.toText id_))) <$>-  maybe id addNote noteM ("signal" <+> fill l (pretty id_) <+> colon <+> either pretty sizedQualTyName ty <> iE <> semi)+decl l (NetDecl' noteM id_ ty iEM) = Just <$> (,fromIntegral (TextS.length (Id.toText id_))) <$>+  maybe id addNote noteM ("signal" <+> fill l (pretty id_) <+> colon <+> sizedQualTyName ty <> iE <> semi)   where     addNote n = mappend ("--" <+> pretty n <> line)     iE = maybe emptyDoc (noEmptyInit . expr_ False) iEM@@ -1384,7 +1422,9 @@     portDir In  = "in"     portDir Out = "out" -    attrs' = if null attrs then emptyDoc else renderAttrs (TextS.pack "component") [(nm, a) | a <- attrs]+    attrs'+      | null attrs = emptyDoc+      | otherwise = renderAttrs (TextS.pack "component") [(nm, a) | a <- attrs]  decl _ _ = return Nothing @@ -1479,9 +1519,16 @@  -- | Turn a Netlist Declaration to a VHDL concurrent block inst_ :: Declaration -> VHDLM (Maybe Doc)-inst_ (Assignment id_ e) = fmap Just $+inst_ (Assignment id_ Cont e) = fmap Just $   pretty id_ <+> larrow <+> align (expr_ False e) <> semi +inst_ (CompDecl nm ps0) =+  fmap Just $ "component" <+> pretty nm <+>+    ("port" <> line <> indent 2 (tupledSemi ps <> semi))+    <> line <> "end component" <> semi+  where ps = traverse (\(t,pd,ty) -> pretty t <+> ":" <+> ppd pd <+> sizedQualTyName ty) ps0+        ppd = \case { In -> "in"; Out -> "out"}+ inst_ (CondAssignment id_ _ scrut _ [(Just (BoolLit b), l),(_,r)]) = fmap Just $   pretty id_ <+> larrow            <+> align (vsep (sequence [expr_ False t <+> "when" <+>@@ -1706,16 +1753,16 @@ expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.BitVector.fromInteger#"   , [Literal _ (NumLit n), Literal _ m, Literal _ i] <- extractLiterals bbCtx-  = let NumLit m' = m-        NumLit i' = i-    in exprLit (Just (BitVector (fromInteger n),fromInteger n)) (BitVecLit m' i')+  , NumLit m' <- m+  , NumLit i' <- i+  = exprLit (Just (BitVector (fromInteger n),fromInteger n)) (BitVecLit m' i')  expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.BitVector.fromInteger##"   , [Literal _ m, Literal _ i] <- extractLiterals bbCtx-  = let NumLit m' = m-        NumLit i' = i-    in exprLit (Just (Bit,1)) (BitLit $ toBit m' i')+  , NumLit m' <- m+  , NumLit i' <- i+  = exprLit (Just (Bit,1)) (BitLit $ toBit m' i')  expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.Index.fromInteger#"@@ -1890,9 +1937,9 @@ bits = dquotes . hcat . mapM bit_char  toHex :: Int -> Integer -> String-toHex sz i =-  let Just d = clogBase 16 (2^sz)-  in  printf ("%0" ++ show d ++ "X") (abs i)+toHex sz i = case clogBase 16 (2^sz) of+  Just d -> printf ("%0" ++ show d ++ "X") (abs i)+  _ -> error "toHex: impossible"  hex :: String -> VHDLM Doc hex s = char 'x' <> dquotes (pretty (T.pack s))@@ -1905,7 +1952,7 @@   case udf of     Nothing -> char '-'     Just Nothing -> char '0'-    Just (Just i) -> "'" <> int i <> "'"+    Just (Just i) -> int i bit_char Z = char 'Z'  toSLV :: HasCallStack => HWType -> Expr -> VHDLM Doc@@ -1918,6 +1965,9 @@ toSLV (Clock {})    e = do   nm <- Ap $ use modNm   pretty nm <> "_types.toSLV" <> parens (expr_ False e)+toSLV (ClockN {})   e = do+  nm <- Ap $ use modNm+  pretty nm <> "_types.toSLV" <> parens (expr_ False e) toSLV (Reset {})    e = do   nm <- Ap $ use modNm   pretty (TextS.toLower nm) <> "_types.toSLV" <> parens (expr_ False e)@@ -2004,6 +2054,7 @@  encodingNote :: HWType -> VHDLM Doc encodingNote (Clock _)  = "-- clock" <> line+encodingNote (ClockN _) = "-- clock (neg phase)" <> line encodingNote (Reset _)  = "-- reset" <> line encodingNote (Enable _) = "-- enable" <> line encodingNote (Annotated _ t) = encodingNote t
src/Clash/Backend/Verilog.hs view
@@ -1,7 +1,8 @@ {-|   Copyright   :  (C) 2015-2016, University of Twente,                      2017-2018, Google Inc.,-                     2021-2022, QBayLogic B.V.+                     2021-2023, QBayLogic B.V.+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -64,8 +65,9 @@   (ConstrRepr'(..), DataRepr'(..), ConstrRepr'(..)) import           Clash.Annotations.BitRepresentation.Util   (BitOrigin(Lit, Field), bitOrigins, bitRanges)-import           Clash.Core.Var                       (Attr'(..))+import           Clash.Annotations.SynthesisAttributes (Attr(..)) import           Clash.Backend+import           Clash.Backend.Verilog.Time           (periodToString) import           Clash.Debug                          (traceIf) import           Clash.Driver.Types                   (ClashOpts(..)) import           Clash.Explicit.BlockRam.Internal     (unpackNats)@@ -73,7 +75,7 @@ import           Clash.Netlist.BlackBox.Util   (extractLiterals, renderBlackBox, renderFilePath) import qualified Clash.Netlist.Id                     as Id-import           Clash.Netlist.Types                  hiding (intWidth)+import           Clash.Netlist.Types as N             hiding (intWidth, usages, _usages) import           Clash.Netlist.Util import           Clash.Signal.Internal                (ActiveEdge (..)) import           Clash.Util@@ -101,6 +103,7 @@     , _undefValue :: Maybe (Maybe Int)     , _aggressiveXOptBB_ :: AggressiveXOptBB     , _domainConfigurations_ :: DomainMap+    , _usages :: UsageMap     }  makeLenses ''VerilogState@@ -108,6 +111,9 @@ instance HasIdentifierSet VerilogState where   identifierSet = idSeen +instance HasUsageMap VerilogState where+  usageMap = usages+ instance Backend VerilogState where   initBackend opts = VerilogState     { _genDepth=0@@ -125,6 +131,7 @@     , _undefValue=opt_forceUndefined opts     , _aggressiveXOptBB_=coerce (opt_aggressiveXOptBB opts)     , _domainConfigurations_=emptyDomainMap+    , _usages=mempty     }   hdlKind         = const Verilog   primDirs        = const $ do root <- primsRoot@@ -136,7 +143,7 @@   name            = const "verilog"   extension       = const ".v" -  genHDL          = const genVerilog+  genHDL          = genVerilog   mkTyPackage _ _ = return []   hdlType _       = verilogType   hdlHWTypeKind _ = pure PrimitiveType -- Everything is a bitvector!@@ -197,20 +204,25 @@  -- | Generate Verilog for a Netlist component genVerilog-  :: SrcSpan+  :: ClashOpts+  -> ModName+  -> SrcSpan   -> IdentifierSet+  -> UsageMap   -> Component   -> VerilogM ((String, Doc), [(String, Doc)])-genVerilog sp seen c = do+genVerilog opts  _ sp seen usage c = do     -- Don't have type names conflict with module names or with previously     -- generated type names.     --     -- TODO: Collect all type names up front, to prevent relatively costly union.     -- TODO: Investigate whether type names / signal names collide in the first place-    Ap $ idSeen %= Id.union seen+    Ap $ do+      idSeen %= Id.union seen+      usages .= usage+      setSrcSpan sp -    Ap (setSrcSpan sp)-    v    <- commentHeader <> line <> timescale <> line <> module_ c+    v    <- commentHeader <> line <> nettype <> line <> timescale <> line <> module_ c     incs <- Ap $ use includes     return ((TextS.unpack (Id.toText cName), v), incs)   where@@ -219,25 +231,76 @@          = "/* AUTOMATICALLY GENERATED VERILOG-2001 SOURCE CODE."       <> line <> "** GENERATED BY CLASH " <> string (Text.pack clashVer) <> ". DO NOT MODIFY."       <> line <> "*/"-    timescale = "`timescale 100fs/100fs"+    nettype = "`default_nettype none"+    timescale = "`timescale 100fs/" <> string (Text.pack precision)+    precision = periodToString (opt_timescalePrecision opts)  sigPort-  :: Maybe WireOrReg+  :: VerilogM Doc+  -> Maybe N.Usage   -> Identifier   -> HWType   -> Maybe Expr   -> VerilogM Doc-sigPort wor (Id.toText -> pName) hwType iEM =+sigPort def mu (Id.toText -> pName) hwType iEM = do     addAttrs (hwTypeAttrs hwType)       (portType <+> verilogType hwType <+> stringS pName <> iE <> encodingNote hwType)   where-    portType = case wor of-                 Nothing   -> if isBiSignalIn hwType then "inout" else "input"-                 Just Wire -> "output" <+> "wire"-                 Just Reg  -> "output" <+> "reg"+    portType =+      -- See NOTE [net and variable ports]+      case mu of+        Just Cont ->+          "output wire" +        Just Proc{} ->+          "output reg"++        Nothing ->+          if isBiSignalIn hwType then "inout wire" else def <+> "wire"+     iE = maybe emptyDoc (noEmptyInit . expr_ False) iEM +{-+NOTE [net and variable ports]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In Verilog, ports are typically seen written with the default implicit net type+of wire, i.e.++  input foo,+  output bar,++which is really a shorthand for++  input wire foo,+  output wire bar,++When we use `default_nettype none however, this is no longer allowed as all+nets must be explicitly given their type. When generating code we must include+the additional word wire (the net type).++What is the benefit of this? When we have a default net type, any variable+generated which is not declared is given an implicit declaration of this+default type. This can obscure clash errors, i.e. if Clash generated++  wire foo;+  fo <= ...;++Then simulators would act as though this was written:++  wire foo;+  wire fo;+  fo <= ...;++Which should never be the desired behaviour for code generated by Clash.++One final point, Verilog allows output to also be a variable type, i.e.++  output reg foo;++If a port is an input or an inout then it can only be a net and not a variable+according to the standard, so input reg and inout reg are impossible.+-}+ module_ :: Component -> VerilogM Doc module_ c =   modVerilog <* Ap (imports .= HashSet.empty >> libraries .= HashSet.empty)@@ -256,8 +319,11 @@     modBody    = indent 2 (decls (declarations c)) <> line <> line <> indent 2 (insts (declarations c))     modEnding  = "endmodule" -    inPorts  = sequence [ sigPort Nothing id_ hwType Nothing | (id_, hwType) <- inputs c  ]-    outPorts = sequence [ sigPort (Just wireOrReg) id_ hwType iEM | (wireOrReg, (id_, hwType), iEM) <- outputs c ]+    inPorts  = sequence [ sigPort "input" Nothing id_ hwType Nothing | (id_, hwType) <- inputs c  ]+    outPorts = do+      us <- use usages+      let useOf i u = lookupUsage i us <> Just u+      sequence [ sigPort "output" (useOf id_ u) id_ hwType iEM | (u,(id_, hwType), iEM) <- outputs c ]      -- slightly more readable than 'tupled', makes the output Haskell-y-er     commafy v = (comma <> space) <> pure v@@ -291,21 +357,23 @@   indent 2 (string "`uselib" <+> (hsep (mapM (\l -> ("lib=" <> string l)) xs)))   <> line <> line -wireRegFileDoc :: WireOrReg -> (Either a HWType) -> VerilogM Doc-wireRegFileDoc _    (Right FileType) = "integer"-wireRegFileDoc Wire _                = "wire"-wireRegFileDoc Reg  _                = "reg"+usageFileDoc :: Maybe N.Usage -> HWType -> VerilogM Doc+usageFileDoc _             FileType  = "integer"+usageFileDoc (Just Proc{}) _         = "reg"+usageFileDoc _             _         = "wire"  verilogType :: HWType -> VerilogM Doc verilogType t = case t of   Signed n -> "signed" <+> brackets (int (n-1) <> colon <> int 0)   Clock {} -> emptyDoc+  ClockN {} -> emptyDoc   Reset {} -> emptyDoc   Enable {} -> emptyDoc   Bit      -> emptyDoc   Bool     -> emptyDoc   FileType -> emptyDoc   Annotated _ ty -> verilogType ty+  BiDirectional _ ty -> verilogType ty   _        -> brackets (int (typeSize t -1) <> colon <> int 0)  sigDecl :: VerilogM Doc -> HWType -> VerilogM Doc@@ -342,31 +410,32 @@  -- | Add attribute notation to given declaration addAttrs-  :: [Attr']+  :: [Attr TextS.Text]   -> VerilogM Doc   -> VerilogM Doc addAttrs []     t = t addAttrs attrs' t =   "(*" <+> attrs'' <+> "*)" <+> t  where-  attrs'' = string $ Text.intercalate ", " (map renderAttr attrs')+  attrs'' = stringS $ TextS.intercalate ", " (map renderAttr attrs')  -- | Convert single attribute to verilog syntax-renderAttr :: Attr' -> Text.Text-renderAttr (StringAttr'  key value) = pack $ concat [key, " = ", show value]-renderAttr (IntegerAttr' key value) = pack $ concat [key, " = ", show value]-renderAttr (BoolAttr'    key True ) = pack $ concat [key, " = ", "1"]-renderAttr (BoolAttr'    key False) = pack $ concat [key, " = ", "0"]-renderAttr (Attr'        key      ) = pack $ key+renderAttr :: Attr TextS.Text -> TextS.Text+renderAttr (StringAttr  key value) = TextS.concat [key, " = ", TextS.pack (show value)]+renderAttr (IntegerAttr key value) = TextS.concat [key, " = ", TextS.pack (show value)]+renderAttr (BoolAttr    key True ) = TextS.concat [key, " = ", "1"]+renderAttr (BoolAttr    key False) = TextS.concat [key, " = ", "0"]+renderAttr (Attr        key      ) = key  decl :: Declaration -> VerilogM (Maybe Doc)-decl (NetDecl' noteM wr id_ tyE iEM) =-  Just A.<$> maybe id addNote noteM (addAttrs attrs (wireRegFileDoc wr tyE <+> tyDec tyE))+decl (NetDecl' noteM id_ tyE iEM) = do+  us <- use usages+  let u = lookupUsage id_ us+  Just A.<$> maybe id addNote noteM (addAttrs attrs (usageFileDoc u tyE <+> tyDec tyE))   where-    tyDec (Left  ty) = stringS ty <+> pretty id_ <> iE-    tyDec (Right ty) = sigDecl (pretty id_) ty <> iE+    tyDec ty = sigDecl (pretty id_) ty <> iE     addNote n = mappend ("//" <+> stringS n <> line)-    attrs = fromMaybe [] (hwTypeAttrs A.<$> either (const Nothing) Just tyE)+    attrs = fromMaybe [] (hwTypeAttrs A.<$> Just tyE)     iE    = maybe emptyDoc (noEmptyInit . expr_ False) iEM  decl _ = return Nothing@@ -471,7 +540,8 @@ -- | Turn a Netlist Declaration to a Verilog concurrent block inst_ :: Declaration -> VerilogM (Maybe Doc) inst_ (TickDecl {}) = return Nothing-inst_ (Assignment id_ e) = fmap Just $+inst_ (CompDecl {}) = return Nothing+inst_ (Assignment id_ Cont e) = fmap Just $   "assign" <+> pretty id_ <+> equals <+> expr_ False e <> semi  inst_ (CondAssignment id_ _ scrut _ [(Just (BoolLit b), l),(_,r)]) = fmap Just $@@ -535,6 +605,9 @@ inst_ (ConditionalDecl cond ds) = Just <$>   "`ifdef" <+> pretty cond <> line <> indent 2 (insts ds) <> line <> "`endif" +inst_ d =+  error ("inst_: " ++ show d)+ seq_ :: Seq -> VerilogM Doc seq_ (AlwaysClocked edge clk ds) =   "always @" <>@@ -575,8 +648,9 @@       "end") <:> conds es'  seq_ (SeqDecl sd) = case sd of-  Assignment id_ e ->-    pretty id_ <+> equals <+> expr_ False e <> semi+  Assignment id_ (Proc b) e ->+    let op = case b of { Blocking -> equals; NonBlocking -> "<=" }+     in pretty id_ <+> op <+> expr_ False e <> semi    BlackBoxD {} ->     fromMaybe <$> emptyDoc <*> inst_ sd@@ -1060,16 +1134,16 @@ expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.BitVector.fromInteger#"   , [Literal _ (NumLit n), Literal _ m, Literal _ i] <- extractLiterals bbCtx-  = let NumLit m' = m-        NumLit i' = i-    in exprLitV (Just (BitVector (fromInteger n),fromInteger n)) (BitVecLit m' i')+  , NumLit m' <- m+  , NumLit i' <- i+  = exprLitV (Just (BitVector (fromInteger n),fromInteger n)) (BitVecLit m' i')  expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.BitVector.fromInteger##"   , [Literal _ m, Literal _ i] <- extractLiterals bbCtx-  = let NumLit m' = m-        NumLit i' = i-    in exprLitV (Just (Bit,1)) (BitLit $ toBit m' i')+  , NumLit m' <- m+  , NumLit i' <- i+  = exprLitV (Just (Bit,1)) (BitLit $ toBit m' i')  expr_ _ (BlackBoxE pNm _ _ _ _ bbCtx _)   | pNm == "Clash.Sized.Internal.Index.fromInteger#"@@ -1192,10 +1266,9 @@   udf <- Ap (use k)   case (udf,b) of     (Just Nothing,U)  -> char '0'-    (Just (Just i),U) -> "'" <> int i <> "'"+    (Just (Just i),U) -> int i     _                 -> char (bit_char' b) - dcToExpr :: HWType -> Int -> Expr dcToExpr ty i = Literal (Just (ty,conSize ty)) (NumLit (toInteger i)) @@ -1211,6 +1284,7 @@  encodingNote :: Applicative m => HWType -> m Doc encodingNote (Clock _) = string " // clock"+encodingNote (ClockN _) = string " // clock (neg phase)" encodingNote (Reset _) = string " // reset" encodingNote (Enable _) = string " // enable" encodingNote (Annotated _ t) = encodingNote t
+ src/Clash/Backend/Verilog/Time.hs view
@@ -0,0 +1,127 @@+{-|+Copyright  :  (C) 2022,      Google Inc.,+License    :  BSD2 (see the file LICENSE)+Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>++Utilities and definitions to deal with Verilog's time unit. These definitions+are here mostly to deal with varying @`timescale@ defintions, see:++  https://www.chipverify.com/verilog/verilog-timescale++-}++{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TypeFamilies #-}++module Clash.Backend.Verilog.Time where++import Clash.Class.HasDomain.HasSingleDomain+  (TryDomain, TryDomainResult(NotFound))++import Control.DeepSeq (NFData)+import Data.Char (toLower, isDigit)+import Data.Hashable (Hashable)+import Data.List (find)+import Data.Word (Word64)+import GHC.Generics (Generic)+import Text.Read (readMaybe)++-- | Verilog time units+data Unit = Fs | Ps | Ns | Us | Ms | S+  deriving (Show, Enum, Bounded, Eq, Ord, Generic, Hashable, NFData)++type instance TryDomain t Unit = 'NotFound++-- | Verilog time period. A combination of a length and a unit.+data Period = Period Word64 Unit+  deriving (Show, Generic, Hashable, Eq, NFData)++-- | Verilog timescale. Influences simulation precision.+data Scale = Scale+  { -- | Time step in wait statements, e.g. `#1`.+    step :: Period++    -- | Simulator precision - all units will get rounded to this period.+  , precision :: Period+  }+  deriving (Show, Generic, Hashable, Eq, NFData)++-- | Pretty print 'Scale' to Verilog `timescale+--+-- >>> scaleToString (Scale (Period 100 Ps) (Period 10 Fs))+-- "`timescale 100ps/10fs"+--+scaleToString :: Scale -> String+scaleToString (Scale{step, precision}) =+  "`timescale " <> periodToString step <> "/" <> periodToString precision++-- | Convert 'Unit' to Verilog time unit+--+-- >>> periodToString (Period 100 Fs)+-- "100fs"+--+periodToString :: Period -> String+periodToString (Period len unit) = show len <> unitToString unit++-- | Convert 'Unit' to Verilog time unit+--+-- >>> unitToString Ms+-- "ms"+--+unitToString :: Unit -> String+unitToString = map toLower . show++-- | Parse string representing a Verilog time unit to 'Unit'.+--+-- >>> parseUnit "ms"+-- Just Ms+-- >>> parseUnit "xs"+-- Nothing+--+parseUnit :: String -> Maybe Unit+parseUnit s = find tryUnit [minBound..]+ where+  tryUnit :: Unit -> Bool+  tryUnit u = unitToString u == s++-- | Parse a Verilog+--+-- >>> parsePeriod "100ms"+-- Just (Period 100 Ms)+-- >>> parsePeriod "100xs"+-- Nothing+-- >>> parsePeriod "100"+-- Nothing+-- >>> parsePeriod "ms"+-- Nothing+--+parsePeriod :: String -> Maybe Period+parsePeriod s =+  case span isDigit s of+    (len0, unit0) -> do+      len1 <- readMaybe len0+      unit1 <- parseUnit unit0+      pure (Period len1 unit1)++-- | Convert a period to a specific time unit. Will always output a minimum+-- of 1, even if the given 'Period' is already of the right 'Unit'.+--+-- >>> convertUnit Ps (Period 100 Ps)+-- 100+-- >>> convertUnit Fs (Period 100 Ps)+-- 100000+-- >>> convertUnit Ns (Period 100 Ps)+-- 1+-- >>> convertUnit Ms (Period 0 Ms)+-- 1+--+convertUnit :: Unit -> Period -> Word64+convertUnit targetUnit = go+ where+  go (Period len unit) =+    case compare unit targetUnit of+      LT -> go (Period (len `div` 1000) (succ unit))+      EQ -> max 1 len+      GT -> go (Period (len * 1000) (pred unit))
src/Clash/Core/Evaluator/Types.hs view
@@ -38,6 +38,7 @@ whnf'   :: Evaluator   -> BindingMap+  -> VarEnv Term   -> TyConMap   -> PrimHeap   -> Supply@@ -45,12 +46,12 @@   -> Bool   -> Term   -> (PrimHeap, PureHeap, Term)-whnf' eval bm tcm ph ids is isSubj e =+whnf' eval bm lh tcm ph ids is isSubj e =   toResult $ whnf eval tcm isSubj m  where   toResult x = (mHeapPrim x, mHeapLocal x, mTerm x) -  m  = Machine ph gh emptyVarEnv [] ids is e+  m  = Machine ph gh lh [] ids is e   gh = mapVarEnv bindingTerm bm  -- | Evaluate to WHNF given an existing Heap and Stack@@ -314,9 +315,19 @@ forcePrims :: Machine -> Bool forcePrims = go . mStack  where+  -- When do we need to force the compile-time evaluation of a primitive?+  --+  -- 1. When they are the subject of a case-expression   go (Scrutinise{}:_) = True+  -- 2. When they are in the argument position of another primitive:+  --    primitives are assumed to be strict in their arguments   go (PrimApply{}:_)  = True+  -- We look through ticks   go (Tickish{}:xs)   = go xs+  -- We are in a context where we dereferenced a heap-binding, hence the+  -- update fram on the stack. So now we need to check whether that variable+  -- reference was in a position where the result must be evaluated to WHNF+  go (Update{}:xs)    = go xs   go _                = False  primCount :: Machine -> Int
src/Clash/Core/HasType.hs view
@@ -22,8 +22,6 @@   , piResultTys   ) where -import qualified Data.Text as Text (isInfixOf)- #if MIN_VERSION_prettyprinter(1,7,0) import Prettyprinter (line) #else@@ -35,17 +33,16 @@ import Clash.Core.DataCon (DataCon(dcType)) import Clash.Core.HasFreeVars import Clash.Core.Literal (Literal(..))-import Clash.Core.Name (Name(nameOcc)) import Clash.Core.Pretty import Clash.Core.Subst import Clash.Core.Term (Term(..), IsMultiPrim(..), PrimInfo(..), collectArgs)-import Clash.Core.TyCon (TyCon(tyConKind), TyConMap)+import Clash.Core.TyCon (TyCon(tyConKind), TyConMap, isTupleTyConLike) import Clash.Core.Type import Clash.Core.TysPrim import Clash.Core.Var (Var(varType)) import Clash.Core.VarEnv+import qualified Clash.Data.UniqMap as UniqMap import Clash.Debug (debugIsOn)-import Clash.Unique (lookupUniqMap') import Clash.Util (curLoc, pprPanic) import qualified Clash.Util.Interpolate as I @@ -70,6 +67,14 @@     CharLiteral _ -> charPrimTy     Int64Literal _ -> int64PrimTy     Word64Literal _ -> word64PrimTy+#if MIN_VERSION_ghc(8,8,0)+    Int8Literal _ -> int8PrimTy+    Int16Literal _ -> int16PrimTy+    Int32Literal _ -> int32PrimTy+    Word8Literal _ -> word8PrimTy+    Word16Literal _ -> word16PrimTy+    Word32Literal _ -> word32PrimTy+#endif     NaturalLiteral _ -> naturalPrimTy     ByteArrayLiteral _ -> byteArrayPrimTy @@ -82,7 +87,7 @@       MultiResult         | let (primArgs, primResTy) = splitFunForallTy (primType pr)         , TyConApp tupTcNm tupArgs <- tyView primResTy-        , Text.isInfixOf "GHC.Tuple.(" (nameOcc tupTcNm)+        , isTupleTyConLike tupTcNm         -> mkPolyFunTy primResTy (primArgs <> fmap Right tupArgs)          | otherwise@@ -111,7 +116,7 @@         liftedTypeKind        TyConApp tc args ->-        piResultTys tcm (tyConKind (lookupUniqMap' tcm tc)) args+        piResultTys tcm (tyConKind (UniqMap.find tc tcm)) args        OtherType{} ->         case ty of@@ -120,6 +125,7 @@           ForAllTy _ a -> inferCoreTypeOf tcm a           LitTy NumTy{} -> typeNatKind           LitTy SymTy{} -> typeSymbolKind+          LitTy CharTy{} -> charPrimTy           AnnType _ a -> inferCoreTypeOf tcm a           AppTy a b -> go a [b]            where
src/Clash/Core/Literal.hs view
@@ -9,6 +9,7 @@   Term Literal -} +{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -50,6 +51,14 @@   | WordLiteral     !Integer   | Int64Literal    !Integer   | Word64Literal   !Integer+#if MIN_VERSION_ghc(8,8,0)+  | Int8Literal     !Integer+  | Int16Literal    !Integer+  | Int32Literal    !Integer+  | Word8Literal    !Integer+  | Word16Literal   !Integer+  | Word32Literal   !Integer+#endif   | StringLiteral   !String   | FloatLiteral    !Word32   | DoubleLiteral   !Word64
src/Clash/Core/PartialEval/AsTerm.hs view
@@ -9,7 +9,6 @@ -}  {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}  module Clash.Core.PartialEval.AsTerm   ( AsTerm(..)
src/Clash/Core/PartialEval/NormalForm.hs view
@@ -12,9 +12,7 @@ -}  {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TemplateHaskell #-}  module Clash.Core.PartialEval.NormalForm   ( Arg
src/Clash/Core/Pretty.hs view
@@ -13,7 +13,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}  {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -224,11 +223,24 @@ dcolon, rarrow, lam, tylam, at, cast, coerce, let_, letrec, in_, case_, of_, forall_,   data_,newtype_,type_,family_,instance_   :: ClashDoc-[dcolon, rarrow, lam, tylam, at, cast, coerce, let_, letrec, in_, case_, of_, forall_,-  data_,newtype_,type_,family_,instance_]-  = annotate (AnnSyntax Keyword) <$>-    ["::", "->", "λ", "Λ", "@", "▷", "~", "let", "letrec", "in", "case", "of", "forall",-     "data","newtype","type","family","instance"]+dcolon = annotate (AnnSyntax Keyword) "::"+rarrow = annotate (AnnSyntax Keyword) "->"+lam = annotate (AnnSyntax Keyword)  "λ"+tylam = annotate (AnnSyntax Keyword) "Λ"+at = annotate (AnnSyntax Keyword)  "@"+cast = annotate (AnnSyntax Keyword) "▷"+coerce = annotate (AnnSyntax Keyword) "~"+let_ = annotate (AnnSyntax Keyword) "let"+letrec = annotate (AnnSyntax Keyword) "letrec"+in_ = annotate (AnnSyntax Keyword) "in"+case_ = annotate (AnnSyntax Keyword) "case"+of_ = annotate (AnnSyntax Keyword) "of"+forall_ = annotate (AnnSyntax Keyword) "forall"+data_ = annotate (AnnSyntax Keyword) "data"+newtype_ = annotate (AnnSyntax Keyword) "newtype"+type_ = annotate (AnnSyntax Keyword) "type"+family_ = annotate (AnnSyntax Keyword) "family"+instance_ = annotate (AnnSyntax Keyword) "instance"  instance PrettyPrec Text where   pprPrec _ = pure . pretty@@ -291,6 +303,7 @@ instance Pretty LitTy where   pretty (NumTy i) = pretty i   pretty (SymTy s) = dquotes $ pretty s+  pretty (CharTy c) = squotes $ pretty c  instance PrettyPrec LitTy where   pprPrec _ = return . annotate (AnnSyntax LitS) . pretty@@ -352,17 +365,19 @@  instance PrettyPrec Literal where   pprPrec _ l = return $ annotate (AnnSyntax LitS) $ case l of-    IntegerLiteral i-      | i < 0          -> parens (pretty i)-      | otherwise      -> pretty i-    IntLiteral i-      | i < 0          -> parens (pretty i <> "#")-      | otherwise      -> pretty i <> "#"-    Int64Literal i-      | i < 0          -> parens (pretty i <> "#")-      | otherwise      -> pretty i <> "#"+    IntegerLiteral i   -> parensIf (i < 0) (pretty i)+    IntLiteral i       -> parensIf (i < 0) (pretty i <> "#")+    Int64Literal i     -> parensIf (i < 0) (pretty i <> "#64")     WordLiteral w      -> pretty w <> "##"-    Word64Literal w    -> pretty w <> "##"+    Word64Literal w    -> pretty w <> "##64"+#if MIN_VERSION_ghc(8,8,0)+    Int8Literal i      -> parensIf (i < 0) (pretty i <> "#8")+    Int16Literal i     -> parensIf (i < 0) (pretty i <> "#16")+    Int32Literal i     -> parensIf (i < 0) (pretty i <> "#32")+    Word8Literal w     -> pretty w <> "##8"+    Word16Literal w    -> pretty w <> "##16"+    Word32Literal w    -> pretty w <> "##32"+#endif     FloatLiteral w     -> pretty (wordToFloat w) <> "#"     DoubleLiteral w    -> pretty (wordToDouble w) <> "##"     CharLiteral c      -> pretty c <> "#"@@ -440,7 +455,7 @@ pprPrecLetrec :: Monad m => Rational -> Bool -> [(Id, Term)] -> Term -> m ClashDoc pprPrecLetrec prec isRec xes body = do   let bndrs = fst <$> xes-  body' <- annotate (AnnContext $ LetBody bndrs) <$> pprPrec noPrec body+  body' <- annotate (AnnContext $ LetBody xes) <$> pprPrec noPrec body   xes'  <- mapM (\(x,e) -> do                   x' <- pprBndr LetBind x                   e' <- pprPrec noPrec e
src/Clash/Core/Subst.hs view
@@ -86,8 +86,8 @@ import           Clash.Core.Type           (Type (..)) import           Clash.Core.VarEnv import           Clash.Core.Var            (Id, Var (..), TyVar, isGlobalId)+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Debug               (debugIsOn)-import           Clash.Unique import           Clash.Util import           Clash.Pretty @@ -457,7 +457,7 @@        "needsInScope" <+> clashPretty needsInScope)   a  where-  needsInScope = foldrWithUnique (\k _ s -> delVarSetByKey k s)+  needsInScope = UniqMap.foldrWithUnique (\k _ s -> delVarSetByKey k s)                    (freeVarsOf tys)                    tenv   tysFVsInSope = needsInScope `varSetInScope` inScope@@ -968,10 +968,6 @@     Case {}    -> 11     Tick {}    -> 12 -thenCompare :: Ordering -> Ordering -> Ordering-thenCompare EQ rel = rel-thenCompare rel _  = rel- -- | Structural equality on 'Term' eqTerm :: Term -> Term -> Bool eqTerm = go@@ -1040,5 +1036,3 @@  instance Ord Term where   compare = acmpTerm--deriving instance Ord TickInfo
src/Clash/Core/Subst.hs-boot view
@@ -19,3 +19,4 @@   -> Bool  instance Eq Type+instance Ord Type
src/Clash/Core/Term.hs view
@@ -70,19 +70,19 @@ import Data.Text                               (Text) import GHC.Generics #if MIN_VERSION_ghc(9,0,0)-import GHC.Types.SrcLoc                        (SrcSpan)+import GHC.Types.SrcLoc                        (SrcSpan, leftmost_smallest) #else-import SrcLoc                                  (SrcSpan)+import SrcLoc                                  (SrcSpan, leftmost_smallest) #endif  -- Internal Modules import Clash.Core.DataCon                      (DataCon) import Clash.Core.Literal                      (Literal) import Clash.Core.Name                         (Name (..))-import {-# SOURCE #-} Clash.Core.Subst         () -- instance Eq Type+import {-# SOURCE #-} Clash.Core.Subst         () -- instance Eq/Ord Type import {-# SOURCE #-} Clash.Core.Type          (Type) import Clash.Core.Var                          (Var, Id, TyVar)-import Clash.Util                              (curLoc)+import Clash.Util                              (curLoc, thenCompare)  -- | Term representation in the CoreHW language: System F + LetRec + Case data Term@@ -124,6 +124,18 @@   -- do not try to share expressions between multiple branches.   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 t1 t2 = compare (getRank t1) (getRank t2)+    where+      getRank :: TickInfo -> Word+      getRank SrcSpan{} = 0+      getRank NameMod{} = 1+      getRank DeDup     = 2+      getRank NoDeDup   = 3+ -- | Tag to indicate which instance/register name modifier was used data NameMod   = PrefixName@@ -254,7 +266,7 @@   -- ^ Function position of a type application   | LetBinding Id [Id]   -- ^ RHS of a Let-binder with the sibling LHS'-  | LetBody [Id]+  | LetBody [LetBinding]   -- ^ Body of a Let-binding with the bound LHS'   | LamBody Id   -- ^ Body of a lambda-term with the abstracted variable@@ -291,7 +303,7 @@     -- NB: we do not see inside the argument here     (TyAppC,          TyAppC)            -> True     (LetBinding i is, LetBinding i' is') -> i == i' && is == is'-    (LetBody is,      LetBody is')       -> is == is'+    (LetBody is,      LetBody is')       -> map fst is == map fst is'     (LamBody i,       LamBody i')        -> i == i'     (TyLamBody tv,    TyLamBody tv')     -> tv == tv'     (CaseAlt p,       CaseAlt p')        -> p == p'
src/Clash/Core/TermInfo.hs view
@@ -6,16 +6,14 @@ module Clash.Core.TermInfo where  import Data.Maybe (fromMaybe)-import Data.Text (isInfixOf) import GHC.Stack (HasCallStack)  import Clash.Core.HasType-import Clash.Core.Name import Clash.Core.Term-import Clash.Core.TyCon (tyConDataCons, TyConMap)+import Clash.Core.TyCon (tyConDataCons, isTupleTyConLike, TyConMap) import Clash.Core.Type import Clash.Core.Var-import Clash.Unique (lookupUniqMap)+import qualified Clash.Data.UniqMap as UniqMap import Clash.Util.Interpolate as I  termSize :: Term -> Word@@ -70,8 +68,8 @@   | (_primArgs, primResTy) <- splitFunForallTy (primType primInfo)   , TyConApp tupTcNm tupEls <- tyView primResTy     -- XXX: Hardcoded for tuples-  , "GHC.Tuple.(," `isInfixOf` nameOcc tupTcNm-  , Just tupTc <- lookupUniqMap tupTcNm tcm+  , isTupleTyConLike tupTcNm+  , Just tupTc <- UniqMap.lookup tupTcNm tcm   , [tupDc] <- tyConDataCons tupTc   = Just $ MultiPrimInfo     { mpi_primInfo = primInfo
src/Clash/Core/TermLiteral.hs view
@@ -1,21 +1,29 @@ {-| Copyright   :  (C) 2019, Myrtle Software Ltd,                    2021, QBayLogic B.V.+                   2022, Google Inc. License     :  BSD2 (see the file LICENSE) Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>  Tools to convert a 'Term' into its "real" representation -}++{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE NamedFieldPuns #-}  --{-# OPTIONS_GHC -ddump-splices #-}  module Clash.Core.TermLiteral   ( TermLiteral+  , showsTypePrec+  , showType   , termToData   , termToDataError+  , deriveTermLiteral   ) where  import           Data.Bifunctor                  (bimap)@@ -23,20 +31,39 @@ import           Data.Proxy                      (Proxy(..)) import           Data.Text                       (Text) import qualified Data.Text                       as Text+import           Data.Text.Extra                 (showt)+#if MIN_VERSION_ghc(9,4,0)+import qualified Data.Text.Internal              as Text+import qualified Data.Text.Array                 as Text+import qualified Data.Primitive.ByteArray        as BA+#endif import           Data.Typeable                   (Typeable, typeRep) import           GHC.Natural import           GHC.Stack+import           GHC.TypeNats (KnownNat)+import           Text.Show.Pretty                (ppShow) -import           Clash.Core.Term                 (Term(Literal), collectArgs)+import           Clash.Annotations.SynthesisAttributes (Attr)+import           Clash.Core.DataCon              (DataCon(..)) import           Clash.Core.Literal+import           Clash.Core.Name                 (Name(..)) import           Clash.Core.Pretty               (showPpr)+import           Clash.Core.Term                 (Term(Literal, Data), collectArgs)+import           Clash.Promoted.Nat+import           Clash.Promoted.Nat.Unsafe+import           Clash.Sized.Index               (Index)+import           Clash.Sized.Vector              (Vec (Nil, Cons), fromList) import qualified Clash.Util.Interpolate          as I import qualified Clash.Verification.Internal     as Cv  import           Clash.Core.TermLiteral.TH --- | Tools to deal with literals encoded as a "Term".-class Typeable a => TermLiteral a where+-- | Pretty print type @a@+showType :: TermLiteral a => Proxy a -> String+showType proxy = showsTypePrec 0 proxy ""++-- | Tools to deal with literals encoded as a 'Term'.+class TermLiteral a where   -- | Convert 'Term' to the constant it represents. Will return an error if   -- (one of the subterms) fail to translate.   termToData@@ -47,6 +74,23 @@     -- ^ 'Left' indicates a failure, containing the (sub)term that failed to     -- translate. 'Right' indicates a success. +  -- | Pretty print the type of a term (for error messages). Its default implementation+  -- uses 'Typeable' to print the type. Note that this method is there to allow+  -- an instance for 'SNat' to exist (and other GADTs imposing+  -- t'GHC.TypeNats.KnownNat'). Without it, GHC would ask for a @KnownNat@+  -- constraint on the instance, which would defeat the purpose of it.+  showsTypePrec ::+    -- | The operator precedence of the enclosing context (a number from @0@ to+    -- @11@). Function application has precedence @10@. Used to determine whether+    -- the result should be wrapped in parentheses.+    Int ->+    -- | Proxy for a term whose type needs to be pretty printed+    Proxy a ->+    ShowS++  default showsTypePrec :: Typeable a => Int -> Proxy a -> ShowS+  showsTypePrec n _ = showsPrec n (typeRep (Proxy @a))+ instance TermLiteral Term where   termToData = pure @@ -55,8 +99,23 @@   termToData t = Left t  instance TermLiteral Text where-  termToData t = Text.pack <$> termToData t+  termToData (collectArgs -> (_, [Left (Literal (StringLiteral s))])) =+    Right (Text.pack s)+#if MIN_VERSION_ghc(9,4,0)+  termToData (collectArgs -> (_, [ Left (Literal (ByteArrayLiteral (BA.ByteArray ba)))+                                 , Left (Literal (IntLiteral off))+                                 , Left (Literal (IntLiteral len))])) =+    Right (Text.Text (Text.ByteArray ba) (fromInteger off) (fromInteger len))+#endif+  termToData t = Left t +instance KnownNat n => TermLiteral (Index n) where+  termToData t@(collectArgs -> (_, [_, _, Left (Literal (IntegerLiteral n))]))+    | n < 0 = Left t+    | n >= natToNum @n = Left t+    | otherwise = Right (fromInteger n)+  termToData t = Left t+ instance TermLiteral Int where   termToData (collectArgs -> (_, [Left (Literal (IntLiteral n))])) =     Right (fromInteger n)@@ -68,6 +127,7 @@   termToData t = Left t  instance TermLiteral Integer where+  termToData (Literal (IntegerLiteral n)) = Right n   termToData (collectArgs -> (_, [Left (Literal (IntegerLiteral n))])) = Right n   termToData t = Left t @@ -76,10 +136,31 @@   termToData t = Left t  instance TermLiteral Natural where+  termToData t@(Literal (NaturalLiteral n))+    | n < 0 = Left t+    | otherwise = Right (fromIntegral n)   termToData (collectArgs -> (_, [Left (Literal (NaturalLiteral n))])) =     Right (fromInteger n)   termToData t = Left t +-- | Unsafe warning: If you use this instance in a monomorphic context (e.g.,+-- @TermLiteral (SNat 5)@), you need to make very sure that the term corresponds+-- to the literal. If you don't, there will be a mismatch between type level+-- variables and the proof carried in 'SNat's 'KnownNat'. Typical usage of this+-- instance will therefore leave the /n/ polymorphic.+--+instance TermLiteral (SNat n) where+  termToData = \case+    Literal (NaturalLiteral n) -> Right (unsafeSNat n)+    t                          -> Left t++  showsTypePrec n _+    -- We don't know the literal /n/ at this point. However, we can't simply put+    -- and /n/ here either, as it might collide with other type variables. To+    -- prevent confusion, we put an underscore. This is obviously "wrong", but+    -- good enough for error messages - the main purpose of this function.+    = showParen (n > 10) $ showString "SNat _"+ instance (TermLiteral a, TermLiteral b) => TermLiteral (a, b) where   termToData (collectArgs -> (_, lefts -> [a, b])) = do     a' <- termToData a@@ -87,38 +168,81 @@     pure (a', b')   termToData t = Left t -instance TermLiteral a => TermLiteral (Maybe a) where-  termToData = $(deriveTermToData ''Maybe)--instance TermLiteral Bool where-  termToData = $(deriveTermToData ''Bool)+  showsTypePrec _ _ =+    -- XXX: We pass in 11 here, but should really be passing in 0. We never want+    --      any parentheses for fields in tuples. However, Typeable's show+    --      implementation does put parentheses around tuple fields - so we+    --      replicate that behavior here for ease of testing.+      showChar '('+    . showsTypePrec 11 (Proxy @a)+    . showString ","+    . showsTypePrec 11 (Proxy @b)+    . showChar ')' -instance TermLiteral Cv.RenderAs where-  termToData = $(deriveTermToData ''Cv.RenderAs)+instance (TermLiteral a, KnownNat n) => TermLiteral (Vec n a) where+  termToData term = do+    res <- fromList <$> go term+    -- Check whether length of list constructed in 'go' corresponds to the+    -- @KnownNat n@ we've been given+    case res of+      Nothing -> Left term+      Just v -> Right v+   where+    -- Construct a list from given term+    go t@(collectArgs -> (constr, args)) =+      case constr of+        Data (MkData{dcName=Name{nameOcc}})+          | nameOcc == showt 'Nil -> Right []+          | nameOcc == showt 'Cons ->+            case lefts args of+              [_gadtProof, c0, cs0] -> do+                c1 <- termToData @a c0+                cs1 <- go cs0+                Right (c1:cs1)+              _ -> Left t+        _ -> Left t -instance TermLiteral a => TermLiteral (Cv.Assertion' a) where-  termToData = $(deriveTermToData ''Cv.Assertion')+  showsTypePrec n _ =+    showParen (n > 10) $+        showString "Vec"+      . showChar ' '+      . showString (show (natToInteger @n))+      . showChar ' '+      . showsTypePrec 11 (Proxy @a) -instance TermLiteral a => TermLiteral (Cv.Property' a) where-  termToData = $(deriveTermToData ''Cv.Property')+deriveTermLiteral ''Bool+deriveTermLiteral ''Maybe+deriveTermLiteral ''Either+deriveTermLiteral ''Cv.RenderAs+deriveTermLiteral ''Cv.Assertion'+deriveTermLiteral ''Cv.Property'+deriveTermLiteral ''Attr  -- | Same as 'termToData', but returns printable error message if it couldn't -- translate a term. termToDataError :: forall a. TermLiteral a => Term -> Either String a termToDataError term = bimap err id (termToData term)  where-  typ = show (typeRep (Proxy @a))+  -- XXX: If we put this construct in the quasiquoted part, it yields a parse+  --      error on some platforms. This is likely related to some older version+  --      of dependencies. In the interested of time yours truly just moved it+  --      outside of the quasiquoter.+  shownType = showType (Proxy @a)    err failedTerm = [I.i|     Failed to translate term to literal. Term that failed to translate:        #{showPpr failedTerm} +    In its non-pretty-printed form:++      #{ppShow failedTerm}+     In the full term:        #{showPpr term}      While trying to interpret something to type: -      #{typ}+      #{shownType}   |]
src/Clash/Core/TermLiteral/TH.hs view
@@ -1,7 +1,20 @@-{-# LANGUAGE TemplateHaskellQuotes #-}+{-|+Copyright   :  (C) 2019, Myrtle Software Ltd,+                   2021, QBayLogic B.V.+                   2022, Google Inc+License     :  BSD2 (see the file LICENSE)+Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> +Template Haskell utilities for "Clash.Core.TermLiteral".+-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TemplateHaskell #-}+ module Clash.Core.TermLiteral.TH-  (  deriveTermToData+  ( deriveTermToData+  , deriveShowsTypePrec+  , deriveTermLiteral      -- Stop exporting @dcName'@  once `ghcide` stops type-checking expanded      -- TH splices   ,  dcName'@@ -9,7 +22,12 @@  import           Data.Either import qualified Data.Text                       as Text+import           Data.List                       (intersperse)+import qualified Data.List.NonEmpty              as NE+import           Data.Proxy+import           Data.Maybe                      (isNothing) import           Language.Haskell.TH.Syntax+import           Language.Haskell.TH.Lib         hiding (match)  import           Clash.Core.DataCon import           Clash.Core.Term                 (collectArgs, Term(Data))@@ -21,18 +39,136 @@ -- module Clash.Core.Subst cannot be linked; it is only available as a boot module import Clash.Core.Subst () +#if __GLASGOW_HASKELL__ >= 900+type CompatTyVarBndr = TyVarBndr ()+#else+type CompatTyVarBndr = TyVarBndr+#endif+ dcName' :: DataCon -> String dcName' = Text.unpack . nameOcc . dcName  termToDataName :: Name-termToDataName = mkName "Clash.Core.TermLiteral.termToData"+termToDataName =+  -- Note that we can't use a fully qualified name here: GHC disallows fully+  -- qualified names in instance function declarations.+  mkName "termToData" +showsTypePrecName :: Name+showsTypePrecName =+  -- Note that we can't use a fully qualified name here: GHC disallows fully+  -- qualified names in instance function declarations.+  mkName "showsTypePrec"++termLiteralName :: Name+termLiteralName = mkName "Clash.Core.TermLiteral.TermLiteral"++-- | Extracts variable names from a 'TyVarBndr'.+typeVarName :: CompatTyVarBndr -> Q (Name, Maybe Type)+typeVarName = \case+#if __GLASGOW_HASKELL__ >= 900+  PlainTV typVarName ()        -> pure (typVarName, Nothing)+  KindedTV typVarName () StarT -> pure (typVarName, Nothing)+  KindedTV typVarName () kind  -> pure (typVarName, Just kind)+#else+  PlainTV typVarName        -> pure (typVarName, Nothing)+  KindedTV typVarName StarT -> pure (typVarName, Nothing)+  KindedTV typVarName kind  -> pure (typVarName, Just kind)+#endif++-- | Derive a t'Clash.Core.TermLiteral.TermLiteral' instance for given type+deriveTermLiteral :: Name -> Q [Dec]+deriveTermLiteral typName = do+  TyConI (DataD _ _ typeVars _ _ _) <- reify typName+#if MIN_VERSION_template_haskell(2,21,0)+  typeVarNames <- mapM (typeVarName . fmap (const ())) typeVars+#else+  typeVarNames <- mapM typeVarName typeVars+#endif+  showsTypePrec <- deriveShowsTypePrec typName+  termToDataBody <- deriveTermToData typName+  let+    termToData = FunD termToDataName [Clause [] (NormalB termToDataBody) []]+    innerInstanceType = foldl AppT (ConT typName) (map (VarT . fst) typeVarNames)+    instanceType = ConT termLiteralName `AppT` innerInstanceType+    constraint typVarName = [t| $(conT termLiteralName) $(varT typVarName) |]+  constraints <- mapM (constraint . fst) (filter (isNothing . snd) typeVarNames)+  pure $ [InstanceD Nothing constraints instanceType [showsTypePrec, termToData]]++-- | For 'Maybe', constructs:+--+-- > showsTypePrec n _+-- >   = let+-- >       showSpace = showChar ' '+-- >       precCalls = [showsTypePrec 11 (Proxy @a)]+-- >       interspersedPrecCalls = intersperse showSpace precCalls+-- >       showType = foldl (.) (showString "Maybe") (showSpace : interspersedPrecCalls)+-- >     in+-- >       showParen (n > 10) showType+--+deriveShowsTypePrec :: Name -> Q Dec+deriveShowsTypePrec typName = do+  TyConI (DataD _ _ typeVars _ _ _) <- reify typName+#if MIN_VERSION_template_haskell(2,21,0)+  typeVarNames <- mapM (typeVarName . fmap (const ())) typeVars+#else+  typeVarNames <- mapM typeVarName typeVars+#endif+  showTypeBody <- mkShowTypeBody typeVarNames+  pure (FunD showsTypePrecName [Clause [VarP nName, WildP] (NormalB showTypeBody) []])+ where+  showTypeName = [| showString $(litE (StringL (nameBase typName))) |]++  -- Constructs:+  --+  -- > showsTypePrec 11 (Proxy @a)+  --+  -- where the 'a' is given as an argument. The surrounding operator precedence+  -- is set to indicate "function" application. I.e., it instructs the call to+  -- wrap the type string in parentheses.+  --+  mkTypePrecCall = \case+    (typVarName, Nothing) ->+      [| $(varE showsTypePrecName) 11 (Proxy @($(varT typVarName))) |]+    (_, Just _) ->+      -- XXX: Not sure how to deal with non-Type type variables so we do the dumb+      --      thing and insert an underscore.+      [| showString "_" |]++  -- Constructs:+  --+  -- > showString "Maybe" . showChar ' ' . showsTypePrec 11 (Proxy @a)+  --+  -- This is wrapped in an if-statement wrapping the result in parentheses if the+  -- incoming prec is more than 10 (function application).+  --+  mkShowTypeBody :: [(Name, Maybe Type)] -> Q Exp+  mkShowTypeBody typeVarNames =+    case typeVarNames of+      [] ->+        -- We seq on `n` here to prevent _unused variable_ warnings. This is a+        -- bit of a hack (the real solution would be to selectively pattern+        -- match).+        [| $(varE nName) `seq` $(showTypeName) |]+      _  -> [|+        let+          showSpace = showChar ' '+          precCalls = $(listE (map mkTypePrecCall typeVarNames))+          interspersedPrecCalls = intersperse showSpace precCalls+          showType = foldl (.) $(showTypeName) (showSpace : interspersedPrecCalls)+        in+          showParen ($(varE nName) > 10) showType+       |]++  nName = mkName "n"+ deriveTermToData :: Name -> Q Exp deriveTermToData typName = do   TyConI (DataD _ _ _ _ constrs _) <- reify typName   pure (deriveTermToData1 (map toConstr' constrs))  where   toConstr' (NormalC cName fields) = (cName, length fields)+  toConstr' (RecC cName fields) = (cName, length fields)   toConstr' c = error $ "Unexpected constructor: " ++ show c  deriveTermToData1 :: [(Name, Int)] -> Exp@@ -46,7 +182,7 @@   nArgs = maximum (map snd constrs)    args :: [Dec]-  args = zipWith (\n nm -> ValD (VarP nm) (NormalB (arg n)) []) [0..] argNames+  args = zipWith (\n nm -> ValD (VarP nm) (NormalB (arg (toInteger n))) []) [0..nArgs-1] (NE.toList argNames)   arg n = UInfixE (VarE argsName) (VarE '(!!)) (LitE (IntegerL n))    -- case nm of {"ConstrOne" -> ConstOne <$> termToData arg0; "ConstrTwo" -> ...}@@ -68,7 +204,7 @@     UInfixE       (ConE cName)       (VarE '(<$>))-      (VarE termToDataName `AppE` VarE (head argNames))+      (VarE termToDataName `AppE` VarE (NE.head argNames))   mkCall cName nFields =     foldl       (\e aName ->@@ -77,7 +213,7 @@           (VarE '(<*>))           (VarE termToDataName `AppE` VarE aName))       (mkCall cName 1)-      (take (nFields-1) (tail argNames))+      (take (nFields-1) (NE.tail argNames))    -- term@(collectArgs -> (Data (dcName' -> nm), args))   pat :: Pat@@ -86,13 +222,16 @@       termName       (ViewP         (VarE 'collectArgs)+#if MIN_VERSION_template_haskell(2,18,0)+        (TupP [ ConP 'Data [] [ViewP (VarE 'dcName') (VarP nameName)]+#else         (TupP [ ConP 'Data [ViewP (VarE 'dcName') (VarP nameName)]+#endif               , ViewP                  (VarE 'lefts)                  (if nArgs == 0 then WildP else VarP argsName)]))    termName = mkName "term"   argsName = mkName "args"-  argNames = [mkName ("arg" ++ show n) | n <- [0..nArgs-1]]+  argNames = fmap (mkName . ("arg" <>) . show) (NE.iterate (+1) (0 :: Word))   nameName = mkName "nm"-
src/Clash/Core/TyCon.hs view
@@ -38,6 +38,7 @@ import Clash.Core.Name import {-# SOURCE #-} Clash.Core.Type         (Kind, Type) import Clash.Core.Var                         (TyVar)+import Clash.Data.UniqMap (UniqMap) import Clash.Unique  -- | Type Constructor@@ -118,13 +119,13 @@  -- | Does the TyCon look like a tuple TyCon isTupleTyConLike :: TyConName -> Bool-isTupleTyConLike nm = tupleName (nameOcc nm)+isTupleTyConLike nm = tupleName (T.takeWhileEnd (/= '.') (nameOcc nm))   where-    tupleName nm'-      | '(' <- T.head nm'-      , ')' <- T.last nm'-      = T.all (== ',') (T.init $ T.tail nm')-    tupleName _ = False+    tupleName nm0+      | Just ('(', nm1) <- T.uncons nm0+      , Just (nm2, ')') <- T.unsnoc nm1+      = T.all (== ',') nm2+    tupleName _ = T.pack "GHC.Tuple.Prim.Tuple" `T.isPrefixOf` (nameOcc nm)  -- | Get the DataCons belonging to a TyCon tyConDataCons :: TyCon -> [DataCon]
src/Clash/Core/Type.hs view
@@ -65,17 +65,31 @@ import           Data.List              (foldl') import           Data.List.Extra        (splitAtList) import           Data.Maybe             (isJust, mapMaybe)+import           Data.Text              (Text) import           GHC.Base               (isTrue#,(==#)) import           GHC.Generics           (Generic(..)) import           GHC.Integer            (smallInteger) import           GHC.Integer.Logarithms (integerLogBase#) import           GHC.TypeLits           (type TypeError, ErrorMessage(Text, (:<>:)))+#if MIN_VERSION_base(4,16,0)+import           GHC.Base               (ord)+import           Data.Char              (chr)+import           Data.Maybe             (fromMaybe)+import           Data.Text.Extra        (showt)+#endif  -- GHC API #if MIN_VERSION_ghc(9,0,0)+#if MIN_VERSION_ghc(9,2,0) import           GHC.Builtin.Names+  (typeCharCmpTyFamNameKey, typeConsSymbolTyFamNameKey, typeUnconsSymbolTyFamNameKey,+   typeCharToNatTyFamNameKey, typeNatToCharTyFamNameKey)+#else+import           GHC.Builtin.Names      (typeNatLeqTyFamNameKey)+#endif+import           GHC.Builtin.Names   (integerTyConKey, typeNatAddTyFamNameKey, typeNatExpTyFamNameKey,-   typeNatLeqTyFamNameKey, typeNatMulTyFamNameKey, typeNatSubTyFamNameKey,+   typeNatMulTyFamNameKey, typeNatSubTyFamNameKey,    typeNatCmpTyFamNameKey, ordLTDataConKey, ordEQDataConKey, ordGTDataConKey,    typeSymbolAppendFamNameKey, typeSymbolCmpTyFamNameKey) import           GHC.Types.SrcLoc       (wiredInSrcSpan)@@ -99,12 +113,13 @@ #endif  -- Local imports+import           Clash.Annotations.SynthesisAttributes import           Clash.Core.DataCon import           Clash.Core.Name import {-# SOURCE #-} Clash.Core.Subst import           Clash.Core.TyCon import           Clash.Core.Var-import           Clash.Unique+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Util  #if __GLASGOW_HASKELL__ <= 806@@ -114,7 +129,7 @@ ordGTDataConKey = gtDataConKey #endif -varAttrs :: Var a -> [Attr']+varAttrs :: Var a -> [Attr Text] varAttrs t@(TyVar {}) =   error $ $(curLoc) ++ "Unexpected argument: " ++ show t @@ -131,7 +146,7 @@   | ForAllTy !TyVar !Type       -- ^ Polymorphic Type   | AppTy    !Type !Type        -- ^ Type Application   | LitTy    !LitTy             -- ^ Type literal-  | AnnType  [Attr'] !Type      -- ^ Annotated type, see Clash.Annotations.SynthesisAttributes+  | AnnType  [Attr Text] !Type  -- ^ Annotated type, see Clash.Annotations.SynthesisAttributes   deriving (Show, Generic, NFData, Binary)  instance TypeError (@@ -158,6 +173,7 @@ data LitTy   = NumTy !Integer   | SymTy !String+  | CharTy !Char   deriving (Eq,Ord,Show,Generic,NFData,Hashable,Binary)  -- | The level above types@@ -263,7 +279,7 @@     , [_,elTy] <- args     -> Just elTy     | otherwise-    -> case tcMap `lookupUniqMap'` tcNm of+    -> case UniqMap.find tcNm tcMap of          AlgTyCon {algTcRhs = (NewTyCon _ nt)}            -> newTyConInstRhs nt args          _ -> reduceTypeFamily tcMap ty@@ -373,9 +389,7 @@  -- | Extract attributes from type. Will return an empty list if this is an -- AnnType with an empty list AND if this is not an AnnType at all.-typeAttrs-  :: Type-  -> [Attr']+typeAttrs :: Type -> [Attr Text] typeAttrs (AnnType attrs _typ) = attrs typeAttrs _                    = [] @@ -522,16 +536,18 @@         -> Just (LitTy (NumTy z))       _ -> Nothing +#if !MIN_VERSION_ghc(9,2,0)   | nameUniq tc == getKey typeNatLeqTyFamNameKey   = case mapMaybe (litView tcm) tys of       [i1, i2]-        | Just (FunTyCon {tyConKind = tck}) <- lookupUniqMap tc tcm+        | Just (FunTyCon {tyConKind = tck}) <- UniqMap.lookup tc tcm         , (_,tyView -> TyConApp boolTcNm []) <- splitFunTys tcm tck-        , Just boolTc <- lookupUniqMap boolTcNm tcm+        , Just boolTc <- UniqMap.lookup boolTcNm tcm         -> let [falseTc,trueTc] = map (coerce . dcName) (tyConDataCons boolTc)             in  if i1 <= i2 then Just (mkTyConApp trueTc [])                             else Just (mkTyConApp falseTc [])       _ -> Nothing+#endif    | nameUniq tc == getKey typeNatCmpTyFamNameKey -- "GHC.TypeNats.CmpNat"   = case mapMaybe (litView tcm) tys of@@ -553,6 +569,50 @@             GT -> Name User "GHC.Types.GT" (getKey ordGTDataConKey) wiredInSrcSpan       _ -> Nothing +#if MIN_VERSION_base(4,16,0)+  | nameUniq tc == getKey typeCharCmpTyFamNameKey -- "GHC.TypeNats.CmpSymbol"+  = case mapMaybe (charLitView tcm) tys of+      [s1, s2] ->+        Just $ ConstTy $ TyCon $+          case compare s1 s2 of+            LT -> Name User (showt 'LT) (getKey ordLTDataConKey) wiredInSrcSpan+            EQ -> Name User (showt 'EQ) (getKey ordEQDataConKey) wiredInSrcSpan+            GT -> Name User (showt 'GT) (getKey ordGTDataConKey) wiredInSrcSpan+      _ -> Nothing++  | nameUniq tc == getKey typeConsSymbolTyFamNameKey -- ConsSymbol+  , [c0, s0] <- tys+  , Just c1 <- charLitView tcm c0+  , Just s1 <- symLitView tcm s0+  = Just (LitTy (SymTy (c1:s1)))++  | nameUniq tc == getKey typeUnconsSymbolTyFamNameKey -- UnconsSymbol+  , [s1] <- mapMaybe (symLitView tcm) tys+  = fromMaybe (error "reduceTypeFamily: cannot construct UnconsSymbol result") $ do+      FunTyCon {tyConKind = tck} <- UniqMap.lookup tc tcm+      TyConApp maybeTcNm [tupTcApp] <- pure (tyView (snd (splitFunTys tcm tck)))+      maybeTc <- UniqMap.lookup maybeTcNm tcm+      [nothingTc,justTc] <- pure (map (coerce . dcName) (tyConDataCons maybeTc))+      TyConApp tupTcNm [charTy,symbolTy] <- pure (tyView tupTcApp)+      tupTc <- UniqMap.lookup tupTcNm tcm+      [tupDc] <- pure (map (coerce . dcName) (tyConDataCons tupTc))+      case s1 of+        [] ->+          pure (Just (mkTyConApp nothingTc [tupTcApp]))+        (c:cs) ->+          let tup = mkTyConApp tupDc+                      [charTy,symbolTy,LitTy (CharTy c),LitTy (SymTy cs)]+           in pure (Just (mkTyConApp justTc [tupTcApp,tup]))++  | nameUniq tc == getKey typeCharToNatTyFamNameKey -- CharToNat+  , [c1] <- mapMaybe (charLitView tcm) tys+  = Just (LitTy (NumTy (fromIntegral (ord c1))))++  | nameUniq tc == getKey typeNatToCharTyFamNameKey -- NatToChar+  , [n1] <- mapMaybe (litView tcm) tys+  = Just (LitTy (CharTy (chr (fromInteger n1))))+#endif+   | nameUniq tc == getKey typeSymbolAppendFamNameKey  -- GHC.TypeLits.AppendSymbol"   = case mapMaybe (symLitView tcm) tys of       [s1, s2] ->@@ -614,7 +674,7 @@         -> Just (LitTy (NumTy (i1 `mod` i2)))       _ -> Nothing -  | Just (FunTyCon {tyConSubst = tcSubst}) <- lookupUniqMap tc tcm+  | Just (FunTyCon {tyConSubst = tcSubst}) <- UniqMap.lookup tc tcm   = let -- See [Note: Eager type families]         tysR = map (argView tcm) tys      in findFunSubst tcm tcSubst tysR@@ -624,7 +684,7 @@ -- | isTypeFamilyApplication ::  TyConMap -> Type -> Bool isTypeFamilyApplication tcm (tyView -> TyConApp tcNm _args)-  | Just (FunTyCon {}) <- lookupUniqMap tcNm tcm = True+  | Just (FunTyCon {}) <- UniqMap.lookup tcNm tcm = True isTypeFamilyApplication _tcm _type = False  argView :: TyConMap -> Type -> Type@@ -642,6 +702,13 @@ symLitView m (reduceTypeFamily m -> Just ty') = symLitView m ty' symLitView _ _ = Nothing +#if MIN_VERSION_base(4,16,0)+charLitView :: TyConMap -> Type -> Maybe Char+charLitView _ (LitTy (CharTy c)) = Just c+charLitView m (reduceTypeFamily m -> Just t) = charLitView m t+charLitView _ _ = Nothing+#endif+ isIntegerTy :: Type -> Bool isIntegerTy (ConstTy (TyCon nm)) = nameUniq nm == getKey integerTyConKey isIntegerTy _ = False@@ -663,7 +730,7 @@         nameOcc tcNm == "Clash.Sized.Internal.Unsigned.Unsigned"       -> mkTyConApp tcNm (map go args)       | otherwise-      -> case lookupUniqMap' tcMap tcNm of+      -> case UniqMap.find tcNm tcMap of           AlgTyCon {algTcRhs = (NewTyCon _ nt)}              -> case newTyConInstRhs nt args of                   Just ty' -> go ty'@@ -691,7 +758,7 @@   -> Type   -> Bool isClassTy tcm (tyView -> TyConApp tcNm _) =-  case lookupUniqMap tcNm tcm of+  case UniqMap.lookup tcNm tcm of     Just (AlgTyCon {isClassTc}) -> isClassTc     _ -> False isClassTy _ _ = False
src/Clash/Core/TysPrim.hs view
@@ -9,7 +9,9 @@ -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskellQuotes #-}  module Clash.Core.TysPrim   ( liftedTypeKind@@ -19,10 +21,20 @@   , integerPrimTy   , charPrimTy   , stringPrimTy+#if !MIN_VERSION_ghc(9,2,0)   , voidPrimTy+#endif   , wordPrimTy   , int64PrimTy   , word64PrimTy+#if MIN_VERSION_ghc(8,8,0)+  , int8PrimTy+  , int16PrimTy+  , int32PrimTy+  , word8PrimTy+  , word16PrimTy+  , word32PrimTy+#endif   , floatPrimTy   , doublePrimTy   , naturalPrimTy@@ -32,7 +44,6 @@   ) where -import qualified Data.List            as List  #if MIN_VERSION_ghc(9,0,0) import           GHC.Builtin.Names@@ -42,16 +53,31 @@ import           Unique               (getKey) #endif +#if MIN_VERSION_ghc(8,8,0)+import           GHC.Base hiding (Type, TyCon)+import           Data.Text.Extra (showt)+#endif++#if MIN_VERSION_base(4,17,0)+import           Clash.Core.DataCon (DataCon(..), DcStrictness(..))+import           GHC.Num.Integer (Integer(..))+import           GHC.Num.Natural (Natural(..))+#endif+ import           Clash.Core.Name import           Clash.Core.TyCon import           Clash.Core.Type import           Clash.Core.Var (mkTyVar)-import           Clash.Unique+import qualified Clash.Data.UniqMap as UniqMap  -- | Builtin Name liftedTypeKindTyConName, typeNatKindTyConName, typeSymbolKindTyConName :: TyConName liftedTypeKindTyConName   = mkUnsafeSystemName "Type" (getKey liftedTypeKindTyConKey)+#if MIN_VERSION_ghc(9,2,0)+typeNatKindTyConName      = naturalPrimTyConName+#else typeNatKindTyConName      = mkUnsafeSystemName "Nat" (getKey typeNatKindConNameKey)+#endif typeSymbolKindTyConName   = mkUnsafeSystemName "Symbol" (getKey typeSymbolKindConNameKey)  -- | Builtin Kind@@ -66,8 +92,8 @@ typeSymbolKind = mkTyConTy typeSymbolKindTyConName  intPrimTyConName, integerPrimTyConName, charPrimTyConName, stringPrimTyConName,-  voidPrimTyConName, wordPrimTyConName, int64PrimTyConName,-  word64PrimTyConName, floatPrimTyConName, doublePrimTyConName,+  wordPrimTyConName,  int64PrimTyConName, word64PrimTyConName,+  floatPrimTyConName, doublePrimTyConName,   naturalPrimTyConName, byteArrayPrimTyConName, eqPrimTyConName :: TyConName intPrimTyConName     = mkUnsafeSystemName "GHC.Prim.Int#"                                 (getKey intPrimTyConKey)@@ -81,7 +107,6 @@ stringPrimTyConName  = mkUnsafeSystemName "GHC.Prim.Addr#" (getKey addrPrimTyConKey) charPrimTyConName    = mkUnsafeSystemName "GHC.Prim.Char#"                                 (getKey charPrimTyConKey)-voidPrimTyConName    = mkUnsafeSystemName "Void#" (getKey voidPrimTyConKey) wordPrimTyConName    = mkUnsafeSystemName "GHC.Prim.Word#"                                 (getKey wordPrimTyConKey) int64PrimTyConName   = mkUnsafeSystemName "GHC.Prim.Int64#"@@ -104,27 +129,144 @@  eqPrimTyConName = mkUnsafeSystemName "GHC.Prim.~#" (getKey eqPrimTyConKey) +#if !MIN_VERSION_ghc(9,2,0)+voidPrimTyConName :: TyConName+voidPrimTyConName    = mkUnsafeSystemName "Void#" (getKey voidPrimTyConKey)+#endif++#if MIN_VERSION_ghc(8,8,0)+int8PrimTyConName, int16PrimTyConName, int32PrimTyConName, word8PrimTyConName,+  word16PrimTyConName, word32PrimTyConName :: TyConName+int8PrimTyConName   = mkUnsafeSystemName (showt ''Int8#) (getKey int8PrimTyConKey)+int16PrimTyConName  = mkUnsafeSystemName (showt ''Int16#) (getKey int16PrimTyConKey)+int32PrimTyConName  = mkUnsafeSystemName (showt ''Int32#) (getKey int32PrimTyConKey)+word8PrimTyConName  = mkUnsafeSystemName (showt ''Word8#) (getKey word8PrimTyConKey)+word16PrimTyConName = mkUnsafeSystemName (showt ''Word16#) (getKey word16PrimTyConKey)+word32PrimTyConName = mkUnsafeSystemName (showt ''Word32#) (getKey word32PrimTyConKey)+#endif+ liftedPrimTC :: TyConName              -> TyCon liftedPrimTC name = PrimTyCon (nameUniq name) name liftedTypeKind 0  -- | Builtin Type-intPrimTc, integerPrimTc, charPrimTc, stringPrimTc, voidPrimTc, wordPrimTc,+intPrimTc, integerPrimTc, charPrimTc, stringPrimTc, wordPrimTc,   int64PrimTc, word64PrimTc, floatPrimTc, doublePrimTc, naturalPrimTc,   byteArrayPrimTc :: TyCon intPrimTc     = liftedPrimTC intPrimTyConName+#if MIN_VERSION_base(4,17,0)+-- While GHC might have dropped Integer and Natural literals, in Clash it is+-- still nice to have them around. However, Integer and Natural are also no+-- longer primitive types in GHC, but we still want to give the Integer and+-- Natural type to our Integer and Natural literals.+--+-- So instead of recording the primitive types, we record the algebraic types,+-- i.e. the complete data type for Integer and Natural, data constructors and all.++integerPrimTc =+  let+    name = integerPrimTyConName+    uniq = nameUniq name+    isDcNm = mkUnsafeSystemName (showt 'IS) (getKey integerISDataConKey)+    isDc = MkData+      { dcName = isDcNm+      , dcUniq = nameUniq isDcNm+      , dcTag  = 1+      , dcType = mkPolyFunTy integerPrimTy [Right intPrimTy]+      , dcUnivTyVars = []+      , dcExtTyVars = []+      , dcArgTys = [intPrimTy]+      , dcArgStrict = [Strict]+      , dcFieldLabels = []+      }+    ipDcNm = mkUnsafeSystemName (showt 'IP) (getKey integerIPDataConKey)+    ipDc = MkData+      { dcName = ipDcNm+      , dcUniq = nameUniq ipDcNm+      , dcTag  = 2+      , dcType = mkPolyFunTy integerPrimTy [Right byteArrayPrimTy]+      , dcUnivTyVars = []+      , dcExtTyVars = []+      , dcArgTys = [byteArrayPrimTy]+      , dcArgStrict = [Strict]+      , dcFieldLabels = []+      }+    inDcNm = mkUnsafeSystemName (showt 'IN) (getKey integerINDataConKey)+    inDc = MkData+      { dcName = inDcNm+      , dcUniq = nameUniq inDcNm+      , dcTag  = 3+      , dcType = mkPolyFunTy integerPrimTy [Right byteArrayPrimTy]+      , dcUnivTyVars = []+      , dcExtTyVars = []+      , dcArgTys = [byteArrayPrimTy]+      , dcArgStrict = [Strict]+      , dcFieldLabels = []+      }+    rhs = DataTyCon [isDc,ipDc,inDc]+  in+    AlgTyCon uniq name liftedTypeKind 0 rhs False++naturalPrimTc =+  let+    name = naturalPrimTyConName+    uniq = nameUniq name+    nsDcNm = mkUnsafeSystemName (showt 'NS) (getKey naturalNSDataConKey)+    nsDc = MkData+      { dcName = nsDcNm+      , dcUniq = nameUniq nsDcNm+      , dcTag  = 1+      , dcType = mkPolyFunTy naturalPrimTy [Right wordPrimTy]+      , dcUnivTyVars = []+      , dcExtTyVars = []+      , dcArgTys = [wordPrimTy]+      , dcArgStrict = [Strict]+      , dcFieldLabels = []+      }+    nbDcNm = mkUnsafeSystemName (showt 'NB) (getKey naturalNBDataConKey)+    nbDc = MkData+      { dcName = nbDcNm+      , dcUniq = nameUniq nbDcNm+      , dcTag  = 2+      , dcType = mkPolyFunTy naturalPrimTy [Right byteArrayPrimTy]+      , dcUnivTyVars = []+      , dcExtTyVars = []+      , dcArgTys = [byteArrayPrimTy]+      , dcArgStrict = [Strict]+      , dcFieldLabels = []+      }+    rhs = DataTyCon [nsDc,nbDc]+   in+    AlgTyCon uniq name liftedTypeKind 0 rhs False+#else integerPrimTc = liftedPrimTC integerPrimTyConName+naturalPrimTc = liftedPrimTC naturalPrimTyConName+#endif charPrimTc    = liftedPrimTC charPrimTyConName stringPrimTc  = liftedPrimTC stringPrimTyConName-voidPrimTc    = liftedPrimTC voidPrimTyConName wordPrimTc    = liftedPrimTC wordPrimTyConName int64PrimTc   = liftedPrimTC int64PrimTyConName word64PrimTc  = liftedPrimTC word64PrimTyConName floatPrimTc   = liftedPrimTC floatPrimTyConName doublePrimTc  = liftedPrimTC doublePrimTyConName-naturalPrimTc = liftedPrimTC naturalPrimTyConName byteArrayPrimTc = liftedPrimTC  byteArrayPrimTyConName +#if !MIN_VERSION_ghc(9,2,0)+voidPrimTc :: TyCon+voidPrimTc    = liftedPrimTC voidPrimTyConName+#endif++#if MIN_VERSION_ghc(8,8,0)+int8PrimTc, int16PrimTc, int32PrimTc, word8PrimTc, word16PrimTc,+  word32PrimTc :: TyCon+int8PrimTc    = liftedPrimTC int8PrimTyConName+int16PrimTc   = liftedPrimTC int16PrimTyConName+int32PrimTc   = liftedPrimTC int32PrimTyConName+word8PrimTc   = liftedPrimTC word8PrimTyConName+word16PrimTc  = liftedPrimTC word16PrimTyConName+word32PrimTc  = liftedPrimTC word32PrimTyConName+#endif+ eqPrimTc :: TyCon eqPrimTc = PrimTyCon (nameUniq eqPrimTyConName) eqPrimTyConName ty 4  where@@ -138,14 +280,13 @@   aTv = mkTyVar liftedTypeKind (mkUnsafeSystemName "a" 0)   bTv = mkTyVar liftedTypeKind (mkUnsafeSystemName "b" 1) -intPrimTy, integerPrimTy, charPrimTy, stringPrimTy, voidPrimTy, wordPrimTy,+intPrimTy, integerPrimTy, charPrimTy, stringPrimTy, wordPrimTy,   int64PrimTy, word64PrimTy, floatPrimTy, doublePrimTy, naturalPrimTy,   byteArrayPrimTy, eqPrimTy :: Type intPrimTy     = mkTyConTy intPrimTyConName integerPrimTy = mkTyConTy integerPrimTyConName charPrimTy    = mkTyConTy charPrimTyConName stringPrimTy  = mkTyConTy stringPrimTyConName-voidPrimTy    = mkTyConTy voidPrimTyConName wordPrimTy    = mkTyConTy wordPrimTyConName int64PrimTy   = mkTyConTy int64PrimTyConName word64PrimTy  = mkTyConTy word64PrimTyConName@@ -155,8 +296,24 @@ byteArrayPrimTy = mkTyConTy byteArrayPrimTyConName eqPrimTy = mkTyConTy eqPrimTyConName +#if !MIN_VERSION_ghc(9,2,0)+voidPrimTy :: Type+voidPrimTy    = mkTyConTy voidPrimTyConName+#endif++#if MIN_VERSION_ghc(8,8,0)+int8PrimTy, int16PrimTy, int32PrimTy, word8PrimTy, word16PrimTy,+  word32PrimTy :: Type+int8PrimTy    = mkTyConTy int8PrimTyConName+int16PrimTy   = mkTyConTy int16PrimTyConName+int32PrimTy   = mkTyConTy int32PrimTyConName+word8PrimTy   = mkTyConTy word8PrimTyConName+word16PrimTy  = mkTyConTy word16PrimTyConName+word32PrimTy  = mkTyConTy word32PrimTyConName+#endif+ tysPrimMap :: TyConMap-tysPrimMap = List.foldl' (\s (k,x) -> extendUniqMap k x s) emptyUniqMap+tysPrimMap = UniqMap.fromList   [  (liftedTypeKindTyConName , liftedTypeKindTc)   ,  (typeNatKindTyConName , typeNatKindTc)   ,  (typeSymbolKindTyConName , typeSymbolKindTc)@@ -164,10 +321,20 @@   ,  (integerPrimTyConName , integerPrimTc)   ,  (charPrimTyConName , charPrimTc)   ,  (stringPrimTyConName , stringPrimTc)+#if !MIN_VERSION_ghc(9,2,0)   ,  (voidPrimTyConName , voidPrimTc)+#endif   ,  (wordPrimTyConName , wordPrimTc)   ,  (int64PrimTyConName , int64PrimTc)   ,  (word64PrimTyConName , word64PrimTc)+#if MIN_VERSION_ghc(8,8,0)+  ,  (int8PrimTyConName , int8PrimTc)+  ,  (int16PrimTyConName , int16PrimTc)+  ,  (int32PrimTyConName , int32PrimTc)+  ,  (word8PrimTyConName , word8PrimTc)+  ,  (word16PrimTyConName , word16PrimTc)+  ,  (word32PrimTyConName , word32PrimTc)+#endif   ,  (floatPrimTyConName , floatPrimTc)   ,  (doublePrimTyConName , doublePrimTc)   ,  (naturalPrimTyConName , naturalPrimTc)
src/Clash/Core/Util.hs view
@@ -1,6 +1,6 @@ {-|   Copyright   :  (C) 2012-2016, University of Twente,-                     2021     , QBayLogic B.V.,+                     2021-2023, QBayLogic B.V.,                      2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>@@ -20,13 +20,14 @@  import           Control.Concurrent.Supply     (Supply, freshId) import Control.Monad.Trans.Except              (Except, throwE, runExcept)-import Data.Bifunctor                          (first)+import Data.Bifunctor                          (first, second) import qualified Data.HashSet                  as HashSet import qualified Data.Graph                    as Graph-import Data.List                               (mapAccumR)+import Data.List                               (mapAccumR, uncons) import Data.List.Extra                         (zipEqual)+import Data.List.NonEmpty                      (NonEmpty (..), toList) import Data.Maybe-  (fromJust, isJust, mapMaybe, catMaybes)+  (fromMaybe, isJust, mapMaybe, catMaybes) import qualified Data.Set                      as Set import qualified Data.Set.Lens                 as Lens import qualified Data.Text                     as T@@ -55,8 +56,8 @@ import Clash.Core.TysPrim                (liftedTypeKind, typeNatKind) import Clash.Core.Var                    (Id, Var(..), mkLocalId, mkTyVar) import Clash.Core.VarEnv+import qualified Clash.Data.UniqMap as UniqMap import Clash.Debug                       (traceIf)-import Clash.Unique import Clash.Util  -- | Rebuild a let expression / let expressions by taking the SCCs of a list@@ -105,12 +106,15 @@                                         ,Left x                                         ,Left (go (n-1) xs)] -    nilCoTy    = head (fromJust $! dataConInstArgTys nilCon  [(LitTy (NumTy 0))-                                                             ,resTy])-    consCoTy n = head (fromJust $! dataConInstArgTys consCon-                                                     [(LitTy (NumTy n))-                                                     ,resTy-                                                     ,(LitTy (NumTy (n-1)))])+    nilCoTy    = case dataConInstArgTys nilCon [(LitTy (NumTy 0)) ,resTy] of+                   Just (x:_) -> x+                   _ -> error "impossible"+    consCoTy n = case dataConInstArgTys consCon+                                        [(LitTy (NumTy n))+                                        ,resTy+                                        ,(LitTy (NumTy (n-1)))] of+                   Just (x:_) -> x+                   _ -> error "impossible"  -- | Append elements to the supplied vector appendToVec :: DataCon -- ^ The Cons (:>) constructor@@ -129,16 +133,19 @@                                         ,Left x                                         ,Left (go (n-1) xs)] -    consCoTy n = head (fromJust $! dataConInstArgTys consCon-                                                   [(LitTy (NumTy n))-                                                   ,resTy-                                                   ,(LitTy (NumTy (n-1)))])+    consCoTy n = case dataConInstArgTys consCon+                                        [(LitTy (NumTy n))+                                        ,resTy+                                        ,(LitTy (NumTy (n-1)))] of+                   Just (x:_) -> x+                   _ -> error "impossible"  -- | Create let-bindings with case-statements that select elements out of a -- vector. Returns both the variables to which element-selections are bound -- and the let-bindings extractElems-  :: Supply+  :: HasCallStack+  => Supply   -- ^ Unique supply   -> InScopeSet   -- ^ (Superset of) in scope variables@@ -152,22 +159,22 @@   -- ^ Length of the vector   -> Term   -- ^ The vector-  -> (Supply, [(Term,[(Id, Term)])])+  -> (Supply, NonEmpty (Term,NonEmpty (Id, Term))) extractElems supply inScope consCon resTy s maxN vec =-  first fst (go maxN (supply,inScope) vec)+  if maxN >= 1 then+    first fst (go maxN (supply,inScope) vec)+  else+    error "extractElems must be called with positive number"  where   go :: Integer -> (Supply,InScopeSet) -> Term-     -> ((Supply,InScopeSet),[(Term,[(Id, Term)])])-  go 0 uniqs _ = (uniqs,[])-  go n uniqs0 e =-    (uniqs3,(elNVar,[(elNId, lhs),(restNId, rhs)]):restVs)-   where-    tys = [(LitTy (NumTy n)),resTy,(LitTy (NumTy (n-1)))]-    (Just idTys) = dataConInstArgTys consCon tys-    restTy       = last idTys+     -> ((Supply,InScopeSet),NonEmpty (Term, NonEmpty (Id, Term)))+  go n uniqs0 e = fromMaybe (error "extractElems: failed to project elements") $ do+    let tys = [(LitTy (NumTy n)),resTy,(LitTy (NumTy (n-1)))]+    idTys <- dataConInstArgTys consCon tys+    let restTy = last idTys -    (uniqs1,mTV) = mkUniqSystemTyVar uniqs0 ("m",typeNatKind)-    (uniqs2,[elNId,restNId,co,el,rest]) =+    let (uniqs1,mTV) = mkUniqSystemTyVar uniqs0 ("m",typeNatKind)+    (uniqs2,[elNId,restNId,co,el,rest]) <- pure $       mapAccumR mkUniqSystemId uniqs1 $ zipEqual         ["el" `T.append` (s `T.cons` T.pack (show (maxN-n)))         ,"rest" `T.append` (s `T.cons` T.pack (show (maxN-n)))@@ -177,13 +184,15 @@         ]         (resTy:restTy:idTys) -    elNVar    = Var elNId-    pat       = DataPat consCon [mTV] [co,el,rest]-    lhs       = Case e resTy  [(pat,Var el)]-    rhs       = Case e restTy [(pat,Var rest)]+    let elNVar    = Var elNId+        pat       = DataPat consCon [mTV] [co,el,rest]+        lhs       = Case e resTy  [(pat,Var el)]+        rhs       = Case e restTy [(pat,Var rest)] -    (uniqs3,restVs) = go (n-1) uniqs2 (Var restNId)+    let (uniqs3,restVs) = if n < 2 then (uniqs2,[]) else second toList (go (n-1) uniqs2 (Var restNId)) +    return (uniqs3,(elNVar,(elNId, lhs) :| [(restNId, rhs)]) :| restVs)+ -- | Create let-bindings with case-statements that select elements out of a -- tree. Returns both the variables to which element-selections are bound -- and the let-bindings@@ -214,35 +223,31 @@      -> (Supply,InScopeSet)      -> Term      -> ((Supply,InScopeSet),([Term],[(Id, Term)]))-  go 0 _ ks uniqs0 e = (uniqs1,([elNVar],[(elNId, rhs)]))-   where-    tys          = [LitTy (NumTy 0),resTy]-    (Just idTys) = dataConInstArgTys lrCon tys+  go 0 _ ks uniqs0 e = fromMaybe (error "extractTElems: failed to project elements") $ do+    let tys = [LitTy (NumTy 0),resTy]+    idTys <- dataConInstArgTys lrCon tys+    (k,_) <- uncons ks -    (uniqs1,[elNId,co,el]) =+    (uniqs1,[elNId,co,el]) <- pure $       mapAccumR mkUniqSystemId uniqs0 $ zipEqual-        [ "el" `T.append` (s `T.cons` T.pack (show (head ks)))+        [ "el" `T.append` (s `T.cons` T.pack (show k))         , "_co_"         , "el"         ]         (resTy:idTys)-    elNVar = Var elNId-    pat    = DataPat lrCon [] [co,el]-    rhs    = Case e resTy [(pat,Var el)]+    let elNVar = Var elNId+        pat    = DataPat lrCon [] [co,el]+        rhs    = Case e resTy [(pat,Var el)]+    return (uniqs1,([elNVar],[(elNId, rhs)])) -  go n bs ks uniqs0 e =-    (uniqs4-    ,(lVars ++ rVars,(ltNId, ltRhs):-                     (rtNId, rtRhs):-                     (lBinds ++ rBinds)))-   where-    tys = [LitTy (NumTy n),resTy,LitTy (NumTy (n-1))]-    (Just idTys) = dataConInstArgTys brCon tys+  go n bs ks uniqs0 e = fromMaybe (error "extractTElems: failed to project elements") $ do+    let tys = [LitTy (NumTy n),resTy,LitTy (NumTy (n-1))]+    idTys <- dataConInstArgTys brCon tys -    (uniqs1,mTV) = mkUniqSystemTyVar uniqs0 ("m",typeNatKind)-    (b0:bL,b1:bR) = splitAt (length bs `div` 2) bs-    brTy = last idTys-    (uniqs2,[ltNId,rtNId,co,lt,rt]) =+    let (uniqs1,mTV) = mkUniqSystemTyVar uniqs0 ("m",typeNatKind)+    (b0:bL,b1:bR) <- pure (splitAt (length bs `div` 2) bs)+    let brTy = last idTys+    (uniqs2,[ltNId,rtNId,co,lt,rt]) <- pure $       mapAccumR mkUniqSystemId uniqs1 $ zipEqual         ["lt" `T.append` (s `T.cons` T.pack (show b0))         ,"rt" `T.append` (s `T.cons` T.pack (show b1))@@ -251,16 +256,22 @@         ,"rt"         ]         (brTy:brTy:idTys)-    ltVar = Var ltNId-    rtVar = Var rtNId-    pat   = DataPat brCon [mTV] [co,lt,rt]-    ltRhs = Case e brTy [(pat,Var lt)]-    rtRhs = Case e brTy [(pat,Var rt)]+    let ltVar = Var ltNId+        rtVar = Var rtNId+        pat   = DataPat brCon [mTV] [co,lt,rt]+        ltRhs = Case e brTy [(pat,Var lt)]+        rtRhs = Case e brTy [(pat,Var rt)] -    (kL,kR) = splitAt (length ks `div` 2) ks-    (uniqs3,(lVars,lBinds)) = go (n-1) bL kL uniqs2 ltVar-    (uniqs4,(rVars,rBinds)) = go (n-1) bR kR uniqs3 rtVar+        (kL,kR) = splitAt (length ks `div` 2) ks+        (uniqs3,(lVars,lBinds)) = go (n-1) bL kL uniqs2 ltVar+        (uniqs4,(rVars,rBinds)) = go (n-1) bR kR uniqs3 rtVar +    return ( uniqs4+           , ( lVars ++ rVars+             , (ltNId, ltRhs):(rtNId, rtRhs): (lBinds ++ rBinds)+             )+           )+ -- | Create a vector of supplied elements mkRTree :: DataCon -- ^ The LR constructor         -> DataCon -- ^ The BR constructor@@ -285,12 +296,15 @@                               ,Left (go (n-1) xsL)                               ,Left (go (n-1) xsR)] -    lrCoTy   = head (fromJust $! dataConInstArgTys lrCon  [(LitTy (NumTy 0))-                                                         ,resTy])-    brCoTy n = head (fromJust $! dataConInstArgTys brCon-                                                   [(LitTy (NumTy n))-                                                   ,resTy-                                                   ,(LitTy (NumTy (n-1)))])+    lrCoTy   = case dataConInstArgTys lrCon [(LitTy (NumTy 0)) ,resTy] of+                 Just (x:_) -> x+                 _ -> error "impossible"+    brCoTy n = case dataConInstArgTys brCon+                                      [(LitTy (NumTy n))+                                      ,resTy+                                      ,(LitTy (NumTy (n-1)))] of+                 Just (x:_) -> x+                 _ -> error "impossible"  -- | Determine whether a type is isomorphic to "Clash.Signal.Internal.Signal" --@@ -315,7 +329,7 @@       "Clash.Signal.BiSignal.BiSignalIn"  -> True       "Clash.Signal.BiSignal.BiSignalOut" -> True       _ | tcNm `HashSet.member` tcSeen    -> False -- Do not follow rec types-        | otherwise -> case lookupUniqMap tcNm tcm of+        | otherwise -> case UniqMap.lookup tcNm tcm of             Just tc -> let dcs         = tyConDataCons tc                            dcInsArgTys = concat                                        $ mapMaybe (`dataConInstArgTys` args) dcs@@ -344,6 +358,7 @@ isClockOrReset m (coreView1 m -> Just ty)    = isClockOrReset m ty isClockOrReset _ (tyView -> TyConApp tcNm _) = case nameOcc tcNm of   "Clash.Signal.Internal.Clock" -> True+  "Clash.Signal.Internal.ClockN" -> True   "Clash.Signal.Internal.Reset" -> True   _ -> False isClockOrReset _ _ = False@@ -472,6 +487,7 @@   , "GHC.Err.error"   , "GHC.Err.errorWithoutStackTrace"   , "GHC.Err.undefined"+  , "GHC.Prim.Panic.absentError"   , "GHC.Real.divZeroError"   , "GHC.Real.overflowError"   , "GHC.Real.ratioZeroDenominatorError"@@ -552,7 +568,7 @@   -> TypeView   -> Maybe ([Term] -> Term, Projections, [Type]) shouldSplit0 tcm (TyConApp tcNm tyArgs)-  | Just tc <- lookupUniqMap tcNm tcm+  | Just tc <- UniqMap.lookup tcNm tcm   , [dc] <- tyConDataCons tc   , let dcArgs = substArgTys dc tyArgs   , let dcArgsLen = length dcArgs@@ -571,7 +587,7 @@   , [nTy,argTy] <- tyArgs   , Right n <- runExcept (tyNatSize tcm nTy)   , n > 1-  , Just tc <- lookupUniqMap tcNm tcm+  , Just tc <- UniqMap.lookup tcNm tcm   , [nil,cons] <- tyConDataCons tc   = if shouldSplitTy (tyView (coreView tcm argTy)) then       Just ( mkVec nil cons argTy n@@ -603,7 +619,7 @@   -- to it being a zero-width type   --   -- TODO: This currently only handles (IP $x, KnownDomain) given that $x is any-  -- TODO: of the constructs handled in 'splitTy'. In practise this means only+  -- TODO: of the constructs handled in 'splitTy'. In practice this means only   -- TODO: HiddenClock, HiddenReset, and HiddenEnable are handled. If a user were   -- TODO: to define their own versions with -for example- the elements of the   -- TODO: tuple swapped, 'isHidden' wouldn't recognize it. We could generalize@@ -616,9 +632,9 @@     && nameOcc a2Nm == "Clash.Signal.Internal.KnownDomain"   isHidden _ _ = False -  -- Currently we're only interested in splitting of Clock, Reset, and Enable   splitTy (TyConApp tcNm0 _)     = nameOcc tcNm0 `elem` [ "Clash.Signal.Internal.Clock"+                           , "Clash.Signal.Internal.ClockN"                            , "Clash.Signal.Internal.Reset"                            , "Clash.Signal.Internal.Enable"                            -- iverilog doesn't like it when we put file handles@@ -663,9 +679,9 @@ -- | Do an inverse topological sorting of the let-bindings in a let-expression inverseTopSortLetBindings   :: HasCallStack-  => Term-  -> Term-inverseTopSortLetBindings (Letrec bndrs0 res) =+  => [(Id, Term)]+  -> [(Id, Term)]+inverseTopSortLetBindings bndrs0 =   let (graph,nodeMap,_) =         Graph.graphFromEdges           (map (\(i,e) -> let fvs = fmap varUniq@@ -673,7 +689,7 @@                           in  ((i,e),varUniq i,fvs)) bndrs0)       nodes  = postOrd graph       bndrs1 = map ((\(x,_,_) -> x) . nodeMap) nodes-  in  Letrec bndrs1 res+   in bndrs1  where   postOrd :: Graph.Graph -> [Graph.Vertex]   postOrd g = postorderF (Graph.dff g) []@@ -683,8 +699,6 @@    postorder :: Graph.Tree a -> [a] -> [a]   postorder (Graph.Node a ts) = postorderF ts . (a :)--inverseTopSortLetBindings e = e {-# SCC inverseTopSortLetBindings #-}  -- | Group let-bindings into cyclic groups and acyclic individual bindings@@ -714,12 +728,14 @@   where     go (coreView1 tcm -> Just ty') = go ty'     go scrutTy@(tyView -> TyConApp tc args) =-      case tyConDataCons (lookupUniqMap' tcm tc) of+      case tyConDataCons (UniqMap.find tc tcm) of         [] -> cantCreate $(curLoc) ("TyCon has no DataCons: " ++ show tc ++ " " ++ showPpr tc) scrutTy         dcs | dcI > length dcs -> cantCreate $(curLoc) "DC index exceeds max" scrutTy             | otherwise -> do           let dc = indexNote ($(curLoc) ++ "No DC with tag: " ++ show (dcI-1)) dcs (dcI-1)-          let (Just fieldTys) = dataConInstArgTysE inScope tcm dc args+          let fieldTys =+                fromMaybe (cantCreate $(curLoc) "Cannot instantiate dataCon" scrutTy)+                          (dataConInstArgTysE inScope tcm dc args)           if fieldI >= length fieldTys             then cantCreate $(curLoc) "Field index exceed max" scrutTy             else do@@ -732,6 +748,7 @@               return retVal     go scrutTy = cantCreate $(curLoc) ("Type of subject is not a datatype: " ++ showPpr scrutTy) scrutTy +    cantCreate :: String -> String -> Type -> a     cantCreate loc info scrutTy = error $ loc ++ "Can't create selector " ++ show (caller,dcI,fieldI) ++ " for: (" ++ showPpr scrut ++ " :: " ++ showPpr scrutTy ++ ")\nAdditional info: " ++ info  -- | Make a binder that should not be referenced
src/Clash/Core/Var.hs view
@@ -14,8 +14,7 @@ {-# LANGUAGE RankNTypes #-}  module Clash.Core.Var-  ( Attr' (..)-  , Var (..)+  ( Var (..)   , IdScope (..)   , Id   , TyVar@@ -27,7 +26,6 @@   , modifyVarName   , isGlobalId   , isLocalId-  , attrName   ) where @@ -41,24 +39,6 @@ import {-# SOURCE #-} Clash.Core.Term   (Term, TmName) import {-# SOURCE #-} Clash.Core.Type   (Kind, Type, TyName) import Clash.Unique----- | Interal version of Clash.Annotations.SynthesisAttributes.Attr.------ Needed because Clash.Annotations.SynthesisAttributes.Attr uses the Symbol--- kind for names, which do not have a term-level representation-data Attr'-  = BoolAttr' String Bool-  | IntegerAttr' String Integer-  | StringAttr' String String-  | Attr' String-  deriving (Eq, Show, NFData, Generic, Hashable, Ord, Binary)--attrName :: Attr' -> String-attrName (BoolAttr' n _)    = n-attrName (IntegerAttr' n _) = n-attrName (StringAttr' n _)  = n-attrName (Attr' n)          = n  -- | Variables in CoreHW data Var a
src/Clash/Core/VarEnv.hs view
@@ -25,6 +25,7 @@   , delVarEnvList   , unionVarEnv   , unionVarEnvWith+  , differenceVarEnv     -- ** Element-wise operations     -- *** Mapping   , mapVarEnv@@ -115,6 +116,8 @@  import           Clash.Core.Pretty         () import           Clash.Core.Var+import           Clash.Data.UniqMap        (UniqMap)+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Debug               (debugIsOn) import           Clash.Unique import           Clash.Util@@ -128,28 +131,28 @@ -- | Empty map emptyVarEnv   :: VarEnv a-emptyVarEnv = emptyUniqMap+emptyVarEnv = UniqMap.empty  -- | Environment containing a single variable-value pair unitVarEnv   :: Var b   -> a   -> VarEnv a-unitVarEnv = unitUniqMap+unitVarEnv = UniqMap.singleton  -- | Look up a value based on the variable lookupVarEnv   :: Var b   -> VarEnv a   -> Maybe a-lookupVarEnv = lookupUniqMap+lookupVarEnv = UniqMap.lookup  -- | Lookup a value based on the unique of a variable lookupVarEnvDirectly   :: Unique   -> VarEnv a   -> Maybe a-lookupVarEnvDirectly = lookupUniqMap+lookupVarEnvDirectly = UniqMap.lookup  -- | Lookup a value based on the variable --@@ -159,21 +162,21 @@   => VarEnv a   -> Var b   -> a-lookupVarEnv' = lookupUniqMap'+lookupVarEnv' = flip UniqMap.find  -- | Remove a variable-value pair from the environment delVarEnv   :: VarEnv a   -> Var b   -> VarEnv a-delVarEnv = delUniqMap+delVarEnv = flip UniqMap.delete  -- | Remove a list of variable-value pairs from the environment delVarEnvList   :: VarEnv a   -> [Var b]   -> VarEnv a-delVarEnvList = delListUniqMap+delVarEnvList = flip UniqMap.deleteMany  -- | Add a variable-value pair to the environment; overwrites the value if the -- variable already exists@@ -182,7 +185,7 @@   -> a   -> VarEnv a   -> VarEnv a-extendVarEnv = extendUniqMap+extendVarEnv = UniqMap.insert  -- | Add a variable-value pair to the environment; if the variable already -- exists, the two values are merged with the given function@@ -192,7 +195,8 @@   -> (a -> a -> a)   -> VarEnv a   -> VarEnv a-extendVarEnvWith = extendUniqMapWith+extendVarEnvWith k v f =+  UniqMap.insertWith f k v  -- | Add a list of variable-value pairs; the values of existing keys will be -- overwritten@@ -200,20 +204,20 @@   :: VarEnv a   -> [(Var b, a)]   -> VarEnv a-extendVarEnvList = extendListUniqMap+extendVarEnvList = flip UniqMap.insertMany  -- | Is the environment empty nullVarEnv   :: VarEnv a   -> Bool-nullVarEnv = nullUniqMap+nullVarEnv = UniqMap.null  -- | Get the (left-biased) union of two environments unionVarEnv   :: VarEnv a   -> VarEnv a   -> VarEnv a-unionVarEnv = unionUniqMap+unionVarEnv = (<>)  -- | Get the union of two environments, mapped values existing in both -- environments will be merged with the given function.@@ -222,20 +226,27 @@   -> VarEnv a   -> VarEnv a   -> VarEnv a-unionVarEnvWith = unionUniqMapWith+unionVarEnvWith = UniqMap.unionWith +-- | Filter the first varenv to only contain keys which are not in the second varenv.+differenceVarEnv+  :: VarEnv a+  -> VarEnv a+  -> VarEnv a+differenceVarEnv = UniqMap.difference+ -- | Create an environment given a list of var-value pairs mkVarEnv   :: [(Var a,b)]   -> VarEnv b-mkVarEnv = listToUniqMap+mkVarEnv = UniqMap.fromList  -- | Apply a function to every element in the environment mapVarEnv   :: (a -> b)   -> VarEnv a   -> VarEnv b-mapVarEnv = mapUniqMap+mapVarEnv = fmap  -- | Apply a function to every element in the environment; values for which the -- function returns 'Nothing' are removed from the environment@@ -243,7 +254,7 @@   :: (a -> Maybe b)   -> VarEnv a   -> VarEnv b-mapMaybeVarEnv = mapMaybeUniqMap+mapMaybeVarEnv = UniqMap.mapMaybe  -- | Strict left-fold over an environment using both the unique of the -- the variable and the value@@ -252,78 +263,78 @@   -> a   -> VarEnv b   -> a-foldlWithUniqueVarEnv' = foldlWithUnique'+foldlWithUniqueVarEnv' = UniqMap.foldlWithUnique'  -- | Extract the elements eltsVarEnv   :: VarEnv a   -> [a]-eltsVarEnv = eltsUniqMap+eltsVarEnv = UniqMap.elems  -- | Does the variable exist in the environment elemVarEnv   :: Var a   -> VarEnv b   -> Bool-elemVarEnv = elemUniqMap+elemVarEnv = UniqMap.elem  -- | Does the variable not exist in the environment notElemVarEnv   :: Var a   -> VarEnv b   -> Bool-notElemVarEnv = notElemUniqMap+notElemVarEnv = UniqMap.notElem  -- * VarSet  -- | Set of variables-type VarSet = UniqSet (Var Any)+type VarSet = UniqMap (Var Any)  -- | The empty set emptyVarSet   :: VarSet-emptyVarSet = emptyUniqSet+emptyVarSet = UniqMap.empty  -- | The set of a single variable unitVarSet   :: Var a   -> VarSet-unitVarSet v = unitUniqSet (coerce v)+unitVarSet v = UniqMap.singletonUnique (coerce v)  -- | Add a variable to the set extendVarSet   :: VarSet   -> Var a   -> VarSet-extendVarSet env v = extendUniqSet env (coerce v)+extendVarSet env v = UniqMap.insertUnique (coerce v) env  -- | Union two sets unionVarSet   :: VarSet   -> VarSet   -> VarSet-unionVarSet = unionUniqSet+unionVarSet = (<>)  -- | Take the difference of two sets differenceVarSet   :: VarSet   -> VarSet   -> VarSet-differenceVarSet = differenceUniqSet+differenceVarSet = UniqMap.difference  -- | Is the variable an element in the set elemVarSet   :: Var a   -> VarSet   -> Bool-elemVarSet v = elemUniqSet (coerce v)+elemVarSet v = UniqMap.elem (getUnique v)  -- | Is the variable not an element in the set notElemVarSet   :: Var a   -> VarSet   -> Bool-notElemVarSet v = notElemUniqSet (coerce v)+notElemVarSet v = UniqMap.notElem (getUnique v)  -- | Is the set of variables A a subset of the variables B subsetVarSet@@ -332,45 +343,45 @@   -> VarSet   -- ^ Set of variables B   -> Bool-subsetVarSet = subsetUniqSet+subsetVarSet = UniqMap.submap  -- | Are the sets of variables disjoint disjointVarSet   :: VarSet   -> VarSet   -> Bool-disjointVarSet = disjointUniqSet+disjointVarSet = UniqMap.disjoint  -- | Check whether a varset is empty nullVarSet   :: VarSet   -> Bool-nullVarSet = nullUniqSet+nullVarSet = UniqMap.null  -- | Look up a variable in the set, returns it if it exists lookupVarSet   :: Var a   -> VarSet   -> Maybe (Var Any)-lookupVarSet = lookupUniqSet+lookupVarSet = UniqMap.lookup  -- | Remove a variable from the set based on its 'Unique' delVarSetByKey   :: Unique   -> VarSet   -> VarSet-delVarSetByKey = delUniqSetDirectly+delVarSetByKey = UniqMap.delete  -- | Create a set from a list of variables mkVarSet   :: [Var a]   -> VarSet-mkVarSet xs = mkUniqSet (coerce xs)+mkVarSet xs = UniqMap.fromList $ fmap (\x -> (getUnique x, coerce x)) xs  eltsVarSet   :: VarSet   -> [Var Any]-eltsVarSet = eltsUniqSet+eltsVarSet = UniqMap.elems  -- * InScopeSet @@ -440,7 +451,7 @@   :: Unique   -> InScopeSet   -> Bool-elemUniqInScopeSet u (InScopeSet s _) = u `elemUniqSetDirectly` s+elemUniqInScopeSet u (InScopeSet s _) = UniqMap.elem u s  -- | Is the variable not in scope notElemInScopeSet@@ -467,7 +478,7 @@   -> a   -> a uniqAway (InScopeSet set n) a =-  uniqAway' (`elemUniqSetDirectly` set) n a+  uniqAway' (`UniqMap.elem` set) n a  uniqAway'   :: (Uniquable a, ClashPretty a)
+ src/Clash/Data/UniqMap.hs view
@@ -0,0 +1,235 @@+{-+Copyright   : (C) 2016-2021 QBayLogic B.V.+                       2022 Alexander McKenna+License     : BSD2 (see the file LICENSE)+Maintainer  : QBayLogic B.V. <devops@qbaylogic.com>+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}++module Clash.Data.UniqMap+  ( UniqMap(..)+  , empty+  , singleton+  , singletonUnique+  , null+  , insert+  , insertUnique+  , insertWith+  , insertMany+  , lookup+  , find+  , elem+  , notElem+  , filter+  , mapMaybe+  , foldrWithUnique+  , foldlWithUnique'+  , delete+  , deleteMany+  , unionWith+  , difference+  , disjoint+  , submap+  , fromList+  , toList+  , keys+  , elems+  ) where++import           Prelude hiding (elem, filter, lookup, notElem, null)++import           Control.DeepSeq (NFData)+import           Data.Binary (Binary)+import           Data.Bifunctor (first)+import           Data.Function (on)+import           Data.IntMap.Strict (IntMap)+import qualified Data.IntMap.Strict as IntMap+import qualified Data.List as List (foldl')++#if !MIN_VERSION_containers(0,6,2)+import qualified Data.IntMap.Extra as IntMap+#endif++#if MIN_VERSION_prettyprinter(1,7,0)+import           Prettyprinter+#else+import           Data.Text.Prettyprint.Doc+#endif++import           Clash.Pretty+import           Clash.Unique (Unique, Uniquable(getUnique))++-- | A map indexed by a 'Unique'. Typically the elements of this map are also+-- uniqueable and provide their own key, however a unique can be associated+-- with any value.+newtype UniqMap a+  = UniqMap { uniqMapToIntMap :: IntMap a }+  deriving stock Traversable+  deriving newtype+    ( Binary+    , Foldable+    , Functor+    , Monoid+    , NFData+    , Semigroup+    , Show+    )++instance ClashPretty a => ClashPretty (UniqMap a) where+  clashPretty xs =+    brackets $ fillSep $ punctuate comma $+      [ fromPretty k <+> ":->" <+> clashPretty v+      | (k, v) <- toList xs+      ]++-- | An empty map.+empty :: UniqMap a+empty =+  UniqMap IntMap.empty++{-# SPECIALIZE singleton :: Unique -> b -> UniqMap b #-}+-- | A map containing a single value indexed by the given key's unique.+singleton :: Uniquable a => a -> b -> UniqMap b+singleton k v =+  UniqMap (IntMap.singleton (getUnique k) v)++{-# SPECIALIZE singletonUnique :: Unique -> UniqMap Unique #-}+-- | A map containing a single value indexed by the value's unique.+singletonUnique :: Uniquable a => a -> UniqMap a+singletonUnique v =+  singleton (getUnique v) v++-- | Check if the map is empty.+null :: UniqMap a -> Bool+null =+  IntMap.null . uniqMapToIntMap++{-# SPECIALIZE insert :: Unique -> b -> UniqMap b -> UniqMap b #-}+-- | Insert a new key-value pair into the map.+insert :: Uniquable a => a -> b -> UniqMap b -> UniqMap b+insert k v =+  UniqMap . IntMap.insert (getUnique k) v . uniqMapToIntMap++{-# SPECIALIZE insertUnique :: Unique -> UniqMap Unique -> UniqMap Unique #-}+-- | Insert a new value into the map, using the unique of the value as the key.+insertUnique :: Uniquable a => a -> UniqMap a -> UniqMap a+insertUnique v =+  insert (getUnique v) v++-- | Insert a new key-value pair into the map, using the given combining+-- function if there is already an entry with the same unique in the map.+insertWith :: Uniquable a => (b -> b -> b) -> a -> b -> UniqMap b -> UniqMap b+insertWith f k v =+  UniqMap . IntMap.insertWith f (getUnique k) v . uniqMapToIntMap++-- | Insert a list of key-value pairs into the map.+insertMany :: Uniquable a => [(a, b)] -> UniqMap b -> UniqMap b+insertMany kvs xs =+  List.foldl' (\acc (k, v) -> insert k v acc) xs kvs++{-# SPECIALIZE lookup :: Unique -> UniqMap b -> Maybe b #-}+-- | Lookup an item in the map, using the unique of the given key.+lookup :: Uniquable a => a -> UniqMap b -> Maybe b+lookup k =+  IntMap.lookup (getUnique k) . uniqMapToIntMap++{-# SPECIALIZE find :: Unique -> UniqMap b -> b #-}+-- | Lookup and item in the map, using the unique of the given key. If the item+-- is not found in the map an error is raised.+find :: Uniquable a => a -> UniqMap b -> b+find k =+  let notFound =+        error ("find: Key " <> show (getUnique k) <> " is not in the UniqMap")+   in IntMap.findWithDefault notFound (getUnique k) . uniqMapToIntMap++{-# SPECIALIZE elem :: Unique -> UniqMap b -> Bool #-}+-- | Check if there is an entry in the map for the unique of the given value.+elem :: Uniquable a => a -> UniqMap b -> Bool+elem k =+  IntMap.member (getUnique k) . uniqMapToIntMap++{-# SPECIALIZE notElem :: Unique -> UniqMap b -> Bool #-}+-- | Check if there is not an entry in the map for the unique of the given+-- value.+notElem :: Uniquable a => a -> UniqMap b -> Bool+notElem k =+  IntMap.notMember (getUnique k) . uniqMapToIntMap++-- | Filter all elements in the map according to some predicate.+filter :: (b -> Bool) -> UniqMap b -> UniqMap b+filter p =+  UniqMap . IntMap.filter p . uniqMapToIntMap++-- | Apply a function to all elements in the map, keeping those where the+-- result is not @Nothing@.+mapMaybe :: (a -> Maybe b) -> UniqMap a -> UniqMap b+mapMaybe f =+  UniqMap . IntMap.mapMaybe f . uniqMapToIntMap++-- | Lazily right-fold over the map using the given function.+foldrWithUnique :: (Unique -> a -> b -> b) -> b -> UniqMap a -> b+foldrWithUnique f x =+  IntMap.foldrWithKey f x . uniqMapToIntMap++-- | Strictly left-fold over the map using the given function.+foldlWithUnique' :: (b -> Unique -> a -> b) -> b -> UniqMap a -> b+foldlWithUnique' f x =+  IntMap.foldlWithKey' f x . uniqMapToIntMap++{-# SPECIALIZE delete :: Unique -> UniqMap b -> UniqMap b #-}+-- | Delete the entry in the map indexed by the unique of the given value.+delete :: Uniquable a => a -> UniqMap b -> UniqMap b+delete k =+  UniqMap . IntMap.delete (getUnique k) . uniqMapToIntMap++-- | Delete all entries in the map indexed by the uniques of the given values.+deleteMany :: Uniquable a => [a] -> UniqMap b -> UniqMap b+deleteMany ks xs =+  List.foldl' (\acc k -> delete k acc) xs ks++-- | Merge two unique maps, using the given combining funcion if a value with+-- the same unique key exists in both maps.+unionWith :: (b -> b -> b) -> UniqMap b -> UniqMap b -> UniqMap b+unionWith f xs ys =+  UniqMap ((IntMap.unionWith f `on` uniqMapToIntMap) xs ys)++-- | Filter the first map to only contain keys which are not in the second map.+difference :: UniqMap b -> UniqMap b -> UniqMap b+difference xs ys =+  UniqMap ((IntMap.difference `on` uniqMapToIntMap) xs ys)++-- | Check if there are no common keys between two maps.+disjoint :: UniqMap b -> UniqMap b -> Bool+disjoint =+  IntMap.disjoint `on` uniqMapToIntMap++-- | Check if one map is a submap of another.+submap :: UniqMap b -> UniqMap b -> Bool+submap =+  -- We only check that the keys of the map make it a submap, the elements do+  -- not need to be equal. Maybe this should be changed?+  IntMap.isSubmapOfBy (\_ _ -> True) `on` uniqMapToIntMap++{-# SPECIALIZE fromList :: [(Unique, b)] -> UniqMap b #-}+-- | Convert a list of key-value pairs to a map.+fromList :: Uniquable a => [(a, b)] -> UniqMap b+fromList =+  UniqMap . IntMap.fromList . fmap (first getUnique)++-- | Convert a map to a list of unique-value pairs.+toList :: UniqMap b -> [(Unique, b)]+toList =+  IntMap.toList . uniqMapToIntMap++-- | Get the unique keys of a map.+keys :: UniqMap b -> [Unique]+keys =+  IntMap.keys . uniqMapToIntMap++-- | Get the values of a map.+elems :: UniqMap b -> [b]+elems =+  IntMap.elems . uniqMapToIntMap
+ src/Clash/DataFiles.hs view
@@ -0,0 +1,63 @@+{-|+Copyright   :  (C) 2022     , Google Inc.+License     :  BSD2 (see the file LICENSE)+Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>++This module provides a way to access static files that are useful when working+with Clash designs.+-}++module Clash.DataFiles where++import System.FilePath ((</>))++import Paths_clash_lib (getDataFileName)++{- | The Tcl Connector: a Tcl script that can parse Clash output and emit the+  correct commands for loading the design into Vivado (Quartus support will be+  added later).++  Apart from parsing the @clash-manifest.json@ files produced by Clash, the Tcl+  Connector also supports the so-called /Clash\<->Tcl API/. This functionality+  enables Clash primitives to pass complex instructions to the Tcl Connector.+  Current features are instantiating IP in Vivado and passing metadata along+  with Vivado XDC files.++  An example use of the Tcl Connector, demonstrating its basic features:++  > source -notrace clashConnector.tcl+  > # Pass it the path to "clash-manifest.json" of your top entity+  > clash::readMetadata vhdl/Design.topEntity+  > # Instantiate IP (no-op if no IP defined)+  > file mkdir ip+  > clash::createAndReadIp -dir ip+  > # Read all VHDL/Verilog/SystemVerilog files generated by Clash+  > clash::readHdl+  > # Handle XDC files, in correct order+  > clash::readXdc early+  > # A file containing PACKAGE_PIN and IOSTANDARD definitions (but not+  > # create_clock, clocks are part of the Clash-generated files)+  > read_xdc Arty-A7-35-Master.xdc+  > set_property USED_IN implementation [get_files Arty-A7-35-Master.xdc]+  > clash::readXdc {normal late}+  > synth_design -top $clash::topEntity -part xc7a35ticsg324-1L+  > opt_design+  > place_design+  > route_design+  > write_bitstream ${clash::topEntity}.bit++  "Clash.Xilinx.ClockGen" and @clash-cores:Clash.Cores.Xilinx@+  modules make use of the IP instantiating functionality; XDC metadata+  functionality is not currently used as the IP is already packaged with correct+  constraints by Vivado.++  More documentation about the Tcl Connector and the Clash\<->Tcl API will be+  made available later.++  In addition to this module, you can also write a copy of the Tcl script to a+  file by invoking++  > cabal run clash-lib:static-files -- --tcl-connector clashConnector.tcl+-}+tclConnector :: IO FilePath+tclConnector = getDataFileName $ "data-files" </> "tcl" </> "clashConnector.tcl"
src/Clash/Driver.hs view
@@ -2,7 +2,7 @@   Copyright   :  (C) 2012-2016, University of Twente,                      2016-2017, Myrtle Software Ltd,                      2017     , QBayLogic, Google Inc.-                     2020-2022, QBayLogic,+                     2020-2023, QBayLogic,                      2022     , Google Inc.    License     :  BSD2 (see the file LICENSE)@@ -35,7 +35,7 @@ import           Control.Monad.State.Strict       (State) import qualified Control.Monad.State.Strict       as State import qualified Crypto.Hash.SHA256               as Sha256-import           Data.Bifunctor                   (first)+import           Data.Bifunctor                   (first, second) import           Data.ByteString                  (ByteString) import qualified Data.ByteString                  as ByteString import qualified Data.ByteString.Lazy             as ByteStringLazy@@ -48,6 +48,7 @@ import qualified Data.HashSet                     as HashSet import           Data.Proxy                       (Proxy(..)) import           Data.List                        (intercalate)+import qualified Data.List                        as List import           Data.Maybe                       (fromMaybe, maybeToList, mapMaybe) import qualified Data.Map.Ordered                 as OMap import           Data.Map.Ordered.Extra           ()@@ -138,7 +139,9 @@ import qualified Clash.Primitives.GHC.Int         as P import qualified Clash.Primitives.GHC.Word        as P import qualified Clash.Primitives.Intel.ClockGen  as P+import qualified Clash.Primitives.Magic           as P import qualified Clash.Primitives.Verification    as P+import qualified Clash.Primitives.Xilinx.ClockGen as P import           Clash.Primitives.Types import           Clash.Signal.Internal import           Clash.Unique                     (Unique, getUnique)@@ -313,8 +316,8 @@   -> WHNF.Evaluator   -- ^ Hardcoded evaluator for WHNF (old evaluator)   -> Maybe (TopEntityT, [TopEntityT])-  -- ^ Main top entity to compile. If Nothing, all top entities in previous-  -- argument will be compiled.+  -- ^ Main top entity to compile. If Nothing, all top entities in the+  -- 'ClashDesign' argument will be compiled.   -> Clock.UTCTime   -> IO () generateHDL env design hdlState typeTrans peEval eval mainTopEntity startTime = do@@ -361,7 +364,7 @@     -> TopEntityT     -> IO ()   go compNames seenV edamFilesV ioLockV deps topEntityMap (TopEntityT topEntity annM isTb) = do-  let domainConfs = designDomains design+  let domainConfs = envDomains env   let bindingsMap = designBindings design   let primMap = envPrimitives env   let topEntities0 = designEntities design@@ -467,7 +470,7 @@        -- 4. Generate topEntity wrapper       (hdlDocs, dfiles, mfiles) <- withMVar seenV $ \seen ->-        pure $! createHDL hdlState' modNameT seen netlist domainConfs topComponent topNmT+        pure $! createHDL hdlState' opts modNameT seen netlist domainConfs topComponent topNmT        -- TODO: Data files should go into their own directory       -- FIXME: Files can silently overwrite each other@@ -478,9 +481,11 @@       let         components = map (snd . snd) (OMap.assocs netlist)         filesAndDigests0 =-             zip (map fst hdlDocs) hdlDocDigests+          -- FIXME: We should track dependencies of `mfiles` and `dfiles` and+          -- maintain the proper topological sort of all these.+             zip (map fst mfiles) memoryFilesDigests           <> zip (map fst dfiles) dataFilesDigests-          <> zip (map fst mfiles) memoryFilesDigests+          <> zip (map fst hdlDocs) hdlDocDigests        filesAndDigests1 <- modifyMVar edamFilesV $ \edamFiles ->         if opt_edalize opts@@ -573,6 +578,7 @@     [ ('P.checkBBF, P.checkBBF)     , ('P.bvToIntegerVHDL, P.bvToIntegerVHDL)     , ('P.bvToIntegerVerilog, P.bvToIntegerVerilog)+    , ('P.clashCompileErrorBBF, P.clashCompileErrorBBF)     , ('P.foldBBF, P.foldBBF)     , ('P.indexIntVerilog, P.indexIntVerilog)     , ('P.indexToIntegerVerilog, P.indexToIntegerVerilog)@@ -596,6 +602,10 @@     , ('P.alteraPllTF, P.alteraPllTF)     , ('P.altpllTF, P.altpllTF)     , ('P.fromIntegerTFvhdl, P.fromIntegerTFvhdl)+    , ('P.clockWizardTF, P.clockWizardTF)+    , ('P.clockWizardDifferentialTF, P.clockWizardDifferentialTF)+    , ('P.clockWizardTclTF, P.clockWizardTclTF)+    , ('P.clockWizardDifferentialTclTF, P.clockWizardDifferentialTclTF)     ]  -- | Compiles blackbox functions and parses blackbox templates.@@ -661,14 +671,14 @@       loadImportAndInterpret idirs args topDir qualMod funcName "BlackBoxFunction"  compilePrimitive idirs pkgDbs topDir-  (BlackBox pNm wf rVoid multiRes tkind () oReg libM imps fPlural incs rM riM templ) = do+  (BlackBox pNm wf rVoid multiRes tkind () outputUsage libM imps fPlural incs rM riM templ) = do   libM'  <- mapM parseTempl libM   imps'  <- mapM parseTempl imps   incs'  <- mapM (traverse parseBB) incs   templ' <- parseBB templ   rM'    <- traverse parseBB rM   riM'   <- traverse parseBB riM-  return (BlackBox pNm wf rVoid multiRes tkind () oReg libM' imps' fPlural incs' rM' riM' templ')+  return (BlackBox pNm wf rVoid multiRes tkind () outputUsage libM' imps' fPlural incs' rM' riM' templ')  where   iArgs = concatMap (("-package-db":) . (:[])) pkgDbs @@ -746,6 +756,8 @@   :: Backend backend   => backend   -- ^ Backend+  -> ClashOpts+  -- ^ Global Clash options   -> IdentifierText   -- ^ Module hierarchy root   -> Id.IdentifierSet@@ -761,21 +773,21 @@   -> ([(String,Doc)],[(String,FilePath)],[(String,String)])   -- ^ The pretty-printed HDL documents   -- + The data files that need to be copied-createHDL backend modName seen components domainConfs top topName = flip evalState backend $ getAp $ do+createHDL backend opts modName seen components domainConfs top topName = flip evalState backend $ getAp $ do   let componentsL = map snd (OMap.assocs components)-  (hdlNmDocs,incs) <-+  (hdlNmDocs0,incs) <-     fmap unzip $-      forM componentsL $ \(ComponentMeta{cmLoc, cmScope}, comp) ->-         genHDL modName cmLoc (Id.union seen cmScope) comp+      forM componentsL $ \(ComponentMeta{cmLoc, cmScope,cmUsage}, comp) ->+         genHDL opts modName cmLoc (Id.union seen cmScope) cmUsage comp    hwtys <- HashSet.toList <$> extractTypes <$> Ap get-  typesPkg <- mkTyPackage modName hwtys+  typesPkg0 <- mkTyPackage modName hwtys   dataFiles <- Ap getDataFiles   memFiles  <- Ap getMemoryDataFiles   let-    hdl = map (first (<.> Clash.Backend.extension backend)) (typesPkg ++ hdlNmDocs)-    qincs = concat incs-    topFiles = hdl ++ qincs+    typesPkg1 = map (first (<.> Clash.Backend.extension backend)) typesPkg0+    hdlNmDocs1 = map (first (<.> Clash.Backend.extension backend)) hdlNmDocs0+    topFiles = concat incs ++ typesPkg1 ++ hdlNmDocs1      topClks = findClocks top     sdcInfo = fmap findDomainConfig <$> topClks@@ -1079,28 +1091,37 @@                             typeTrans peEval eval emptyVarEnv                             topEntities doNorm --- | topologically sort the top entities-sortTop-  :: BindingMap-  -> [TopEntityT]-  -> ([TopEntityT], HashMap Unique [Unique])+-- | Reverse topologically sort given top entities. Also returns a mapping that+-- maps a top entity to its reverse topologically sorted transitive dependencies.+sortTop ::+  BindingMap ->+  [TopEntityT] ->+  ( [TopEntityT]+  , HashMap Unique [Unique]+  ) sortTop bindingsMap topEntities =-  let (nodes,edges) = unzip (map go topEntities)-      edges' = concat edges-  in  case reverseTopSort nodes edges' of-        Left msg   -> error msg-        Right tops -> (tops, mapFrom edges')+  case reverseTopSort nodes edges of+    Left msg   -> error msg+    Right tops -> (tops, mapFrom tops)  where-  go t@(TopEntityT topE _ _) =-    let topRefs = goRefs topE topE-    in  ((varUniq topE,t)-         ,map ((\top -> (varUniq topE, varUniq (topId top)))) topRefs)+  nodes = [(varUniq topE, t) | t@(TopEntityT topE _ _) <- topEntities]+  edges = concatMap getEdges topEntities -  goRefs top i_ =-    let cg = callGraph bindingsMap i_-    in-      filter-        (\t -> topId t /= top && topId t /= i_ && topId t `elemVarEnv` cg)-        topEntities+  getEdges (TopEntityT topE _ _) =+    map+      (\top -> (varUniq topE, topToUnique top))+      (getTransitiveRefs topE) -  mapFrom = HashMap.fromListWith mappend . fmap (fmap pure)+  getTransitiveRefs top =+    let allDeps = callGraph bindingsMap top+    in  filter (\t -> topId t /= top && topId t `elemVarEnv` allDeps) topEntities++  topToUnique = varUniq . topId++  mapFrom tops =+    let+      topIndices = HashMap.fromList (zip (map topToUnique tops) [(0 :: Int)..])+      nonOrdered = HashMap.fromListWith (<>) (map (second pure) edges)+      orderFunc k = fromMaybe (-1) (HashMap.lookup k topIndices)+    in+      HashMap.map (List.sortOn orderFunc) nonOrdered
src/Clash/Driver/Manifest.hs view
@@ -1,5 +1,5 @@ {-|-Copyright  : (C) 2021-2022, QBayLogic B.V.+Copyright  : (C) 2021-2023, QBayLogic B.V. License    : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> @@ -58,7 +58,7 @@ import           Clash.Primitives.Types import           Clash.Core.Var (Id, varName) import           Clash.Netlist.Types-  (TopEntityT, Component(..), HWType (Clock), hwTypeDomain)+  (TopEntityT, Component(..), HWType (Clock, ClockN), hwTypeDomain) import qualified Clash.Netlist.Types as Netlist import qualified Clash.Netlist.Id as Id import           Clash.Netlist.Util (typeSize)@@ -66,7 +66,9 @@ import           Clash.Signal (VDomainConfiguration(..)) import           Clash.Util.Graph (callGraphBindings) -#if MIN_VERSION_ghc(9,0,0)+#if MIN_VERSION_ghc(9,4,0)+import GHC.Data.Bool (OverridingBool(..))+#elif MIN_VERSION_ghc(9,0,0) import GHC.Utils.Misc (OverridingBool(..)) #else import Util (OverridingBool(..))@@ -164,10 +166,8 @@     -- ^ Dependencies of this design (fully qualified binder names). Is a     -- transitive closure of all dependencies.     ---    -- This list is topologically sorted. I.e., a dependency might depend-    -- on any dependency listed after it, but not before it.-    ---    -- TODO: this ordered differs from `fileNames` and `componentNames`. Fix?+    -- This list is reverse topologically sorted. I.e., a component might depend+    -- on any component listed before it, but not after it.   } deriving (Show,Read,Eq)  instance ToJSON Manifest where@@ -291,7 +291,7 @@   mpName = Id.toText portId   mpWidth = typeSize portType   mpDirection = portDir-  mpIsClock = case portType of {Clock _ -> True; _ -> False}+  mpIsClock = case portType of {Clock _ -> True; ClockN _ -> True; _ -> False}   mpDomain = hwTypeDomain portType   mpTypeName = flip evalState backend $ getAp $ do      LText.toStrict . renderOneLine <$> hdlType (External mpName) portType
src/Clash/Driver/Types.hs view
@@ -1,8 +1,9 @@ {-|   Copyright  :  (C) 2013-2016, University of Twente,                     2016-2017, Myrtle Software Ltd,-                    2017     , QBayLogic, Google Inc.-                    2020-2022, QBayLogic+                    2017     , QBayLogic, Google Inc.,+                    2020-2022, QBayLogic,+                    2022     , Google Inc.,   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -41,9 +42,13 @@  import           GHC.Generics                   (Generic) -#if MIN_VERSION_ghc(9,0,0)+#if MIN_VERSION_ghc(9,4,0) import           GHC.Types.Basic                (InlineSpec) import           GHC.Types.SrcLoc               (SrcSpan)+import           GHC.Data.Bool                  (OverridingBool(..))+#elif MIN_VERSION_ghc(9,0,0)+import           GHC.Types.Basic                (InlineSpec)+import           GHC.Types.SrcLoc               (SrcSpan) import           GHC.Utils.Misc                 (OverridingBool(..)) #else import           BasicTypes                     (InlineSpec)@@ -54,6 +59,7 @@ import           Clash.Annotations.BitRepresentation.Internal (CustomReprs) import           Clash.Signal.Internal +import           Clash.Backend.Verilog.Time     (Period(..), Unit(Fs)) import           Clash.Core.Term                (Term) import           Clash.Core.TyCon               (TyConMap, TyConName) import           Clash.Core.Var                 (Id)@@ -68,18 +74,17 @@   , envTupleTyCons :: IntMap TyConName   , envPrimitives  :: CompiledPrimMap   , envCustomReprs :: CustomReprs+  , envDomains     :: DomainMap   } deriving (Generic, NFData)  data ClashDesign = ClashDesign   { designEntities :: [TopEntityT]-  , designDomains  :: DomainMap   , designBindings :: BindingMap   }  instance NFData ClashDesign where   rnf design =     designEntities design `seq`-    designDomains design `deepseq`     designBindings design `deepseq`     () @@ -340,7 +345,7 @@   --   -- Command line flag: -fdiagnostics-color   , opt_intWidth :: Int-  -- ^ Set the bit width for the Int/Word/Integer types. The only allowed values+  -- ^ Set the bit width for the Int\/Word\/Integer types. The only allowed values   -- are 32 or 64.   , opt_hdlDir :: Maybe String   -- ^ Directory to save HDL files to@@ -358,8 +363,8 @@   , opt_escapedIds :: Bool   -- ^ Use escaped identifiers in HDL. See:   ---  --  * http://vhdl.renerta.com/mobile/source/vhd00037.htm-  --  * http://verilog.renerta.com/source/vrg00018.htm+  --  * https://peterfab.com/ref/vhdl/vhdl_renerta/source/vhd00037.htm+  --  * https://peterfab.com/ref/verilog/verilog_renerta/source/vrg00018.htm   , opt_lowerCaseBasicIds :: PreserveCase   -- ^ Force all generated basic identifiers to lowercase. Among others, this   -- affects module and file names.@@ -392,6 +397,9 @@   , opt_renderEnums :: Bool   -- ^ Render sum types with all zero-width fields as enums where supported, as   -- opposed to rendering them as bitvectors.+  , opt_timescalePrecision :: Period+  -- ^ Timescale precision set in Verilog files. E.g., setting this would sets+  -- the second part of @`timescale 100fs/100fs@.   }   deriving (Show) @@ -424,6 +432,7 @@     opt_inlineWFCacheLimit o `deepseq`     opt_edalize o `deepseq`     opt_renderEnums o `deepseq`+    opt_timescalePrecision o `deepseq`     ()  instance Eq ClashOpts where@@ -454,7 +463,8 @@     opt_aggressiveXOptBB s0 == opt_aggressiveXOptBB s1 &&     opt_inlineWFCacheLimit s0 == opt_inlineWFCacheLimit s1 &&     opt_edalize s0 == opt_edalize s1 &&-    opt_renderEnums s0 == opt_renderEnums s1+    opt_renderEnums s0 == opt_renderEnums s1 &&+    opt_timescalePrecision s0 == opt_timescalePrecision s1     where     eqOverridingBool :: OverridingBool -> OverridingBool -> Bool@@ -492,7 +502,8 @@     opt_aggressiveXOptBB `hashWithSalt`     opt_inlineWFCacheLimit `hashWithSalt`     opt_edalize `hashWithSalt`-    opt_renderEnums+    opt_renderEnums `hashWithSalt`+    opt_timescalePrecision    where     hashOverridingBool :: Int -> OverridingBool -> Int     hashOverridingBool s1 Auto = hashWithSalt s1 (0 :: Int)@@ -531,6 +542,7 @@   , opt_inlineWFCacheLimit  = 10 -- TODO: find "optimal" value   , opt_edalize             = False   , opt_renderEnums         = True+  , opt_timescalePrecision  = Period 100 Fs   }  -- | Synopsys Design Constraint (SDC) information for a component.
src/Clash/Netlist.hs view
@@ -3,6 +3,7 @@                      2016-2017, Myrtle Software Ltd,                      2017-2018, Google Inc.,                      2021-2022, QBayLogic B.V.+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -24,18 +25,20 @@ import           Control.Exception                (throw) import           Control.Lens                     ((.=), (<~)) import qualified Control.Lens                     as Lens-import           Control.Monad.Extra              (concatMapM)+import           Control.Monad                    (zipWithM)+import           Control.Monad.Extra              (concatMapM, mapMaybeM) import           Control.Monad.Reader             (runReaderT) import           Control.Monad.State.Strict       (State, runStateT, runState) import           Data.Bifunctor                   (first, second) import           Data.Char                        (ord) import           Data.Either                      (partitionEithers, rights) import           Data.Foldable                    (foldlM)-import qualified Data.HashMap.Lazy                as HashMap-import           Data.List                        (elemIndex, partition, sortOn)+import           Data.List                        (elemIndex, partition) import           Data.List.Extra                  (zipEqual)+import           Data.List.NonEmpty               (NonEmpty (..))+import qualified Data.List.NonEmpty.Extra         as NE import           Data.Maybe-  (listToMaybe, mapMaybe, fromMaybe)+  (listToMaybe, fromMaybe) import qualified Data.Map.Ordered                 as OMap import qualified Data.Set                         as Set import           Data.Primitive.ByteArray         (ByteArray (..))@@ -55,7 +58,7 @@ import           SrcLoc                           (isGoodSrcSpan) #endif -import           Clash.Annotations.Primitive      (extractPrim, HDL)+import           Clash.Annotations.Primitive      (HDL) import           Clash.Annotations.BitRepresentation.ClashLib   (coreToType') import           Clash.Annotations.BitRepresentation.Internal@@ -172,6 +175,7 @@         , _backEndITE=ite         , _backend=be         , _htyCache=mempty+        , _usages=mempty         }  -- | Generate names for all binders in "BindingMap", except for the ones already@@ -255,6 +259,7 @@   compName1 <- (`lookupVarEnv'` compName0) <$> Lens.use componentNames   sp <- (bindingLoc . (`lookupVarEnv'` compName0)) <$> Lens.use bindings   curCompNm .= (compName1, sp)+  usages .= mempty    topEntityTM <- lookupVarEnv compName0 <$> Lens.use topEntityAnns   let topAnnMM = topAnnotation <$> topEntityTM@@ -280,29 +285,33 @@    case resultM of     Just result -> do-      [NetDecl' _ rw _ _ rIM] <- case filter ((==result) . fst) binders of+      [NetDecl' _ _ _ rIM] <- case filter ((==result) . fst) binders of         b:_ -> mkNetDecl b         _ -> error "internal error: couldn't find result binder" +      u <- Lens.use usages+      let useOf i = fromMaybe Cont $ lookupUsage (fst i) u+       let (compOutps',resUnwrappers') = case compOutps of-            [oport] -> ([(rw,oport,rIM)],resUnwrappers)-            _       -> let NetDecl n res resTy = case resUnwrappers of-                             decl:_ -> decl-                             _ -> error "internal error: insufficient resUnwrappers"-                       in  (map (Wire,,Nothing) compOutps-                           ,NetDecl' n rw res (Right resTy) Nothing:tail resUnwrappers-                           )+            [oport] -> ([(useOf oport,oport,rIM)],resUnwrappers)+            _ -> case resUnwrappers of+              NetDecl n res resTy:_ ->+                (map (\op -> (useOf op,op,Nothing)) compOutps+                ,NetDecl' n res resTy Nothing:drop 1 resUnwrappers+                )+              _ -> error "internal error: insufficient resUnwrappers"           component      = Component compName1 compInps compOutps'                              (netDecls ++ argWrappers ++ decls ++ resUnwrappers')       ids <- Lens.use seenIds-      return (ComponentMeta wereVoids sp ids, component)+      return (ComponentMeta wereVoids sp ids u, component)     -- No result declaration means that the result is empty, this only happens     -- when the TopEntity has an empty result. We just create an empty component     -- in this case.     Nothing -> do       let component = Component compName1 compInps [] (netDecls ++ argWrappers ++ decls)       ids <- Lens.use seenIds-      return (ComponentMeta wereVoids sp ids, component)+      u <- Lens.use usages+      return (ComponentMeta wereVoids sp ids u, component)  mkNetDecl :: (Id, Term) -> NetlistMonad [Declaration] mkNetDecl (id_,tm) = preserveVarEnv $ do@@ -321,19 +330,16 @@         resInits1 = map Just resInits0 <> repeat Nothing         mpInfo = multiPrimInfo' tcm pInfo         (_, res) = splitMultiPrimArgs mpInfo args0+         netdecl i typ resInit =-          -- TODO: Dehardcode Wire. Would entail changing 'outputReg' to a-          -- list.-          NetDecl' srcNote Wire (id2identifier i) (Right typ) resInit+          NetDecl' srcNote (Id.unsafeFromCoreId i) typ resInit        hwTys <- mapM (unsafeCoreTypeToHWTypeM' $(curLoc)) (mpi_resultTypes mpInfo)       pure (zipWith3 netdecl res hwTys resInits1) -     singleDecl hwTy = do-      wr <- termToWireOrReg tm       rIM <- listToMaybe <$> getResInits (id_, tm)-      return (NetDecl' srcNote wr (id2identifier id_) (Right hwTy) rIM)+      return (NetDecl' srcNote (Id.unsafeFromCoreId id_) hwTy rIM)      addSrcNote loc       | isGoodSrcSpan loc = Just (StrictText.pack (showSDocUnsafe (ppr loc)))@@ -354,23 +360,6 @@       | isMultiPrimSelect t = False       | otherwise = True -    termToWireOrReg :: Term -> NetlistMonad WireOrReg-    termToWireOrReg (stripTicks -> Case scrut _ alts0@(_:_:_)) = do-      tcm <- Lens.view tcCache-      let scrutTy = inferCoreTypeOf tcm scrut-      scrutHTy <- unsafeCoreTypeToHWTypeM' $(curLoc) scrutTy-      ite <- Lens.use backEndITE-      case iteAlts scrutHTy alts0 of-        Just _ | ite -> return Wire-        _ -> return Reg-    termToWireOrReg (collectArgs -> (Prim p,_)) = do-      bbM <- HashMap.lookup (primName p) <$> Lens.view primitives-      case bbM of-        Just (extractPrim -> Just BlackBox {..}) | outputReg -> return Reg-        _ | primName p == "Clash.Explicit.SimIO.mealyIO" -> return Reg-        _ -> return Wire-    termToWireOrReg _ = return Wire-     -- 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@@ -431,8 +420,7 @@   -- ^ RHS of the let-binder   -> NetlistMonad [Declaration] mkDeclarations' _declType bndr (collectTicks -> (Var v,ticks)) =-  withTicks ticks $ \tickDecls -> do-  mkFunApp (id2identifier bndr) v [] tickDecls+  withTicks ticks (mkFunApp (Id.unsafeFromCoreId bndr) v [])  mkDeclarations' _declType _bndr e@(collectTicks -> (Case _ _ [],_)) = do   (_,sp) <- Lens.use curCompNm@@ -445,37 +433,42 @@                     ])           Nothing -mkDeclarations' declType bndr (collectTicks -> (Case scrut altTy alts@(_:_:_),ticks)) =-  withTicks ticks $ \tickDecls -> do-  mkSelection declType (CoreId bndr) scrut altTy alts tickDecls+mkDeclarations' declType bndr (collectTicks -> (Case scrut altTy (alt:alts@(_:_)),ticks)) =+  withTicks ticks (mkSelection declType (CoreId bndr) scrut altTy (alt :| alts))  mkDeclarations' declType bndr app = do   let (appF,args0,ticks) = collectArgsTicks app       (args,tyArgs) = partitionEithers args0   case appF of     Var f-      | null tyArgs -> withTicks ticks (mkFunApp (id2identifier bndr) f args)+      | null tyArgs ->+        withTicks ticks (mkFunApp (Id.unsafeFromCoreId bndr) f args)       | otherwise   -> do         (_,sp) <- Lens.use curCompNm         throw (ClashException sp ($(curLoc) ++ "Not in normal form: Var-application with Type arguments:\n\n" ++ showPpr app) Nothing)     _ -> do       (exprApp,declsApp0) <- mkExpr False declType (CoreId bndr) app-      let dstId = id2identifier bndr-          assn  =-            case exprApp of-              Identifier _ Nothing ->-                -- Supplied 'bndr' was used to assign a result to, so we-                -- don't have to manually turn it into a declaration-                []-              Noop ->-                -- Rendered expression rendered a "noop" - a list of-                -- declarations without a result. Used for things like-                -- mealy IO / inline assertions / multi result primitives.-                []-              _ ->-                -- Turn returned expression into declaration by assigning-                -- it to 'dstId'-                [Assignment dstId exprApp]+      let dstId = Id.unsafeFromCoreId bndr+      assn  <- case exprApp of+                 Identifier _ Nothing ->+                   -- Supplied 'bndr' was used to assign a result to, so we+                   -- don't have to manually turn it into a declaration+                   pure []++                 Noop ->+                   -- Rendered expression rendered a "noop" - a list of+                   -- declarations without a result. Used for things like+                   -- mealy IO / inline assertions / multi result primitives.+                   pure []++                 _ -> do+                   -- Turn returned expression into declaration by assigning+                   -- it to 'dstId'+                   assn <- case declType of+                     Concurrent -> contAssign dstId exprApp+                     Sequential -> procAssign Blocking dstId exprApp+                   pure [assn]+       declsApp1 <- if null declsApp0                    then withTicks ticks return                    else pure declsApp0@@ -488,11 +481,11 @@   -> NetlistId   -> Term   -> Type-  -> [Alt]+  -> NonEmpty Alt   -> [Declaration]   -> NetlistMonad [Declaration] mkSelection declType bndr scrut altTy alts0 tickDecls = do-  let dstId = netlistId1 id id2identifier bndr+  let dstId = netlistId1 id Id.unsafeFromCoreId bndr   tcm <- Lens.view tcCache   let scrutTy = inferCoreTypeOf tcm scrut   scrutHTy <- unsafeCoreTypeToHWTypeM' $(curLoc) scrutTy@@ -500,13 +493,13 @@   (_,sp) <- Lens.use curCompNm   ite <- Lens.use backEndITE   altHTy <- unsafeCoreTypeToHWTypeM' $(curLoc) altTy-  case iteAlts scrutHTy alts0 of+  case iteAlts scrutHTy (NE.toList alts0) of     Just (altT,altF)       | ite       , Concurrent <- declType       -> do       (scrutExpr,scrutDecls) <- case scrutHTy of-        SP {} -> first (mkScrutExpr sp scrutHTy (fst (last alts0))) <$>+        SP {} -> first (mkScrutExpr sp scrutHTy (fst (NE.last alts0))) <$>                    mkExpr True declType (NetlistId scrutId scrutTy) scrut         _ -> mkExpr False declType (NetlistId scrutId scrutTy) scrut       altTId <- Id.suffix dstId "sel_alt_t"@@ -525,19 +518,18 @@          | isVoid altHTy           -> return $! altTDecls ++ altFDecls          | otherwise-          -> return $! scrutDecls ++ altTDecls ++ altFDecls ++ tickDecls ++-                [Assignment dstId (IfThenElse scrutExpr altTExpr altFExpr)]+          -> do dstAssign <- contAssign dstId (IfThenElse scrutExpr altTExpr altFExpr)+                return $! scrutDecls ++ altTDecls ++ altFDecls ++ tickDecls ++ [dstAssign]     _ -> do       reprs <- Lens.view customReprs       let alts1 = (reorderDefault . reorderCustom tcm reprs scrutTy) alts0-      (scrutExpr,scrutDecls) <- first (mkScrutExpr sp scrutHTy (fst (head alts1))) <$>+      (scrutExpr,scrutDecls) <- first (mkScrutExpr sp scrutHTy (fst (NE.head alts1))) <$>                                   mkExpr True declType (NetlistId scrutId scrutTy) scrut-      (exprs,altsDecls)      <- unzip <$> mapM (mkCondExpr scrutHTy) alts1+      (exprs,altsDecls)      <- unzip <$> mapM (mkCondExpr scrutHTy) (NE.toList alts1)       case declType of         Sequential -> do           -- Assign to the result in every branch-          let (altNets,exprAlts) = unzip (zipWith (altAssign dstId)-                                                  exprs altsDecls)+          (altNets,exprAlts) <- fmap unzip (zipWithM (altAssign dstId) exprs altsDecls)           return $! scrutDecls ++ tickDecls ++ concat altNets ++                     [Seq [Branch scrutExpr scrutHTy exprAlts]]         Concurrent ->@@ -546,12 +538,12 @@              | isVoid altHTy               -> return $! concat altsDecls              | otherwise-              -> return $! scrutDecls ++ concat altsDecls ++ tickDecls-                    ++ [CondAssignment dstId altHTy scrutExpr scrutHTy exprs]+              -> do assign <- condAssign dstId altHTy scrutExpr scrutHTy exprs+                    return $! scrutDecls ++ concat altsDecls ++ tickDecls ++ [assign]  where   mkCondExpr :: HWType -> (Pat,Term) -> NetlistMonad ((Maybe HW.Literal,Expr),[Declaration])   mkCondExpr scrutHTy (pat,alt) = do-    altId <- Id.suffix (netlistId1 id id2identifier bndr) "sel_alt"+    altId <- Id.suffix (netlistId1 id Id.unsafeFromCoreId bndr) "sel_alt"     (altExpr,altDecls) <- mkExpr False declType (NetlistId altId altTy) alt     (,altDecls) <$> case pat of       DefaultPat           -> return (Nothing,altExpr)@@ -562,6 +554,14 @@       LitPat  (CharLiteral c) -> return (Just (NumLit . toInteger $ ord c), altExpr)       LitPat  (Int64Literal i) -> return (Just (NumLit i), altExpr)       LitPat  (Word64Literal w) -> return (Just (NumLit w), altExpr)+#if MIN_VERSION_base(4,16,0)+      LitPat  (Int8Literal i) -> return (Just (NumLit i), altExpr)+      LitPat  (Int16Literal i) -> return (Just (NumLit i), altExpr)+      LitPat  (Int32Literal i) -> return (Just (NumLit i), altExpr)+      LitPat  (Word8Literal w) -> return (Just (NumLit w), altExpr)+      LitPat  (Word16Literal w) -> return (Just (NumLit w), altExpr)+      LitPat  (Word32Literal w) -> return (Just (NumLit w), altExpr)+#endif       LitPat  (NaturalLiteral n) -> return (Just (NumLit n), altExpr)       _  -> do         (_,sp) <- Lens.use curCompNm@@ -575,12 +575,18 @@                           _ -> throw (ClashException sp ($(curLoc) ++ "Not in normal form: Not a variable reference or primitive as subject of a case-statement:\n\n" ++ show scrutE) Nothing)     _ -> scrutE -  altAssign :: Identifier -> (Maybe HW.Literal,Expr) -> [Declaration]-            -> ([Declaration],(Maybe HW.Literal,[Seq]))-  altAssign i (m,expr) ds =+  altAssign+    :: Identifier+    -> (Maybe HW.Literal,Expr)+    -> [Declaration]+    -> NetlistMonad ([Declaration],(Maybe HW.Literal,[Seq]))+  altAssign i (m,expr) ds = do     let (nets,rest) = partition isNet ds-        assn = case expr of { Noop -> []; _ -> [SeqDecl (Assignment i expr)] }-    in  (nets,(m,map SeqDecl rest ++ assn))+    assn <- case expr of+              Noop -> pure []+              _ -> do assn <- procAssign Blocking i expr+                      pure [assn]+    pure (nets,(m,map SeqDecl (rest ++ assn)))    where     isNet NetDecl' {} = True     isNet _ = False@@ -588,23 +594,26 @@ -- GHC puts default patterns in the first position, we want them in the -- last position. reorderDefault-  :: [(Pat, Term)]-  -> [(Pat, Term)]-reorderDefault ((DefaultPat,e):alts') = alts' ++ [(DefaultPat,e)]-reorderDefault alts'                  = alts'+  :: NonEmpty (Pat, Term)+  -> NonEmpty (Pat, Term)+reorderDefault ((DefaultPat,e) :| alts') =+  case alts' of+    [] -> (DefaultPat,e) :| []+    x:xs -> x :| (xs <> [(DefaultPat,e)])+reorderDefault alts' = alts'  reorderCustom   :: TyConMap   -> CustomReprs   -> Type-  -> [(Pat, Term)]-  -> [(Pat, Term)]+  -> NonEmpty (Pat, Term)+  -> NonEmpty (Pat, Term) reorderCustom tcm reprs (coreView1 tcm -> Just ty) alts =   reorderCustom tcm reprs ty alts reorderCustom _tcm reprs (coreToType' -> Right typeName) alts =   case getDataRepr typeName reprs of     Just (DataRepr' _name _size _constrReprs) ->-      sortOn (patPos reprs . fst) alts+      NE.sortOn (patPos reprs . fst) alts     Nothing ->       alts reorderCustom _tcm _reprs _type alts =@@ -691,14 +700,13 @@         --       pure (expandTopEntityOrErr is (zip argIds argTys) (resId, resTy) topAnnM)          -- Generate ExpandedTopEntity, see TODO^-        is <- Lens.use seenIds         argTys <- mapM (unsafeCoreTypeToHWTypeM $(curLoc) . inferCoreTypeOf tcm) args         resTy <- unsafeCoreTypeToHWTypeM $(curLoc) fResTy         let           ettArgs = (Nothing,) <$> argTys           ettRes = (Nothing, resTy)-          expandedTopEntity =-            expandTopEntityOrErr is ettArgs ettRes (topAnnotation topEntity)+        expandedTopEntity <-+            expandTopEntityOrErrM ettArgs ettRes (topAnnotation topEntity)          instDecls <-           mkTopUnWrapper@@ -744,6 +752,7 @@               instLabel3 <- Id.makeBasic instLabel2               let portMap = NamedPortMap (outpAssign ++ inpAssigns)                   instDecl = InstDecl Entity Nothing [] compName instLabel3 [] portMap+              declareInstUses outpAssign               return (argDecls ++ argDecls' ++ tickDecls ++ [instDecl])             else               let@@ -769,9 +778,10 @@             |]     _ ->       case args of-        [] ->+        [] -> do           -- TODO: Figure out what to do with zero-width constructs-          return [Assignment dstId (Identifier (id2identifier fun) Nothing)]+          assn <- contAssign dstId (Identifier (Id.unsafeFromCoreId fun) Nothing)+          pure [assn]         _ -> error [I.i|           Netlist generation encountered a local function. This should not           happen. Function:@@ -802,9 +812,8 @@ toSimpleVar dstId (e,ty) = do   argNm <- Id.suffix dstId "fun_arg"   hTy <- unsafeCoreTypeToHWTypeM' $(curLoc) ty-  let argDecl         = NetDecl Nothing argNm hTy-      argAssn         = Assignment argNm e-  return (Identifier argNm Nothing,[argDecl,argAssn])+  argDecl <- mkInit Concurrent Cont argNm hTy e+  return (Identifier argNm Nothing, argDecl)  -- | Generate an expression for a term occurring on the RHS of a let-binder mkExpr :: HasCallStack@@ -822,6 +831,14 @@     WordLiteral w    -> return (HW.Literal (Just (Unsigned iw,iw)) $ NumLit w, [])     Int64Literal i   -> return (HW.Literal (Just (Signed 64,64)) $ NumLit i, [])     Word64Literal w  -> return (HW.Literal (Just (Unsigned 64,64)) $ NumLit w, [])+#if MIN_VERSION_ghc(8,8,0)+    Int8Literal i    -> return (HW.Literal (Just (Signed 8,8)) $ NumLit i, [])+    Int16Literal i   -> return (HW.Literal (Just (Signed 16,16)) $ NumLit i, [])+    Int32Literal i   -> return (HW.Literal (Just (Signed 32,32)) $ NumLit i, [])+    Word8Literal w   -> return (HW.Literal (Just (Unsigned 8,8)) $ NumLit w, [])+    Word16Literal w  -> return (HW.Literal (Just (Unsigned 16,16)) $ NumLit w, [])+    Word32Literal w  -> return (HW.Literal (Just (Unsigned 32,32)) $ NumLit w, [])+#endif     CharLiteral c    -> return (HW.Literal (Just (Unsigned 21,21)) . NumLit . toInteger $ ord c, [])     FloatLiteral w   -> return (HW.Literal (Just (BitVector 32,32)) (NumLit $ toInteger w), [])     DoubleLiteral w  -> return (HW.Literal (Just (BitVector 64,64)) (NumLit $ toInteger w), [])@@ -843,45 +860,40 @@         hwTy:_ -> hwTy         _ -> error ("internal error: unable to extract sufficient hwTys from: " <> show bndr)   case appF of-    Data dc -> mkDcApplication hwTys bndr dc tmArgs-    Prim pInfo -> mkPrimitive False bbEasD bndr pInfo args tickDecls+    Data dc -> mkDcApplication declType hwTys bndr dc tmArgs+    Prim pInfo -> mkPrimitive False bbEasD declType bndr pInfo args tickDecls     Var f       | null tmArgs ->           if isVoid hwTyA then             return (Noop, [])-          else-            return (Identifier (id2identifier f) Nothing, [])+          else do+            return (Identifier (Id.unsafeFromCoreId f) Nothing, [])       | not (null tyArgs) ->           throw (ClashException sp ($(curLoc) ++ "Not in normal form: "             ++ "Var-application with Type arguments:\n\n" ++ showPpr app) Nothing)       | otherwise -> do-          argNm <- Id.suffix (netlistId1 id id2identifier bndr) "fun_arg"+          argNm <- Id.suffix (netlistId1 id Id.unsafeFromCoreId bndr) "fun_arg"           decls  <- mkFunApp argNm f tmArgs tickDecls           if isVoid hwTyA then             return (Noop, decls)           else+            -- This net was already declared in the call to mkSelection.             return ( Identifier argNm Nothing-                   , NetDecl' Nothing Wire argNm (Right hwTyA) Nothing:decls)+                   , NetDecl Nothing argNm hwTyA : decls)     Case scrut ty' [alt] -> mkProjection bbEasD bndr scrut ty' alt-    Case scrut tyA alts -> do-      tcm <- Lens.view tcCache-      let scrutTy = inferCoreTypeOf tcm scrut-      scrutHTy <- unsafeCoreTypeToHWTypeM' $(curLoc) scrutTy-      ite <- Lens.use backEndITE-      let wr = case iteAlts scrutHTy alts of-                 Just _ | ite -> Wire-                 _ -> Reg-      argNm <- Id.suffix (netlistId1 id id2identifier bndr) "sel_arg"+    Case scrut tyA (alt:alts) -> do+      argNm <- Id.suffix (netlistId1 id Id.unsafeFromCoreId bndr) "sel_arg"       decls  <- mkSelection declType (NetlistId argNm (netlistTypes1 bndr))-                            scrut tyA alts tickDecls+                            scrut tyA (alt :| alts) tickDecls       if isVoid hwTyA then         return (Noop, decls)       else+        -- This net was already declared in the call to mkSelection         return ( Identifier argNm Nothing-               , NetDecl' Nothing wr argNm (Right hwTyA) Nothing:decls)+               , NetDecl' Nothing argNm hwTyA Nothing:decls)     Letrec binders body -> do       netDecls <- concatMapM mkNetDecl binders-      decls    <- concatMapM (uncurry mkDeclarations) binders+      decls    <- concatMapM (uncurry (mkDeclarations' declType)) binders       (bodyE,bodyDecls) <- mkExpr bbEasD declType bndr (mkApps (mkTicks body ticks) args)       return (bodyE,netDecls ++ decls ++ bodyDecls)     _ -> throw (ClashException sp ($(curLoc) ++ "Not in normal form: application of a Lambda-expression\n\n" ++ showPpr app) Nothing)@@ -917,7 +929,7 @@     scrutNm <-       netlistId1         Id.next-        (\b -> Id.suffix (id2identifier b) "projection")+        (\b -> Id.suffix (Id.unsafeFromCoreId b) "projection")         bndr     (scrutExpr,newDecls) <- mkExpr False Concurrent (NetlistId scrutNm scrutTy) scrut     case scrutExpr of@@ -930,14 +942,13 @@         -- TODO: seems useless?         pure (Left newDecls)       _ -> do-        let scrutDecl = NetDecl Nothing scrutNm sHwTy-            scrutAssn = Assignment scrutNm scrutExpr-        pure (Right (scrutNm, Nothing, newDecls ++ [scrutDecl, scrutAssn]))+        scrutDecl <- mkInit Concurrent Cont scrutNm sHwTy scrutExpr+        pure (Right (scrutNm, Nothing, newDecls ++ scrutDecl))    case scrutRendered of     Left newDecls -> pure (Noop, newDecls)     Right (selId, modM, decls) -> do-      let altVarId = id2identifier varTm+      let altVarId = Id.unsafeFromCoreId varTm       modifier <- case pat of         DataPat dc exts tms -> do           let@@ -968,9 +979,8 @@       case bndr of         NetlistId scrutNm _ | mkDec -> do           scrutNm' <- Id.next scrutNm-          let scrutDecl = NetDecl Nothing scrutNm' vHwTy-              scrutAssn = Assignment scrutNm' extractExpr-          return (Identifier scrutNm' Nothing,scrutDecl:scrutAssn:decls)+          scrutDecl <- mkInit Concurrent Cont scrutNm' vHwTy extractExpr+          return (Identifier scrutNm' Nothing, scrutDecl ++ decls)         MultiId {} -> error "mkProjection: MultiId"         _ -> return (extractExpr,decls)   where@@ -981,7 +991,8 @@ -- | Generate an expression for a DataCon application occurring on the RHS of a let-binder mkDcApplication     :: HasCallStack-    => [HWType]+    => DeclarationType+    -> [HWType]     -- ^ HWType of the LHS of the let-binder, can multiple types when we're     -- creating a "split" product type (e.g. a tuple of a Clock and Reset)     -> NetlistId@@ -992,15 +1003,15 @@     -- ^ DataCon Arguments     -> NetlistMonad (Expr,[Declaration])     -- ^ Returned expression and a list of generate BlackBox declarations-mkDcApplication [dstHType] bndr dc args = do+mkDcApplication declType [dstHType] bndr dc args = do   let dcNm = nameOcc (dcName dc)   tcm <- Lens.view tcCache   let argTys = map (inferCoreTypeOf tcm) args-  argNm <- netlistId1 return (\b -> Id.suffix (id2identifier b) "_dc_arg") bndr+  argNm <- netlistId1 return (\b -> Id.suffix (Id.unsafeFromCoreId b) "_dc_arg") bndr   argHWTys <- mapM coreTypeToHWTypeM' argTys    (argExprs, concat -> argDecls) <- unzip <$>-    mapM (\(e,t) -> mkExpr False Concurrent (NetlistId argNm t) e) (zip args argTys)+    mapM (\(e,t) -> mkExpr False declType (NetlistId argNm t) e) (zip args argTys)    -- Filter void arguments, but make sure to render their declarations:   let@@ -1127,7 +1138,7 @@         error $ $(curLoc) ++ "mkDcApplication undefined for: " ++ show (dstHType,dc,args,argHWTys)  -- Handle MultiId assignment-mkDcApplication dstHTypes (MultiId argNms) _ args = do+mkDcApplication declType dstHTypes (MultiId argNms) _ args = do   tcm                 <- Lens.view tcCache   let argTys          = map (inferCoreTypeOf tcm) args   argHWTys            <- mapM coreTypeToHWTypeM' argTys@@ -1137,18 +1148,20 @@       (_hWTysFiltered,argsFiltered) = unzip         (filter (maybe True (not . isVoid) . fst) argsBundled)   (argExprs,argDecls) <- fmap (second concat . unzip) $!-                         mapM (uncurry (mkExpr False Concurrent)) argsFiltered+                         mapM (uncurry (mkExpr False declType)) argsFiltered   if length dstHTypes == length argExprs then do-    let assns = mapMaybe-                  (\case (_,Noop) -> Nothing-                         (dstId,e) -> let nm = netlistId1 id id2identifier dstId-                                      in  case e of+    assns <- mapMaybeM+                  (\case (_,Noop) -> pure Nothing+                         (dstId,e) -> let nm = netlistId1 id Id.unsafeFromCoreId dstId+                                       in case e of                                             Identifier nm0 Nothing-                                              | nm == nm0 -> Nothing-                                            _ -> Just (Assignment nm e))+                                              | nm == nm0 -> pure Nothing+                                            _ -> Just <$> case declType of+                                                            Concurrent -> contAssign nm e+                                                            Sequential -> procAssign Blocking nm e)                   (zipEqual (map CoreId argNms) argExprs)     return (Noop,argDecls ++ assns)   else     error "internal error" -mkDcApplication _ _ _ _ = error "internal error"+mkDcApplication _ _ _ _ _ = error "internal error"
src/Clash/Netlist.hs-boot view
@@ -1,7 +1,8 @@ {-|   Copyright   :  (C) 2015-2016, University of Twente+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)-  Maintainer  :  Christiaan Baaij <christiaan.baaij@gmail.com>+  Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> -} {-# LANGUAGE CPP #-} @@ -17,6 +18,8 @@   ,mkFunApp   ) where +import Data.List.NonEmpty (NonEmpty)+ import Clash.Core.DataCon   (DataCon) import Clash.Core.Term      (Alt,LetBinding,Term) import Clash.Core.Type      (Type)@@ -39,7 +42,8 @@        -> NetlistMonad (Expr,[Declaration])  mkDcApplication :: HasCallStack-                => [HWType]+                => DeclarationType+                -> [HWType]                 -> NetlistId                 -> DataCon                 -> [Term]@@ -58,7 +62,7 @@   -> NetlistId   -> Term   -> Type-  -> [Alt]+  -> NonEmpty Alt   -> [Declaration]   -> NetlistMonad [Declaration] 
src/Clash/Netlist/BlackBox.hs view
@@ -3,7 +3,8 @@   Copyright  :  (C) 2012-2016, University of Twente,                     2016-2017, Myrtle Software Ltd,                     2017     , Google Inc.,-                    2021-2022, QBayLogic B.V.+                    2021-2023, QBayLogic B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -30,8 +31,10 @@ import           Data.Bifunctor                (first, second) import           Data.Char                     (ord) import           Data.Either                   (lefts, partitionEithers)+import           Data.Foldable                 (for_) import qualified Data.HashMap.Lazy             as HashMap import qualified Data.IntMap                   as IntMap+import           Data.List.NonEmpty            (NonEmpty (..)) import           Data.List                     (elemIndex, partition) import           Data.List.Extra               (countEq, mapAccumLM) import           Data.Maybe                    (listToMaybe, fromJust, fromMaybe)@@ -50,7 +53,9 @@   , ConsoleIntensity(BoldIntensity), ConsoleLayer(Foreground), ColorIntensity(Vivid)) import           System.IO   (hPutStrLn, stderr, hFlush, hIsTerminalDevice)-#if MIN_VERSION_ghc(9,0,0)+#if MIN_VERSION_ghc(9,4,0)+import           GHC.Data.Bool                 (OverridingBool(..))+#elif MIN_VERSION_ghc(9,0,0) import           GHC.Utils.Misc                (OverridingBool(..)) #else import           Util                          (OverridingBool(..))@@ -59,7 +64,7 @@ import           Clash.Annotations.Primitive   ( PrimitiveGuard(HasBlackBox, DontTranslate)   , PrimitiveWarning(WarnNonSynthesizable, WarnAlways)-  , extractPrim)+  , extractPrim, HDL(VHDL)) import           Clash.Core.DataCon            as D (dcTag) import           Clash.Core.FreeVars           (freeIds) import           Clash.Core.HasType@@ -79,13 +84,14 @@ import           Clash.Core.Util   (inverseTopSortLetBindings, splitShouldSplit) import           Clash.Core.Var                as V-  (Id, Var (..), mkLocalId, modifyVarName)+  (Id, mkLocalId, modifyVarName, varType) import           Clash.Core.VarEnv   (extendInScopeSet, mkInScopeSet, lookupVarEnv, uniqAway, unitVarSet) import {-# SOURCE #-} Clash.Netlist   (genComponent, mkDcApplication, mkDeclarations, mkExpr, mkNetDecl,    mkProjection, mkSelection, mkFunApp, mkDeclarations') import qualified Clash.Backend                 as Backend+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Debug                   (debugIsOn) import           Clash.Driver.Types   (ClashOpts(opt_primWarn, opt_color, opt_werror))@@ -97,7 +103,6 @@ import           Clash.Primitives.Types        as P import qualified Clash.Primitives.Util         as P import           Clash.Signal.Internal         (ActiveEdge (..))-import           Clash.Unique                  (lookupUniqMap') import           Clash.Util import qualified Clash.Util.Interpolate        as I @@ -140,7 +145,7 @@ mkBlackBoxContext bbName resIds args@(lefts -> termArgs) = do     -- Make context inputs     let-      resNms = map id2identifier resIds+      resNms = fmap Id.unsafeFromCoreId resIds       resNm = fromMaybe (error "mkBlackBoxContext: head") (listToMaybe resNms)     resTys <- mapM (unsafeCoreTypeToHWTypeM' $(curLoc) . coreTypeOf) resIds     (imps,impDecls) <- unzip <$> zipWithM (mkArgument bbName resNm) [0..] termArgs@@ -182,7 +187,7 @@          curBBlvl Lens.+= 1         (fs,ds) <- case resIds of-          (resId:_) -> unzip <$> replicateM funcPlurality (mkFunInput resId arg)+          (resId:_) -> unzip <$> replicateM funcPlurality (mkFunInput bbName resId arg)           _ -> error "internal error: insufficient resIds"         curBBlvl Lens.-= 1 @@ -204,6 +209,7 @@           (fmap (first BBTemplate) . setSym bbCtx)           (\bbName bbHash bbFunc -> pure (BBFunction bbName bbHash bbFunc, []))           templ+      for_ decls goDecl       return (t2,decls)     Just err0 -> do       (_,sp) <- Lens.use curCompNm@@ -211,7 +217,44 @@                         , Data.Text.unpack (bbName bbCtx), ". Verification "                         , "procedure reported:\n\n" ++ err0 ]       throw (ClashException sp ($(curLoc) ++ err1) Nothing)+ where+  -- Right now we assume that (1) a blackbox doesn't assign to a signal+  -- declared outside the black box template and (2) all uses of a signal+  -- within a blackbox are correct for the targeted HDL (i.e. we don't try+  -- to generate new signals when a signal is used incorrectly).+  goDecl = \case+    Assignment i u _ ->+      declareUse u i +    CondAssignment i _ _ _ _ -> do+      -- Currently, all CondAssignment get rendered as `always @*` blocks in+      -- (System)Verilog. This means when we target these HDL, this is _really_+      -- a blocking procedural assignment.+      SomeBackend b <- Lens.use backend+      let use = case Backend.hdlKind b of { VHDL -> Cont ; _ -> Proc Blocking }+      declareUse use i++    Seq seqs -> for_ seqs goSeq++    _ -> pure ()++  goSeq = \case+    AlwaysClocked _ _ seqs ->+      for_ seqs goSeq++    Initial seqs ->+      for_ seqs goSeq++    AlwaysComb seqs ->+      for_ seqs goSeq++    SeqDecl conc ->+      goDecl conc++    Branch _ _ alts ->+      let seqs = concatMap snd alts+       in for_ seqs goSeq+ -- | Determine if a term represents a literal isLiteral :: Term -> Bool isLiteral e = case collectArgs e of@@ -246,8 +289,8 @@         | otherwise         -> return ((error ($(curLoc) ++ "Forced to evaluate untranslatable type: " ++ eTyMsg), Void Nothing, False), [])       Just hwTy -> case collectArgsTicks e of-        (C.Var v,[],_) ->-          return ((Identifier (id2identifier v) Nothing,hwTy,False),[])+        (C.Var v,[],_) -> do+          return ((Identifier (Id.unsafeFromCoreId v) Nothing,hwTy,False),[])         (C.Literal (IntegerLiteral i),[],_) ->           return ((N.Literal (Just (Signed iw,iw)) (N.NumLit i),hwTy,True),[])         (C.Literal (IntLiteral i), [],_) ->@@ -262,15 +305,29 @@           return ((N.Literal (Just (Signed 64,64)) (N.NumLit i),hwTy,True),[])         (C.Literal (Word64Literal i), [],_) ->           return ((N.Literal (Just (Unsigned 64,64)) (N.NumLit i),hwTy,True),[])+#if MIN_VERSION_base(4,16,0)+        (C.Literal (Int8Literal i), [],_) ->+          return ((N.Literal (Just (Signed 8,8)) (N.NumLit i),hwTy,True),[])+        (C.Literal (Int16Literal i), [],_) ->+          return ((N.Literal (Just (Signed 16,16)) (N.NumLit i),hwTy,True),[])+        (C.Literal (Int32Literal i), [],_) ->+          return ((N.Literal (Just (Signed 16,16)) (N.NumLit i),hwTy,True),[])+        (C.Literal (Word8Literal i), [],_) ->+          return ((N.Literal (Just (Unsigned 8,8)) (N.NumLit i),hwTy,True),[])+        (C.Literal (Word16Literal i), [],_) ->+          return ((N.Literal (Just (Unsigned 16,16)) (N.NumLit i),hwTy,True),[])+        (C.Literal (Word32Literal i), [],_) ->+          return ((N.Literal (Just (Unsigned 32,32)) (N.NumLit i),hwTy,True),[])+#endif         (C.Literal (NaturalLiteral n), [],_) ->           return ((N.Literal (Just (Unsigned iw,iw)) (N.NumLit n),hwTy,True),[])         (Prim pinfo,args,ticks) -> withTicks ticks $ \tickDecls -> do-          (e',d) <- mkPrimitive True False (NetlistId bndr ty) pinfo args tickDecls+          (e',d) <- mkPrimitive True False Concurrent (NetlistId bndr ty) pinfo args tickDecls           case e' of             (Identifier _ _) -> return ((e',hwTy,False), d)             _                -> return ((e',hwTy,isLiteral e), d)         (Data dc, args,_) -> do-          (exprN,dcDecls) <- mkDcApplication [hwTy] (NetlistId bndr ty) dc (lefts args)+          (exprN,dcDecls) <- mkDcApplication Concurrent [hwTy] (NetlistId bndr ty) dc (lefts args)           return ((exprN,hwTy,isLiteral e),dcDecls)         (Case scrut ty' [alt],[],_) -> do           (projection,decls) <- mkProjection False (NetlistId bndr ty) scrut ty' alt@@ -356,6 +413,8 @@   -- ^ Put BlackBox expression in parenthesis   -> Bool   -- ^ Treat BlackBox expression as declaration+  -> DeclarationType+  -- ^ Are we concurrent or sequential?   -> NetlistId   -- ^ Id to assign the result to   -> PrimInfo@@ -365,7 +424,7 @@   -> [Declaration]   -- ^ Tick declarations   -> NetlistMonad (Expr,[Declaration])-mkPrimitive bbEParen bbEasD dst pInfo args tickDecls =+mkPrimitive bbEParen bbEasD declType dst pInfo args tickDecls =   go =<< extractPrimWarnOrFail (primName pInfo)   where     tys = netlistTypes dst@@ -391,7 +450,7 @@               -- Blackbox template generation successful. Rerun 'go', but this time               -- around with a 'normal' @BlackBox@               go (P.BlackBox-                    bbName wf bbRenderVoid multiResult bbKind () bbOutputReg+                    bbName wf bbRenderVoid multiResult bbKind () bbOutputUsage                     bbLibrary bbImports bbFunctionPlurality bbIncludes                     bbResultNames bbResultInits bbTemplate)         -- See 'setupMultiResultPrim' in "Clash.Normalize.Transformations":@@ -407,7 +466,7 @@           (templ, templDecl) <- prepareBlackBox name template bbCtx           let bbDecl = N.BlackBoxD name (libraries p) (imports p) (includes p) templ bbCtx           return (Noop, ctxDcls ++ templDecl ++ tickDecls ++ [bbDecl])-        p@P.BlackBox {template, name=pNm, kind} ->+        p@(P.BlackBox {template, name=pNm, kind,outputUsage}) ->           case kind of             TDecl -> do               resM <- resBndr1 True dst@@ -417,6 +476,7 @@                   (templ,templDecl) <- prepareBlackBox pNm template bbCtx                   let bbDecl = N.BlackBoxD pNm (libraries p) (imports p)                                            (includes p) templ bbCtx+                  declareUse outputUsage dstNm                   return (Identifier dstNm Nothing,dstDecl ++ ctxDcls ++ templDecl ++ tickDecls ++ [bbDecl])                  -- Render declarations as a Noop when requested@@ -437,12 +497,12 @@                   resM <- resBndr1 True dst                   case resM of                     Just (dst',dstNm,dstDecl) -> do-                      (bbCtx,ctxDcls)     <- mkBlackBoxContext (primName pInfo) [dst'] args+                      (bbCtx,ctxDcls) <- mkBlackBoxContext (primName pInfo) [dst'] args                       (bbTempl,templDecl) <- prepareBlackBox pNm template bbCtx-                      let tmpAssgn = Assignment dstNm-                                        (BlackBoxE pNm (libraries p) (imports p)-                                                   (includes p) bbTempl bbCtx-                                                   bbEParen)+                      let bbE =  BlackBoxE pNm (libraries p) (imports p) (includes p) bbTempl bbCtx bbEParen+                      tmpAssgn <- case declType of+                        Concurrent -> contAssign dstNm bbE+                        Sequential -> procAssign Blocking dstNm bbE                       return (Identifier dstNm Nothing, dstDecl ++ ctxDcls ++ templDecl ++ [tmpAssgn])                      -- Render expression as a Noop when requested@@ -494,9 +554,9 @@               case args of                 [Right (ConstTy (TyCon tcN)), Left (C.Literal (IntLiteral i))] -> do                   tcm <- Lens.view tcCache-                  let dcs = tyConDataCons (tcm `lookupUniqMap'` tcN)+                  let dcs = tyConDataCons (UniqMap.find tcN tcm)                       dc  = dcs !! fromInteger i-                  (exprN,dcDecls) <- mkDcApplication [hwTy] dst dc []+                  (exprN,dcDecls) <- mkDcApplication declType [hwTy] dst dc []                   return (exprN,dcDecls)                 [Right _, Left scrut] -> do                   tcm     <- Lens.view tcCache@@ -508,9 +568,9 @@                     _ -> do                       scrutHTy <- unsafeCoreTypeToHWTypeM' $(curLoc) scrutTy                       tmpRhs <- Id.make "c$tte_rhs"-                      let netDeclRhs   = NetDecl Nothing tmpRhs scrutHTy-                          netAssignRhs = Assignment tmpRhs scrutExpr-                      return (DataTag hwTy (Left tmpRhs),[netDeclRhs,netAssignRhs] ++ scrutDecls)+                      let assignTy = case declType of { Concurrent -> Cont ; Sequential -> Proc Blocking }+                      netDecl <- N.mkInit declType assignTy tmpRhs scrutHTy scrutExpr+                      return (DataTag hwTy (Left tmpRhs), netDecl ++ scrutDecls)                 _ -> error $ $(curLoc) ++ "tagToEnum: " ++ show (map (either showPpr showPpr) args)           | pNm == "GHC.Prim.dataToTag#" -> case args of               [Right _,Left (Data dc)] -> do@@ -526,9 +586,9 @@                   Identifier id_ Nothing -> return (DataTag scrutHTy (Right id_),scrutDecls)                   _ -> do                     tmpRhs <- Id.make "c$dtt_rhs"-                    let netDeclRhs   = NetDecl Nothing tmpRhs scrutHTy-                        netAssignRhs = Assignment tmpRhs scrutExpr-                    return (DataTag scrutHTy (Right tmpRhs),[netDeclRhs,netAssignRhs] ++ scrutDecls)+                    let assignTy = case declType of { Concurrent -> Cont ; Sequential -> Proc Blocking }+                    netDecl <- N.mkInit declType assignTy tmpRhs scrutHTy scrutExpr+                    return (DataTag scrutHTy (Right tmpRhs),netDecl ++ scrutDecls)               _ -> error $ $(curLoc) ++ "dataToTag: " ++ show (map (either showPpr showPpr) args)            | pNm == "Clash.Explicit.SimIO.mealyIO" -> do@@ -548,9 +608,10 @@                   Noop ->                     return (Noop,decls)                   _ -> case dstNms of-                    [dstNm] ->+                    [dstNm] -> do+                      declareUse (Proc Blocking) dstNm                       return ( Identifier dstNm Nothing-                             , dstDecl ++ decls ++ [Assignment dstNm expr])+                             , dstDecl ++ decls ++ [Assignment dstNm (Proc Blocking) expr])                     _ -> error $ $(curLoc) ++ "bindSimIO: " ++ show resM                 _ ->                   return (Noop,decls)@@ -561,26 +622,32 @@           | pNm == "Clash.Explicit.SimIO.fmapSimIO#" -> do               resM <- resBndr1 True dst               case resM of-                Just (_,dstNm,dstDecl) -> do-                  tcm <- Lens.view tcCache-                  let (fun0:arg0:_) = lefts args-                      arg1 = unSimIO tcm arg0-                      fun1 = case fun0 of-                        Lam b bE ->-                          let is0 = mkInScopeSet (Lens.foldMapOf freeIds unitVarSet fun0)-                              subst = extendIdSubst (mkSubst is0) b arg1-                          in  substTm "mkPrimitive.fmapSimIO" subst bE-                        _ -> mkApps fun0 [Left arg1]-                  (expr,bindDecls) <- mkExpr False Sequential dst fun1-                  let assn = case expr of-                               Noop -> []-                               _ -> [Assignment dstNm expr]-                  return (Identifier dstNm Nothing, dstDecl ++ bindDecls ++ assn)-                Nothing -> do-                  let (_:arg0:_) = lefts args-                  (_,bindDecls) <- mkExpr True Sequential dst arg0-                  return (Noop, bindDecls)+                Just (_,dstNm,dstDecl) -> case lefts args of+                  (fun0:arg0:_) -> do+                    tcm <- Lens.view tcCache+                    let arg1 = unSimIO tcm arg0+                        fun1 = case fun0 of+                          Lam b bE ->+                            let is0 = mkInScopeSet (Lens.foldMapOf freeIds unitVarSet fun0)+                                subst = extendIdSubst (mkSubst is0) b arg1+                            in  substTm "mkPrimitive.fmapSimIO" subst bE+                          _ -> mkApps fun0 [Left arg1]+                    (expr,bindDecls) <- mkExpr False Sequential dst fun1+                    assn <- case expr of+                              Noop -> pure []+                              _ -> do declareUse (Proc Blocking) dstNm+                                      pure [Assignment dstNm (Proc Blocking) expr]+                    return (Identifier dstNm Nothing, dstDecl ++ bindDecls ++ assn)+                  args1 -> error ("internal error: fmapSimIO# has insufficient arguments"+                                  <> showPpr args1)+                Nothing -> case lefts args of+                  (_:arg0:_) -> do+                    (_,bindDecls) <- mkExpr True Sequential dst arg0+                    return (Noop, bindDecls)+                  args1 -> error ("internal error: fmapSimIO# has insufficient arguments"+                                  <> showPpr args1) +           | pNm == "Clash.Explicit.SimIO.unSimIO#" ->               case lefts args of                 (arg:_) -> mkExpr False Sequential dst arg@@ -596,9 +663,10 @@                   Noop ->                     return (Noop,decls)                   _ -> case dstNms of-                    [dstNm] ->+                    [dstNm] -> do+                      declareUse (Proc Blocking) dstNm                       return ( Identifier dstNm Nothing-                             , dstDecl ++ decls ++ [Assignment dstNm expr])+                             , dstDecl ++ decls ++ [Assignment dstNm (Proc Blocking) expr])                     _ -> error "internal error"                 _ ->                   return (Noop,decls)@@ -683,17 +751,18 @@         pure Nothing       else         case dst' of-          NetlistId dstL _ -> case mkDec of+          NetlistId dstL ty' -> case mkDec of             False -> do               -- TODO: check that it's okay to use `mkUnsafeSystemName`               let nm' = mkUnsafeSystemName (Id.toText dstL) 0-                  id_ = mkLocalId ty nm'+                  id_ = mkLocalId ty' nm'               return (Just ([id_],[dstL],[]))             True -> do               nm2 <- Id.suffix dstL "res"               -- TODO: check that it's okay to use `mkUnsafeInternalName`               let nm3 = mkUnsafeSystemName (Id.toText nm2) 0                   id_ = mkLocalId ty nm3+               idDeclM <- mkNetDecl (id_, mkApps (Prim pInfo) args)               case idDeclM of                 [] -> return Nothing@@ -706,10 +775,11 @@                   Multi primitive should only appear on the RHS of a                   let-binding. Please report this as a bug.                 |]+           CoreId dstR ->-            return (Just ([dstR], [Id.unsafeMake . nameOcc . varName $ dstR], []))+            return (Just ([dstR], [Id.unsafeFromCoreId dstR], []))           MultiId ids ->-            return (Just (ids, map (Id.unsafeMake . nameOcc . varName) ids, []))+            return (Just (ids, map Id.unsafeFromCoreId ids, []))      -- Like resBndr, but fails on MultiId     resBndr1@@ -741,15 +811,16 @@                           Lens.foldMapOf freeIds unitVarSet mealyIn)       -- Given that we're creating a sequential list of statements from the       -- let-bindings, make sure that everything is inverse topologically sorted-      (bs,res) = case inverseTopSortLetBindings res0 of-        Letrec bsN (C.Var resN) -> (bsN,resN)-        Letrec bsN e ->-          let u = case dst of-                    CoreId u0 -> u0-                    _ -> uniqAway is0-                           (mkLocalId (inferCoreTypeOf tcm e)-                                      (mkUnsafeSystemName "mealyres" 0))-          in  (bsN ++ [(u,e)], u)+      (bs,res) = case res0 of+        Letrec bsU e | let bsN = inverseTopSortLetBindings bsU -> case e of+          C.Var resN -> (bsN,resN)+          _ ->+            let u = case dst of+                      CoreId u0 -> u0+                      _ -> uniqAway is0+                            (mkLocalId (inferCoreTypeOf tcm e)+                                        (mkUnsafeSystemName "mealyres" 0))+            in  (bsN ++ [(u,e)], u)         e ->           let u = case dst of                     CoreId u0 -> u0@@ -814,37 +885,49 @@         Letrec _ (C.Var {}) -> mkExpr False Concurrent dst (C.Var result)         _ -> case dst of           CoreId {} -> pure (Noop,[])-          _ -> mkExpr False Concurrent dst (C.Var result)-      let resAssn = case resExpr of-            Noop -> []-            _ -> [Seq [AlwaysComb [SeqDecl (Assignment dstNm resExpr)]]]+          _ -> mkExpr False Sequential dst (C.Var result) +      resAssn <- case resExpr of+            Noop -> pure []+            _ -> do+              assign <- SeqDecl <$> procAssign Blocking dstNm resExpr+              pure [Seq [AlwaysComb [assign]]]+       -- Create the declarations for the "initial state" block       let sDst = case sBinders of                    [] -> error "internal error: insufficient sBinders"                    [(b,_)] -> CoreId b                    _       -> MultiId (map fst sBinders)+       (exprInit,initDecls) <- mkExpr False Sequential sDst mealyInit-      let initAssign = case exprInit of-            Identifier _ Nothing -> []-            Noop -> []-            _ -> case sBinders of-              ((b,_):_) -> [Assignment (id2identifier b) exprInit]-              _ -> error "internal error: insufficient sBinders" +      initAssign <- case exprInit of+        Identifier _ Nothing -> pure []+        Noop -> pure []+        _ -> case sBinders of+          ((b,_):_) -> do assn <- procAssign Blocking (Id.unsafeFromCoreId b) exprInit+                          pure [assn]+          _ -> error "internal error: insufficient sBinders"+       -- Create the declarations that corresponding to the input       let iDst = case iBinders of                    []      -> error "internal error: insufficient iBinders"                    [(b,_)] -> CoreId b                    _       -> MultiId (map fst iBinders)+       (exprArg,inpDeclsMisc) <- mkExpr False Concurrent iDst mealyIn +      argAssign <- case iBinders of+        ((i,_):_) -> do assn <- contAssign (Id.unsafeFromCoreId i) exprArg+                        pure [assn]+        _ -> error "internal error: insufficient iBinders"+       -- Split netdecl declarations and other declarations       let (netDeclsSeqMisc,seqDeclsOther) = partition isNet (seqDecls ++ resDecls)           (netDeclsInit,initDeclsOther)   = partition isNet initDecls       -- All assignments happens within a sequential block, so the nets need to       -- be of type 'reg' in Verilog nomenclature-      let netDeclsSeq1 = map toReg (netDeclsSeq ++ netDeclsSeqMisc ++ netDeclsInit)+      let netDeclsSeq1 = netDeclsSeq ++ netDeclsSeqMisc ++ netDeclsInit        -- We run mealy block in the opposite clock edge of the the ambient system       -- because we're basically clocked logic; so we need to have our outputs@@ -862,11 +945,8 @@       let netDeclsInp1 = netDeclsInp ++ inpDeclsMisc        -- Collate everything-      return (clkDecls ++ netDeclsSeq1 ++ netDeclsInp1 ++-                [ case iBinders of-                    ((i,_):_) -> Assignment (id2identifier i) exprArg-                    _ -> error "internal error: insufficient iBinders"-                , Seq [Initial (map SeqDecl (initDeclsOther ++ initAssign))]+      return (clkDecls ++ netDeclsSeq1 ++ netDeclsInp1 ++ argAssign +++                [ Seq [Initial (map SeqDecl (initDeclsOther ++ initAssign))]                 , Seq [AlwaysClocked edge clkExpr (map SeqDecl seqDeclsOther)]                 ] ++ resAssn)     _ -> error "internal error"@@ -874,9 +954,6 @@   isNet NetDecl' {} = True   isNet _ = False -  toReg (NetDecl' cmM _ r ty eM) = NetDecl' cmM Reg r ty eM-  toReg d = d- collectMealy _ _ _ _ = error "internal error"  -- | Collect the sequential declarations for 'bindIO'@@ -891,14 +968,14 @@   let qS = substTm "collectBindIO1" subst q   case splitNormalized tcm qS of     Right (args,bs0,res) -> do-      let Letrec bs _ = inverseTopSortLetBindings (Letrec bs0 (C.Var res))+      let bs = inverseTopSortLetBindings bs0       let is0 = mkInScopeSet (Lens.foldMapOf freeIds unitVarSet qS)       normE <- mkUniqueNormalized is0 Nothing (args,bs,res)       case normE of         (_,_,[],_,[],binders,Just result) -> do           ds1 <- concatMapM (uncurry (mkDeclarations' Sequential)) binders           netDecls <- concatMapM mkNetDecl binders-          return (Identifier (id2identifier result) Nothing, netDecls ++ ds0 ++ ds1)+          return (Identifier (Id.unsafeFromCoreId result) Nothing, netDecls ++ ds0 ++ ds1)         _ -> error "internal error"     _ -> case substTm "collectBindIO2" subst e of       Letrec {} -> error "internal error"@@ -912,12 +989,12 @@  where   collectAction tcm = case splitNormalized tcm m of     Right (args,bs0,res) -> do-      let Letrec bs _ = inverseTopSortLetBindings (Letrec bs0 (C.Var res))+      let bs = inverseTopSortLetBindings bs0       let is0 = mkInScopeSet (Lens.foldMapOf freeIds unitVarSet m)       normE <- mkUniqueNormalized is0 Nothing (args,(x,m):bs,res)       case normE of         (_,_,[],_,[],binders@(b:_),Just result) -> do-          let binders1 = tail binders ++ [(fst b, C.Var result)]+          let binders1 = drop 1 binders ++ [(fst b, C.Var result)]           ds1 <- concatMapM (uncurry (mkDeclarations' Sequential)) binders1           netDecls <- concatMapM mkNetDecl binders           return (netDecls ++ ds1,extendIdSubst (mkSubst eInScopeSet) x (Var (fst b)))@@ -973,20 +1050,23 @@ -- a function mkFunInput   :: HasCallStack-  => Id+  => TextS.Text+  -- ^ Name of the primitive of which the function in question is an argument.+  -- Used for error reporting.+  -> Id   -- ^ Identifier binding the encompassing primitive/blackbox application. Used   -- as a name hint if 'mkFunInput' needs intermediate signals.   -> Term   -- ^ The function argument term   -> NetlistMonad       ((Either BlackBox (Identifier,[Declaration])-       ,WireOrReg+       ,Usage        ,[BlackBoxTemplate]        ,[BlackBoxTemplate]        ,[((TextS.Text,TextS.Text),BlackBox)]        ,BlackBoxContext)       ,[Declaration])-mkFunInput resId e =+mkFunInput parentName resId e =  let (appE,args,ticks) = collectArgsTicks e  in  withTicks ticks $ \tickDecls -> do   tcm <- Lens.view tcCache@@ -997,7 +1077,7 @@               bb  <- extractPrimWarnOrFail (primName p)               case bb of                 P.BlackBox {..} ->-                  pure (Left (kind,outputReg,libraries,imports,includes,primName p,template))+                  pure (Left (kind,outputUsage,libraries,imports,includes,primName p,template))                 P.Primitive pn _ pt ->                   error $ $(curLoc) ++ "Unexpected blackbox type: "                                     ++ "Primitive " ++ show pn@@ -1023,7 +1103,7 @@                                         ++ err                     Right (BlackBoxMeta{..}, template) ->                       pure $-                        Left ( bbKind, bbOutputReg, bbLibrary, bbImports+                        Left ( bbKind, bbOutputUsage, bbLibrary, bbImports                              , bbIncludes, pName, template)             Data dc -> do               let eTy = inferCoreTypeOf tcm e@@ -1038,8 +1118,8 @@                 Just (_resHTy, [areVoids@(countEq False -> 1)]) -> do                   let nonVoidArgI = fromJust (elemIndex False areVoids)                   let arg = Id.unsafeMake (TextS.concat ["~ARG[", showt nonVoidArgI, "]"])-                  let assign = Assignment (Id.unsafeMake "~RESULT") (Identifier arg Nothing)-                  return (Right ((Id.unsafeMake "", tickDecls ++ [assign]), Wire))+                  let assign = Assignment (Id.unsafeMake "~RESULT") Cont (Identifier arg Nothing)+                  return (Right ((Id.unsafeMake "", tickDecls ++ [assign]), Cont))                  -- Because we filter void constructs, the argument indices and                 -- the field indices don't necessarily correspond anymore. We@@ -1053,8 +1133,8 @@                       mkArg i   = Id.unsafeMake ("~ARG[" <> showt i <> "]")                       dcInps    = [Identifier (mkArg x) Nothing | x <- originalIndices areVoids1]                       dcApp     = DataCon resHTy (DC (resHTy,dcI)) dcInps-                      dcAss     = Assignment (Id.unsafeMake "~RESULT") dcApp-                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]),Wire))+                      dcAss     = Assignment (Id.unsafeMake "~RESULT") Cont dcApp+                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]), Cont))                  -- CustomSP the same as SP, but with a user-defined bit                 -- level representation@@ -1065,16 +1145,16 @@                       mkArg i   = Id.unsafeMake ("~ARG[" <> showt i <> "]")                       dcInps    = [Identifier (mkArg x) Nothing | x <- originalIndices areVoids1]                       dcApp     = DataCon resHTy (DC (resHTy,dcI)) dcInps-                      dcAss     = Assignment (Id.unsafeMake "~RESULT") dcApp-                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]),Wire))+                      dcAss     = Assignment (Id.unsafeMake "~RESULT") Cont dcApp+                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]), Cont))                  -- Like SP, we have to retrieve the index BEFORE filtering voids                 Just (resHTy@(Product _ _ _), areVoids1:_) -> do                   let mkArg i    = Id.unsafeMake ("~ARG[" <> showt i <> "]")                       dcInps    = [ Identifier (mkArg x) Nothing | x <- originalIndices areVoids1]                       dcApp     = DataCon resHTy (DC (resHTy,0)) dcInps-                      dcAss     = Assignment (Id.unsafeMake "~RESULT") dcApp-                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]),Wire))+                      dcAss     = Assignment (Id.unsafeMake "~RESULT") Cont dcApp+                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]), Cont))                  -- Vectors never have defined areVoids (or all set to False), as                 -- it would be converted to Void otherwise. We can therefore@@ -1083,22 +1163,22 @@                   let mkArg i = Id.unsafeMake ("~ARG[" <> showt i <> "]")                       dcInps = [ Identifier (mkArg x) Nothing | x <- [(1::Int)..2] ]                       dcApp  = DataCon resHTy (DC (resHTy,1)) dcInps-                      dcAss  = Assignment (Id.unsafeMake "~RESULT") dcApp-                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]),Wire))+                      dcAss  = Assignment (Id.unsafeMake "~RESULT") Cont dcApp+                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]), Cont))                  -- Sum types OR a Sum type after filtering empty types:                 Just (resHTy@(Sum _ _), _areVoids) -> do                   let dcI   = dcTag dc - 1                       dcApp = DataCon resHTy (DC (resHTy,dcI)) []-                      dcAss = Assignment (Id.unsafeMake "~RESULT") dcApp-                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]),Wire))+                      dcAss = Assignment (Id.unsafeMake "~RESULT") Cont dcApp+                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]), Cont))                  -- Same as Sum, but with user defined bit level representation                 Just (resHTy@(CustomSum {}), _areVoids) -> do                   let dcI   = dcTag dc - 1                       dcApp = DataCon resHTy (DC (resHTy,dcI)) []-                      dcAss = Assignment (Id.unsafeMake "~RESULT") dcApp-                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]),Wire))+                      dcAss = Assignment (Id.unsafeMake "~RESULT") Cont dcApp+                  return (Right ((Id.unsafeMake "",tickDecls ++ [dcAss]), Cont))                  Just (Void {}, _areVoids) ->                   return (error $ $(curLoc) ++ "Encountered Void in mkFunInput."@@ -1114,7 +1194,7 @@                   normalized <- Lens.use bindings                   case lookupVarEnv fun normalized of                     Just _ -> do-                      (meta,N.Component compName compInps [(_,compOutp,_)] _) <-+                      (meta,N.Component compName compInps compOutps _) <-                         preserveVarEnv $ genComponent fun                        let@@ -1123,16 +1203,32 @@                         inpVar i = Id.unsafeMake ("~VAR[arg" <> showt i <> "][" <> showt i <> "]")                         inpVars = [Identifier (inpVar i)  Nothing | i <- originalIndices cmWereVoids]                         inpAssigns = zipWith inpAssign compInps inpVars-                        outpAssign =-                          ( Identifier (fst compOutp) Nothing-                          , Out-                          , snd compOutp-                          , Identifier (Id.unsafeMake "~RESULT") Nothing )+                        outpAssigns = case compOutps of+                          [] -> [] -- See issue #2549+                          [(_,compOutp,_)] ->+                            [ ( Identifier (fst compOutp) Nothing+                              , Out+                              , snd compOutp+                              , Identifier (Id.unsafeMake "~RESULT") Nothing )+                            ]+                          outps ->+                            error [I.i|+                              Cannot handle multi-result function as an argument to+                              a primitive.++                              Primitive: #{parentName}++                              Argument: #{showPpr fun} :: #{showPpr (varType fun)}++                              Outputs: #{show (map (\(_,x,_) -> x) outps)}++                              Please report this as an issue.+                            |]                       instLabel <- Id.next compName                       let-                        portMap = NamedPortMap (outpAssign:inpAssigns)+                        portMap = NamedPortMap (outpAssigns ++ inpAssigns)                         instDecl = InstDecl Entity Nothing [] compName instLabel [] portMap-                      return (Right ((Id.unsafeMake "",tickDecls ++ [instDecl]),Wire))+                      return (Right ((Id.unsafeMake "",tickDecls ++ [instDecl]), Cont))                     Nothing -> error $ $(curLoc) ++ "Cannot make function input for: " ++ showPpr e             C.Lam {} -> do               let is0 = mkInScopeSet (Lens.foldMapOf freeIds unitVarSet appE)@@ -1143,27 +1239,27 @@               _ -> "__INTERNAL__"   (bbCtx,dcls) <- mkBlackBoxContext pNm [resId] args   case templ of-    Left (TDecl,oreg,libs,imps,inc,_,templ') -> do+    Left (TDecl,outputUsage,libs,imps,inc,_,templ') -> do       (l',templDecl)         <- onBlackBox             (fmap (first BBTemplate) . setSym bbCtx)             (\bbName bbHash bbFunc -> pure $ (BBFunction bbName bbHash bbFunc, []))             templ'-      return ((Left l',if oreg then Reg else Wire,libs,imps,inc,bbCtx),dcls ++ templDecl)+      return ((Left l',outputUsage,libs,imps,inc,bbCtx),dcls ++ templDecl)     Left (TExpr,_,libs,imps,inc,nm,templ') -> do       onBlackBox         (\t -> do t' <- getAp (prettyBlackBox t)                   let t'' = Id.unsafeMake (Text.toStrict t')-                      assn = Assignment (Id.unsafeMake "~RESULT") (Identifier t'' Nothing)-                  return ((Right (Id.unsafeMake "",[assn]),Wire,libs,imps,inc,bbCtx),dcls))+                      assn = Assignment (Id.unsafeMake "~RESULT") Cont (Identifier t'' Nothing)+                  return ((Right (Id.unsafeMake "",[assn]),Cont,libs,imps,inc,bbCtx),dcls))         (\bbName bbHash (TemplateFunction k g _) -> do           let f' bbCtx' = do-                let assn = Assignment (Id.unsafeMake "~RESULT")+                let assn = Assignment (Id.unsafeMake "~RESULT") Cont                             (BlackBoxE nm libs imps inc templ' bbCtx' False)                 p <- getAp (Backend.blockDecl (Id.unsafeMake "") [assn])                 return p           return ((Left (BBFunction bbName bbHash (TemplateFunction k g f'))-                  ,Wire+                  ,Cont                   ,[]                   ,[]                   ,[]@@ -1173,8 +1269,8 @@                  )         )         templ'-    Right (decl,wr) ->-      return ((Right decl,wr,[],[],[],bbCtx),dcls)+    Right (decl,u) ->+      return ((Right decl,u,[],[],[],bbCtx),dcls)   where     goExpr app@(collectArgsTicks -> (C.Var fun,args@(_:_),ticks)) = do       tcm <- Lens.view tcCache@@ -1185,10 +1281,10 @@           withTicks ticks $ \tickDecls -> do             resNm <- Id.make "result"             appDecls <- mkFunApp resNm fun tmArgs tickDecls-            let assn = [ Assignment (Id.unsafeMake "~RESULT") (Identifier resNm Nothing)+            let assn = [ Assignment (Id.unsafeMake "~RESULT") Cont (Identifier resNm Nothing)                        , NetDecl Nothing resNm resTy ]             nm <- Id.makeBasic "block"-            return (Right ((nm,assn++appDecls),Wire))+            return (Right ((nm,assn++appDecls), Cont))         else do           (_,sp) <- Lens.use curCompNm           throw (ClashException sp ($(curLoc) ++ "Not in normal form: Var-application with Type arguments:\n\n" ++ showPpr app) Nothing)@@ -1196,11 +1292,11 @@       tcm <- Lens.view tcCache       let eType = inferCoreTypeOf tcm e'       (appExpr,appDecls) <- mkExpr False Concurrent (NetlistId (Id.unsafeMake "c$bb_res") eType) e'-      let assn = Assignment (Id.unsafeMake "~RESULT") appExpr+      let assn = Assignment (Id.unsafeMake "~RESULT") Cont appExpr       nm <- if null appDecls                then return (Id.unsafeMake "")                else Id.makeBasic "block"-      return (Right ((nm,appDecls ++ [assn]),Wire))+      return (Right ((nm,appDecls ++ [assn]), Cont))      go is0 n (Lam id_ e') = do       lvl <- Lens.use curBBlvl@@ -1213,38 +1309,30 @@       go is1 (n+(1::Int)) e''      go _ _ (C.Var v) = do-      let assn = Assignment (Id.unsafeMake "~RESULT") (Identifier (id2identifier v) Nothing)-      return (Right ((Id.unsafeMake "",[assn]),Wire))+      let assn = Assignment (Id.unsafeMake "~RESULT") Cont (Identifier (Id.unsafeFromCoreId v) Nothing)+      return (Right ((Id.unsafeMake "",[assn]), Cont))      go _ _ (Case scrut ty [alt]) = do       tcm <- Lens.view tcCache       let sTy = inferCoreTypeOf tcm scrut       (projection,decls) <- mkProjection False (NetlistId (Id.unsafeMake "c$bb_res") sTy) scrut ty alt-      let assn = Assignment (Id.unsafeMake "~RESULT") projection+      let assn = Assignment (Id.unsafeMake "~RESULT") Cont projection       nm <- if null decls                then return (Id.unsafeMake "")                else Id.makeBasic "projection"-      return (Right ((nm,decls ++ [assn]),Wire))--    go _ _ (Case scrut ty alts@(_:_:_)) = do-      tcm <- Lens.view tcCache-      let scrutTy = inferCoreTypeOf tcm scrut-      scrutHTy <- unsafeCoreTypeToHWTypeM' $(curLoc) scrutTy-      ite <- Lens.use backEndITE-      let wr = case iteAlts scrutHTy alts of-                 Just _ | ite -> Wire-                 _ -> Reg+      return (Right ((nm,decls ++ [assn]), Cont)) +    go _ _ (Case scrut ty (alt:alts@(_:_))) = do       resNm <- Id.make "result"+      resTy <- unsafeCoreTypeToHWTypeM' $(curLoc) ty       -- It's safe to use 'mkUnsafeSystemName' here: only the name, not the       -- unique, will be used       let resId'  = NetlistId resNm ty-      selectionDecls <- mkSelection Concurrent resId' scrut ty alts []-      resTy <- unsafeCoreTypeToHWTypeM' $(curLoc) ty-      let assn = [ NetDecl' Nothing wr resNm (Right resTy) Nothing-                 , Assignment (Id.unsafeMake "~RESULT") (Identifier resNm Nothing) ]+      selectionDecls <- mkSelection Concurrent resId' scrut ty (alt :| alts) []+      let assn = [ NetDecl' Nothing resNm resTy Nothing+                 , Assignment (Id.unsafeMake "~RESULT") Cont (Identifier resNm Nothing) ]       nm <- Id.makeBasic "selection"-      return (Right ((nm,assn++selectionDecls),Wire))+      return (Right ((nm,assn++selectionDecls), Cont))      go is0 _ e'@(Let{}) = do       tcm <- Lens.view tcCache@@ -1258,15 +1346,15 @@           netDecls <- concatMapM mkNetDecl $ binders           decls    <- concatMapM (uncurry mkDeclarations) binders           nm <- Id.makeBasic "fun"-          let resultId = id2identifier result+          let resultId = Id.unsafeFromCoreId result           -- TODO: Due to reasons lost in the mists of time, #1265 creates an           -- assignement here, whereas it previously wouldn't. With the PR in           -- tests break when reverting to the old behavior. In some cases this           -- creates "useless" assignments. We should investigate whether we can           -- get the old behavior back.-          let resDecl = Assignment (Id.unsafeMake "~RESULT") (Identifier resultId Nothing)-          return (Right ((nm,resDecl:netDecls ++ decls),Wire))-        Nothing -> return (Right ((Id.unsafeMake "",[]),Wire))+          let resDecl = Assignment (Id.unsafeMake "~RESULT") Cont (Identifier resultId Nothing)+          return (Right ((nm,resDecl:netDecls ++ decls), Cont))+        Nothing -> return (Right ((Id.unsafeMake "",[]), Cont))      go is0 n (Tick _ e') = go is0 n e' 
src/Clash/Netlist/BlackBox/Parser.hs view
@@ -2,6 +2,7 @@   Copyright  :  (C) 2012-2016, University of Twente,                     2017     , Myrtle Software Ltd,                     2021-2022, QBayLogic B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -112,7 +113,9 @@      <|> IsActiveEnable    <$> (string "~ISACTIVEENABLE" *> brackets' natural')      <|> IsUndefined       <$> (string "~ISUNDEFINED" *> brackets' natural')      <|> StrCmp            <$> (string "~STRCMP" *> brackets' pSigD) <*> brackets' natural'-     <|> OutputWireReg     <$> (string "~OUTPUTWIREREG" *> brackets' natural')+     -- Parse ~OUTPUTWIREREG for backwards compatibility+     <|> OutputUsage       <$> (string "~OUTPUTWIREREG" *> brackets' natural')+     <|> OutputUsage       <$> (string "~OUTPUTUSAGE" *> brackets' natural')      <|> GenSym            <$> (string "~GENSYM" *> brackets' pSigD) <*> brackets' natural'      <|> Template          <$> (string "~TEMPLATE" *> brackets' pSigD) <*> brackets' pSigD      <|> Repeat            <$> (string "~REPEAT" *> brackets' pSigD) <*> brackets' pSigD
src/Clash/Netlist/BlackBox/Types.hs view
@@ -3,6 +3,7 @@                     2017     , Myrtle Software Ltd,                     2021-2022, QBayLogic B.V.                     2022     , LUMI GUIDE FIETSDETECTIE B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -34,7 +35,7 @@ import                Clash.Core.Term            (Term) import                Clash.Core.Type            (Type) import {-# SOURCE #-} Clash.Netlist.Types-  (BlackBox, NetlistMonad)+  (BlackBox, NetlistMonad, Usage(Cont))  import qualified      Clash.Signal.Internal      as Signal @@ -52,10 +53,10 @@   | TExpr   deriving (Show, Eq, Generic, NFData, Binary, Hashable) --- | See @Clash.Primitives.Types.BlackBox@ for documentation on this record's+-- | See 'Clash.Primitives.Types.BlackBox' for documentation on this record's -- fields. (They are intentionally renamed to prevent name clashes.) data BlackBoxMeta =-  BlackBoxMeta { bbOutputReg :: Bool+  BlackBoxMeta { bbOutputUsage :: Usage                , bbKind :: TemplateKind                , bbLibrary :: [BlackBoxTemplate]                , bbImports :: [BlackBoxTemplate]@@ -67,9 +68,9 @@                }  -- | Use this value in your blackbox template function if you do want to--- accept the defaults as documented in @Clash.Primitives.Types.BlackBox@.+-- accept the defaults as documented in 'Clash.Primitives.Types.BlackBox'. emptyBlackBoxMeta :: BlackBoxMeta-emptyBlackBoxMeta = BlackBoxMeta False TExpr [] [] [] [] NoRenderVoid [] []+emptyBlackBoxMeta = BlackBoxMeta Cont TExpr [] [] [] [] NoRenderVoid [] []  -- | A BlackBox function generates a blackbox template, given the inputs and -- result type of the function it should provide a blackbox for. This is useful@@ -178,7 +179,8 @@   -- ^ Period of a domain. Errors if not applied to a @KnownDomain@ or   -- @KnownConfiguration@.   | LongestPeriod-  -- ^ Longest period of all known domains+  -- ^ Longest period of all known domains. The minimum duration returned is+  -- 100 ns, see https://github.com/clash-lang/clash-compiler/issues/2455.   | ActiveEdge !Signal.ActiveEdge !Int   -- ^ Test active edge of memory elements in a certain domain. Errors if not   -- applied to a @KnownDomain@ or @KnownConfiguration@.@@ -198,7 +200,7 @@   -- always return 0 (False) if `-fclash-aggressive-x-optimization-blackboxes`   -- is NOT set.   | StrCmp [Element] !Int-  | OutputWireReg !Int+  | OutputUsage !Int   | Vars !Int   | GenSym [Element] !Int   | Repeat [Element] [Element]
src/Clash/Netlist/BlackBox/Util.hs view
@@ -1,8 +1,9 @@ {-|   Copyright  :  (C) 2012-2016, University of Twente,                     2016-2017, Myrtle Software Ltd,-                    2021-2022, QBayLogic B.V.+                    2021-2023, QBayLogic B.V.                     2022     , LUMI GUIDE FIETSDETECTIE B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -13,6 +14,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-}@@ -55,7 +57,7 @@ import           Text.Trifecta.Result            hiding (Err)  import           Clash.Backend-  (Backend (..), Usage (..), AggressiveXOptBB(..), RenderEnums(..))+  (Backend (..), DomainMap, Usage (..), AggressiveXOptBB(..), RenderEnums(..)) import           Clash.Netlist.BlackBox.Parser import           Clash.Netlist.BlackBox.Types import           Clash.Netlist.Types@@ -63,7 +65,7 @@    Declaration(BlackBoxD)) import qualified Clash.Netlist.Id                as Id import qualified Clash.Netlist.Types             as N-import           Clash.Netlist.Util              (typeSize, isVoid, stripVoid)+import           Clash.Netlist.Util              (typeSize, isVoid, stripAttributes, stripVoid) import           Clash.Signal.Internal   (ResetKind(..), ResetPolarity(..), InitBehavior(..), VDomainConfiguration (..)) import           Clash.Util@@ -117,7 +119,7 @@   IsActiveEnable n -> pure n   IsUndefined n    -> pure n   StrCmp _ n       -> pure n-  OutputWireReg n  -> pure n+  OutputUsage n    -> pure n   Vars n           -> pure n   GenSym _ _       -> Nothing   Repeat _ _       -> Nothing@@ -125,7 +127,7 @@   SigD _ nM        -> nM   CtxName          -> Nothing --- | Determine if the number of normal/literal/function inputs of a blackbox+-- | Determine if the number of normal\/literal\/function inputs of a blackbox -- context at least matches the number of argument that is expected by the -- template. verifyBlackBoxContext@@ -183,10 +185,11 @@             Just n ->               case indexMaybe (bbInputs bbCtx) n of                 Just _ -> Nothing-                Nothing ->-                  Just ( "Blackbox required at least " ++ show (n+1)-                      ++ " arguments, but only " ++ show (length (bbInputs bbCtx))-                      ++ " were passed." )+                Nothing -> do+                  let str = fromJust (fmap Text.unpack (getAp $ prettyElem e))+                  Just ( "Blackbox used \"" ++ str ++ "\""+                      ++ ", but only " ++ show (length (bbInputs bbCtx))+                      ++ " arguments were passed." )  extractLiterals :: BlackBoxContext                 -> [Expr]@@ -227,7 +230,7 @@               let decls = case typeSize hwTy of                     0 -> []                     _ -> [N.NetDecl Nothing nm' hwTy-                         ,N.Assignment nm' e'+                         ,N.Assignment nm' N.Cont e' -- TODO De-hardcode Cont                          ]               _2 %= (IntMap.insert i (Id.toText nm',decls))               return (ToVar [Text (Id.toLazyText nm')] i)@@ -392,51 +395,57 @@ renderElem b (Component (Decl n subN (l:ls))) = do   (o,oTy,_) <- idToExpr <$> bitraverse (lineToIdentifier b) (return . lineToType b) l   is <- mapM (fmap idToExpr . bitraverse (lineToIdentifier b) (return . lineToType b)) ls+  sp <- getSrcSpan   let func0 = IntMap.lookup n (bbFunctions b)       errr = concat [ "renderElem: not enough functions rendered? Needed "                     , show (subN +1 ), " got only ", show (length (fromJust func0)) ]-      func1 = indexNote' errr subN <$> func0-      Just (templ0,_,libs,imps,inc,pCtx) = func1-      b' = pCtx { bbResults = [(o,oTy)], bbInputs = bbInputs pCtx ++ is }-      layoutOptions = LayoutOptions (AvailablePerLine 120 0.4)-      render = N.BBTemplate . parseFail . renderLazy . layoutPretty layoutOptions--  templ1 <--    case templ0 of-      Left t ->-        return t-      Right (nm0,ds) -> do-        nm1 <- Id.next nm0-        block <- getAp (blockDecl nm1 ds)-        return (render block)+  case indexNote' errr subN <$> func0 of+    Just (templ0,_,libs,imps,inc,pCtx) -> do+      let b' = pCtx { bbResults = [(o,oTy)], bbInputs = bbInputs pCtx ++ is }+          layoutOptions = LayoutOptions (AvailablePerLine 120 0.4)+          render = N.BBTemplate . parseFail . renderLazy . layoutPretty layoutOptions -  templ4 <--    case templ1 of-      N.BBFunction {} ->-        return templ1-      N.BBTemplate templ2 -> do-        (templ3, templDecls) <- setSym b' templ2-        case templDecls of-          [] ->-            return (N.BBTemplate templ3)-          _ -> do-            nm1 <- Id.toText <$> Id.makeBasic "bb"-            nm2 <- Id.makeBasic "bb"-            let bbD = BlackBoxD nm1 libs imps inc (N.BBTemplate templ3) b'-            block <- getAp (blockDecl nm2 (templDecls ++ [bbD]))+      templ1 <-+        case templ0 of+          Left t ->+            return t+          Right (nm0,ds) -> do+            nm1 <- Id.next nm0+            block <- getAp (blockDecl nm1 ds)             return (render block) -  case verifyBlackBoxContext b' templ4 of-    Nothing -> do-      bb <- renderBlackBox libs imps inc templ4 b'-      return (renderLazy . layoutPretty layoutOptions . bb)-    Just err0 -> do-      sp <- getSrcSpan-      let err1 = concat [ "Couldn't instantiate blackbox for "-                        , Data.Text.unpack (bbName b), ". Verification procedure "-                        , "reported:\n\n" ++ err0 ]-      throw (ClashException sp ($(curLoc) ++ err1) Nothing)+      templ4 <-+        case templ1 of+          N.BBFunction {} ->+            return templ1+          N.BBTemplate templ2 -> do+            (templ3, templDecls) <- setSym b' templ2+            case templDecls of+              [] ->+                return (N.BBTemplate templ3)+              _ -> do+                nm1 <- Id.toText <$> Id.makeBasic "bb"+                nm2 <- Id.makeBasic "bb"+                let bbD = BlackBoxD nm1 libs imps inc (N.BBTemplate templ3) b'+                block <- getAp (blockDecl nm2 (templDecls ++ [bbD]))+                return (render block) +      case verifyBlackBoxContext b' templ4 of+        Nothing -> do+          bb <- renderBlackBox libs imps inc templ4 b'+          return (renderLazy . layoutPretty layoutOptions . bb)+        Just err0 -> do+          let err1 = concat [ "Couldn't instantiate blackbox for "+                            , Data.Text.unpack (bbName b), ". Verification procedure "+                            , "reported:\n\n" ++ err0 ]+          throw (ClashException sp ($(curLoc) ++ err1) Nothing)+    Nothing ->+      let err1 = concat [show n+                        , "'th argument isn't a function, only "+                        , show (IntMap.keys (bbFunctions b))+                        , "are."]+       in throw (ClashException sp ($(curLoc) ++ err1) Nothing)+ renderElem b (SigD e m) = do   e' <- Text.concat <$> mapM (fmap ($ 0) . renderElem b) e   let ty = case m of@@ -456,7 +465,9 @@  renderElem _ LongestPeriod = do   doms <- domainConfigurations-  let longestPeriod = maximum [vPeriod v | v <- HashMap.elems doms]+  -- Longest period with a minimum of 100 ns, see:+  -- https://github.com/clash-lang/clash-compiler/issues/2455+  let longestPeriod = maximum (100_000 : [vPeriod v | v <- HashMap.elems doms])   return (const (Text.pack (show longestPeriod)))  renderElem b (Tag n) = do@@ -466,6 +477,8 @@       return (const (Text.pack (Data.Text.unpack dom)))     Clock dom ->       return (const (Text.pack (Data.Text.unpack dom)))+    ClockN dom ->+      return (const (Text.pack (Data.Text.unpack dom)))     Reset dom ->       return (const (Text.pack (Data.Text.unpack dom)))     Enable dom ->@@ -480,45 +493,57 @@   syn <- hdlSyn   enums <- renderEnums   xOpt <- aggressiveXOptBB-  let c' = check (coerce xOpt) iw hdl syn enums c+  c' <- check (coerce xOpt) iw hdl syn enums c   if c' > 0 then renderTemplate b t else renderTemplate b f   where-    check :: Bool -> Int -> HDL -> HdlSyn -> RenderEnums -> Element -> Int+    check :: Backend backend => Bool -> Int -> HDL -> HdlSyn -> RenderEnums -> Element -> State backend Int     check xOpt iw hdl syn enums c' = case c' of-      (Size e)   -> typeSize (lineToType b [e])-      (Length e) -> case lineToType b [e] of+      (Size e)   -> pure $ typeSize (lineToType b [e])+      (Length e) -> pure $ case lineToType b [e] of                        (Vector n _)              -> n                        Void (Just (Vector n _))  -> n                        (MemBlob n _)             -> n                        Void (Just (MemBlob n _)) -> n                        _                         -> 0 -- HACK: So we can test in splitAt if one of the                               -- vectors in the tuple had a zero length-      (Lit n) -> case bbInputs b !! n of+      (Lit n) -> pure $ case bbInputs b !! n of         (l,_,_)           | Literal _ l' <- l ->             case l' of+              -- Integer, Int#, KnownNat, Natural, Word#               NumLit i -> fromInteger i+              -- Bit               BitLit bl -> case bl of                 N.H -> 1                 N.L -> 0                 _   -> error $ $(curLoc) ++ "IF: LIT bit literal must be high or low"+              -- Bool               BoolLit bl -> bool 0 1 bl               _ -> error $ $(curLoc) ++ "IF: LIT must be a numeric lit"+          -- Int           | DataCon (Signed _) _ [Literal _ (NumLit i)] <- l             -> fromInteger i+          -- Word, SNat           | DataCon (Unsigned _) _ [Literal _ (NumLit i)] <- l             -> fromInteger i+          | BlackBoxE pNm _lib _use _incl _templ bbCtx _paren <- l+          , pNm `elem` ["GHC.Int.I8#", "GHC.Int.I16#", "GHC.Int.I32#", "GHC.Int.I64#"+                       ,"GHC.Word.W8#","GHC.Word.W16#","GHC.Word.W32#","GHC.Word.W64#"+                       ,"GHC.Types.I#","GHC.Types.W#"+                       ]+          , [Literal _ (NumLit j)] <- extractLiterals bbCtx+          -> fromInteger j         k -> error $ $(curLoc) ++ ("IF: LIT must be a numeric lit:" ++ show k)-      (Depth e)  -> case lineToType b [e] of+      (Depth e)  -> pure $ case lineToType b [e] of                       (RTree n _) -> n                       _ -> error $ $(curLoc) ++ "IF: treedepth of non-tree type"-      IW64       -> if iw == 64 then 1 else 0-      (HdlSyn s) -> if s == syn then 1 else 0-      (IsVar n)  -> let (e,_,_) = bbInputs b !! n+      IW64       -> pure $ if iw == 64 then 1 else 0+      (HdlSyn s) -> pure $ if s == syn then 1 else 0+      (IsVar n)  -> pure $ let (e,_,_) = bbInputs b !! n                     in case e of                       Identifier _ Nothing -> 1                       _                    -> 0-      (IsLit n)  -> let (e,_,_) = bbInputs b !! n+      (IsLit n)  -> pure $ let (e,_,_) = bbInputs b !! n                     in case e of                       DataCon {}   -> 1                       Literal {}   -> 1@@ -532,13 +557,13 @@                                                        RenderEnums True  -> 1                                                        RenderEnums False -> 0                           isScalar _ _            = 0-                      in isScalar hdl ty+                        in pure $ isScalar hdl ty -      (IsUndefined n) ->+      (IsUndefined n) -> pure $         let (e, _, _) = bbInputs b !! n         in if xOpt && checkUndefined e then 1 else 0 -      (IsActiveEnable n) ->+      (IsActiveEnable n) -> pure $         let (e, ty, _) = bbInputs b !! n in         case ty of           Enable _ ->@@ -558,54 +583,83 @@               Literal Nothing (BoolLit False) -> 1               _                               -> 1           _ ->-            error $ $(curLoc) ++ "IsActiveEnable: Expected Bool, not: " ++ show ty+            error $ $(curLoc) ++ "IsActiveEnable: Expected Bool or Enable, not: " ++ show ty -      (ActiveEdge edgeRequested n) ->-        let (_, ty, _) = bbInputs b !! n in-        case stripVoid ty of-          KnownDomain _ _ edgeActual _ _ _ ->+      (ActiveEdge edgeRequested n) -> do+        let (_, ty, _) = bbInputs b !! n+        domConf <- getDomainConf ty+        case domConf of+          VDomainConfiguration _ _ edgeActual _ _ _ -> pure $             if edgeRequested == edgeActual then 1 else 0-          _ ->-            error $ $(curLoc) ++ "ActiveEdge: Expected `KnownDomain` or `KnownConfiguration`, not: " ++ show ty -      (IsSync n) ->-        let (_, ty, _) = bbInputs b !! n in-        case stripVoid ty of-          KnownDomain _ _ _ Synchronous _ _ -> 1-          KnownDomain _ _ _ Asynchronous _ _ -> 0-          _ -> error $ $(curLoc) ++ "IsSync: Expected `KnownDomain` or `KnownConfiguration`, not: " ++ show ty+      (IsSync n) -> do+        let (_, ty, _) = bbInputs b !! n+        domConf <- getDomainConf ty+        case domConf of+          VDomainConfiguration _ _ _ Synchronous _ _ -> pure 1+          VDomainConfiguration _ _ _ Asynchronous _ _ -> pure 0 -      (IsInitDefined n) ->-        let (_, ty, _) = bbInputs b !! n in-        case stripVoid ty of-          KnownDomain _ _ _ _ Defined _ -> 1-          KnownDomain _ _ _ _ Unknown _ -> 0-          _ -> error $ $(curLoc) ++ "IsInitDefined: Expected `KnownDomain` or `KnownConfiguration`, not: " ++ show ty+      (IsInitDefined n) -> do+        let (_, ty, _) = bbInputs b !! n+        domConf <- getDomainConf ty+        case domConf of+          VDomainConfiguration _ _ _ _ Defined _ -> pure 1+          VDomainConfiguration _ _ _ _ Unknown _ -> pure 0 -      (IsActiveHigh n) ->-        let (_, ty, _) = bbInputs b !! n in-        case stripVoid ty of-          KnownDomain _ _ _ _ _ ActiveHigh -> 1-          KnownDomain _ _ _ _ _ ActiveLow -> 0-          _ -> error $ $(curLoc) ++ "IsActiveHigh: Expected `KnownDomain` or `KnownConfiguration`, not: " ++ show ty+      (IsActiveHigh n) -> do+        let (_, ty, _) = bbInputs b !! n+        domConf <- getDomainConf ty+        case domConf of+          VDomainConfiguration _ _ _ _ _ ActiveHigh -> pure 1+          VDomainConfiguration _ _ _ _ _ ActiveLow  -> pure 0 -      (StrCmp [Text t1] n) ->+      (StrCmp [Text t1] n) -> pure $         let (e,_,_) = bbInputs b !! n         in  case exprToString e of               Just t2                 | t1 == Text.pack t2 -> 1                 | otherwise -> 0               Nothing -> error $ $(curLoc) ++ "Expected a string literal: " ++ show e-      (And es)   -> if all (/=0) (map (check xOpt iw hdl syn enums) es)+      (And es)   -> do+        es' <- mapM (check xOpt iw hdl syn enums) es+        pure $ if all (/=0) es'                        then 1                        else 0-      CmpLE e1 e2 -> if check xOpt iw hdl syn enums e1 <= check xOpt iw hdl syn enums e2-                        then 1-                        else 0+      CmpLE e1 e2 -> do+        v1 <- check xOpt iw hdl syn enums e1+        v2 <- check xOpt iw hdl syn enums e2+        if v1 <= v2+          then pure 1+          else pure 0       _ -> error $ $(curLoc) ++ "IF: condition must be: SIZE, LENGTH, LIT, DEPTH, IW64, VIVADO, OTHERSYN, ISVAR, ISLIT, ISUNDEFINED, ISACTIVEENABLE, ACTIVEEDGE, ISSYNC, ISINITDEFINED, ISACTIVEHIGH, STRCMP, AND, ISSCALAR or CMPLE."                              ++ "\nGot: " ++ show c' renderElem b e = fmap const (renderTag b e) +getDomainConf :: (Backend backend, HasCallStack) => HWType -> State backend VDomainConfiguration+getDomainConf = generalGetDomainConf domainConfigurations++generalGetDomainConf+  :: forall m. (Monad m, HasCallStack)+  => (m DomainMap) -- ^ a way to get the `DomainMap`+  -> HWType -> m VDomainConfiguration+generalGetDomainConf getDomainMap ty = case (snd . stripAttributes . stripVoid) ty of+  KnownDomain dom period activeEdge resetKind initBehavior resetPolarity ->+    pure $ VDomainConfiguration (Data.Text.unpack dom) (fromIntegral period) activeEdge resetKind initBehavior resetPolarity++  Clock dom -> go dom+  ClockN dom -> go dom+  Reset dom  -> go dom+  Enable dom -> go dom+  Product _DiffClock _ [Clock dom,_clkN] -> go dom+  t -> error $ "Don't know how to get a Domain out of HWType: " <> show t+ where+  go :: HasCallStack => N.DomainName -> m VDomainConfiguration+  go dom = do+    doms <- getDomainMap+    case HashMap.lookup dom doms of+      Nothing -> error $ "Can't find domain " <> show dom <> ". Please report an issue at https://github.com/clash-lang/clash-compiler/issues."+      Just conf -> pure conf+ parseFail :: Text -> BlackBoxTemplate parseFail t = case runParse t of   Failure errInfo ->@@ -690,6 +744,7 @@    mkLit (BlackBoxE pNm _ _ _ _ bbCtx _) | pNm `elem` ["GHC.Int.I8#", "GHC.Int.I16#", "GHC.Int.I32#", "GHC.Int.I64#"                                                      ,"GHC.Word.W8#","GHC.Word.W16#","GHC.Word.W32#","GHC.Word.W64#"+                                                     ,"GHC.Types.I#","GHC.Types.W#"                                                      ]                                         , [Literal _ i] <- extractLiterals bbCtx                                         = Literal Nothing i@@ -789,9 +844,19 @@ renderTag b (IncludeName n) = case indexMaybe (bbQsysIncName b) n of   Just nm -> return (Text.fromStrict nm)   _ -> error $ $(curLoc) ++ "~INCLUDENAME[" ++ show n ++ "] does not correspond to any index of the 'includes' field that is specified in the primitive definition"-renderTag b (OutputWireReg n) = case IntMap.lookup n (bbFunctions b) of-  Just ((_,rw,_,_,_,_):_) -> case rw of {N.Wire -> return "wire"; N.Reg -> return "reg"}-  _ -> error $ $(curLoc) ++ "~OUTPUTWIREREG[" ++ show n ++ "] used where argument " ++ show n ++ " is not a function"+renderTag b (OutputUsage n) = do+  hdl <- gets hdlKind++  let u = case IntMap.lookup n (bbFunctions b) of+            Just ((_,u',_,_,_,_):_) -> u'+            _ -> error $ $(curLoc) ++ "~OUTPUTUSAGE[" ++ show n ++ "] used where argument " ++ show n ++ " is not a function"++  pure $ case (hdl, u) of+    (VHDL, N.Proc N.Blocking) -> "variable"+    (VHDL, _) -> "signal"++    (_, N.Cont) -> "wire"+    (_, _) -> "reg" renderTag b (Repeat [es] [i]) = do   i'  <- Text.unpack <$> renderTag b i   es' <- renderTag b es@@ -1033,7 +1098,7 @@            (((string "~SIGD" <> brackets (string es')) <>) . int)            mI) prettyElem (Vars i) = renderOneLine <$> (string "~VARS" <> brackets (int i))-prettyElem (OutputWireReg i) = renderOneLine <$> (string "~RESULTWIREREG" <> brackets (int i))+prettyElem (OutputUsage n) = renderOneLine <$> (string "~OUTPUTUSAGE" <> brackets (int n)) prettyElem (ArgGen n x) =   renderOneLine <$> (string "~ARGN" <> brackets (int n) <> brackets (int x)) prettyElem (Template bbname source) = do@@ -1108,7 +1173,7 @@         IsActiveEnable _ -> []         IsUndefined _ -> []         StrCmp es _ -> concatMap go es-        OutputWireReg _ -> []+        OutputUsage _ -> []         Vars _ -> []         Repeat es1 es2 ->           concatMap go es1 ++ concatMap go es2@@ -1186,7 +1251,7 @@         IW64 -> Nothing         Length _ -> Nothing         MaxIndex _ -> Nothing-        OutputWireReg _ -> Nothing+        OutputUsage _ -> Nothing         Repeat _ _ -> Nothing         Result -> Nothing         Sel _ _ -> Nothing
+ src/Clash/Netlist/Expr.hs view
@@ -0,0 +1,172 @@+{-|+  Copyright  :  (C) 2012-2016, University of Twente,+                    2017     , Myrtle Software Ltd,+                    2017-2018, Google Inc.+                    2020-2022, QBayLogic B.V.+                    2022     , Google Inc.+  License    :  BSD2 (see the file LICENSE)+  Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>++  Functions for expression manipulation+-}++{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++module Clash.Netlist.Expr where++import Control.Monad (zipWithM)+import Control.Exception (assert)+import Data.Set (fromList, member)+import Data.Bits (Bits, testBit, setBit, zeroBits)+import Data.Foldable (fold)+import Data.Tree (Tree(..))+import GHC.Stack (HasCallStack)+import Data.Text (unpack)+import Language.Haskell.TH.Quote (dataToPatQ)++import qualified Clash.Sized.Vector as V (replicate)+import qualified Clash.Sized.Internal.Index as I (fromInteger#)+import qualified Clash.Sized.Internal.Signed as S (fromInteger#)+import qualified Clash.Sized.Internal.Unsigned as U (fromInteger#)+import qualified Clash.Sized.Internal.BitVector as BV+  (high, low, fromInteger#, fromInteger##)+import GHC.Int (Int8(I8#), Int16(I16#), Int32(I32#), Int64(I64#))+import GHC.Word (Word8(W8#), Word16(W16#), Word32(W32#), Word64(W64#))++import Clash.Primitives.DSL (tySize)+import Clash.Netlist.Types+  ( Size, Bit(..), Expr(..), HWType(..), Literal(..), Modifier(..)+  , BlackBoxContext(..)+  )++-- | Turns a constant expression of known bitsize into their+-- corresponding bitstream representation, arranged as a tree+-- that corresponds to the structure of the expression.+--+-- NOTE: This conversion serves as a best effort approach and can be+-- considered a hack. Fully featured constant expression evaluation is+-- not available in clash yet and will replace this implementation+-- once it is officially supported.+bits :: HasCallStack => Size -> Expr -> Either Expr (Tree [Bool])+bits size expr = case expr of+  Literal _ lit -> case lit of+    BitLit bLit   -> case bLit of+      H -> leaf [True]+      L -> leaf [False]+      _ -> Left expr+    BoolLit bLit      -> leaf [bLit]+    NumLit nLit       -> leaf $ toBits size nLit+    BitVecLit _ bvLit -> leaf $ toBits size bvLit+    VecLit lits       ->+      mapM (bits (size `div` length lits) . lit2Expr) lits >>= inner+    StringLit{}       -> Left expr+  DataCon ty m subs -> assert (tySize ty == size) $ case ty of+    Vector s t      -> vecBits (tySize t) s subs+    Product _ _ tys -> zipWithM bits (map tySize tys) subs >>= inner+    Sum _ cs        -> spBits expr size m subs $ map (const []) cs+    SP _ xs         -> spBits expr size m subs $ map (map tySize . snd) xs+    _               -> case subs of+      [e] -> bits size e+      []  -> leaf []+      _   -> Left expr+  -- appears in case of complex transformations, e.g.,+  -- >>> (bv2v 0b010) :: Vec 3 Bit+  -- >>> (iterate (SNat @3) not True) :: Vec 3 Bool+  -- >>> (complement <$> (True :> False :> Nil)) :: Vec 2 Bool+  Identifier{} -> Left expr+  DataTag{} -> Left expr+  BlackBoxE bbName _ _ _ _ bbCtx _ -> case unpack bbName of+    $(dataToPatQ (const Nothing) $ show 'BV.low) -> leaf [False]+    $(dataToPatQ (const Nothing) $ show 'BV.high) -> leaf [True]+    $(dataToPatQ (const Nothing) $ show 'V.replicate) -> case bbInputs bbCtx of+      [ (eSize, ty, _), (eValue, _, _) ] -> do+        bs <- bits (tySize ty) eSize+        let s = fromBits $ fold bs+        v <- bits (size `div` s) eValue+        inner $ replicate s v+      _ -> Left expr+    _ ->+      if unpack bbName `member` skippableBBs+      then skippableBBBits expr bbCtx size+      else Left expr+  ToBv _ _ e -> bits size e+  FromBv _ _ e -> bits size e+  IfThenElse cond match alt -> case bits 1 cond of+    Right (Node [True] [])  -> bits size match+    Right (Node [False] []) -> bits size alt+    _ -> Left expr+  Noop -> leaf []++ where+  -- known skippable blackboxes+  skippableBBs = fromList $ map show+    [ 'I.fromInteger#, 'S.fromInteger#, 'U.fromInteger#+    , 'BV.fromInteger#, 'BV.fromInteger##+    , 'I8#, 'I16#, 'I32#, 'I64#+    , 'W8#, 'W16#, 'W32#, 'W64#+    ]++  -- skips the blackbox conversion and obtains the constant result+  -- directly from the last input argument instead+  skippableBBBits e Context{..} n = case reverse bbInputs of+    (x, _, _) : _ -> bits n x+    _             -> Left e++  -- turns sum (& product) expressions into bitstreams (preserving the+  -- expressions' tree layout)+  spBits :: Expr -> Size -> Modifier -> [Expr] -> [[Size]]+         -> Either Expr (Tree [Bool])+  spBits e n m es sizes = case m of+    DC (_, i) -> do+      xs <- zipWithM bits (sizes !! i) es+      bs <- fold <$> inner xs+      l <- leaf $ toBits (n - length bs) i+      r <- leaf bs+      inner [ l, r ]+    _ -> Left e++  -- turns vector expressions into bitstream (preserving the+  -- expressions' tree layout)+  vecBits :: Size -> Int -> [Expr] -> Either Expr (Tree [Bool])+  vecBits elemSize elems = \case+    []   -> assert (elems == 0) $ leaf []+    x:xr -> assert (elems > 0) $ do+      (processedElems, cur) <- case x of+        DataCon t _ xs -> case t of+          Vector subElems (tySize -> subTySize) ->+            assert (subElems <= elems && subTySize == elemSize)+              ((subElems,) <$> vecBits elemSize subElems xs)+          _ -> (1,) <$> bits elemSize x+        _ -> (1,) <$> bits elemSize x+      sub <- vecBits elemSize (elems - processedElems) xr+      inner [cur, sub]++  -- creates a leaf node holding the leaf value+  leaf :: [a] -> Either b (Tree [a])+  leaf x = return $ Node x []++  -- creates an inner node (holding no value) with the given+  -- sub-trees+  inner :: [Tree [a]] -> Either b (Tree [a])+  inner = return . Node []++  -- turns a literal into an expression+  lit2Expr = Literal Nothing++-- | Turns values into bitstreams of known length. If the bit stream+-- requires more bits for representing the given value, then only the+-- suffix of the corresponding bitstream gets returned.+toBits :: Bits a => Int -> a -> [Bool]+toBits n x =+  map (testBit x) [n-1,n-2..0]++-- | Turns bitstreams into values.+fromBits :: Bits a => [Bool] -> a+fromBits xs =+  foldl setBit zeroBits $ map snd $ filter fst $ zip xs [n-1,n-2..0]+ where+  n = length xs
src/Clash/Netlist/Id.hs view
@@ -1,5 +1,6 @@ {-|   Copyright  :  (C) 2020, QBayLogic B.V.+                    2022, Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -8,7 +9,6 @@  {-# LANGUAGE CPP #-} {-# LANGUAGE MagicHash #-}-{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-}  module Clash.Netlist.Id@@ -24,6 +24,7 @@   , Identifier   , IdentifierType (..)   , unsafeMake+  , unsafeFromCoreId   , toText   , toLazyText   , toList@@ -54,7 +55,8 @@ where  import           Clash.Annotations.Primitive (HDL (..))-import           Clash.Core.Var (Id)+import           Clash.Core.Name (nameOcc)+import           Clash.Core.Var (Id, varName) import           Clash.Debug (debugIsOn) import           Clash.Netlist.Types   (PreserveCase(..), HasIdentifierSet(..), IdentifierSet(..), Identifier(..),@@ -116,13 +118,11 @@ toList :: IdentifierSet -> [Identifier] toList (IdentifierSet _ _ _ _ idStore) = HashSet.toList idStore --- | Convert an identifier to string. Use 'unmake' if you need the--- "IdentifierType" too.+-- | Convert an identifier to string toText :: Identifier -> Text toText = toText# --- | Convert an identifier to string. Use 'unmake' if you need the--- "IdentifierType" too.+-- | Convert an identifier to string toLazyText :: Identifier -> LT.Text toLazyText = LT.fromStrict . toText @@ -235,3 +235,10 @@ -- is unique. fromCoreId :: (HasCallStack, IdentifierSetMonad m) => Id -> m Identifier fromCoreId = withIdentifierSetM fromCoreId#++-- | Like 'fromCoreId, 'unsafeFromCoreId' creates an identifier that will be+-- spliced at verbatim in the HDL. As opposed to 'fromCoreId', the resulting+-- Identifier might be generated at a later point as it is NOT added to an+-- IdentifierSet.+unsafeFromCoreId :: HasCallStack => Id -> Identifier+unsafeFromCoreId = unsafeMake . nameOcc . varName
src/Clash/Netlist/Id/Common.hs view
@@ -95,7 +95,7 @@ maybeTuple :: Text -> Maybe (Text, Text) maybeTuple "(# #)" = Just ("Unit", "") maybeTuple "()" = Just ("Unit", "")-maybeTuple t = first (\n -> "Tup" <> showt n) <$> parseTuple t+maybeTuple t = first (\n -> "Tuple" <> showt n) <$> parseTuple t  parseTuple :: Text -> Maybe (Int, Text) parseTuple t0 = do
src/Clash/Netlist/Id/Internal.hs view
@@ -80,10 +80,12 @@  where   freshCache = updateFreshCache# (is_freshCache is) id2   isStore = HashSet.insert id2 (is_store is)-  id2 = id1{i_provenance=if debugIsOn then callStack else emptyCallStack}+  id2 = case id1 of+          x@RawIdentifier{} -> x+          y -> y{i_provenance=if debugIsOn then callStack else emptyCallStack}   id1 = case lookupFreshCache# (is_freshCache is) id0 of     Just currentMax ->-      id0{i_extensionsRev=currentMax+1 : tail (i_extensionsRev id0)}+      id0{i_extensionsRev=currentMax+1 : drop 1 (i_extensionsRev id0)}     Nothing ->       -- Identifier doesn't exist in set yet, so just return it.       id0
src/Clash/Netlist/Types.hs view
@@ -2,7 +2,8 @@   Copyright  :  (C) 2012-2016, University of Twente,                     2017     , Myrtle Software Ltd,                     2017-2018, Google Inc.-                    2020-2022, QBayLogic B.V.+                    2020-2023, QBayLogic B.V.+                    2022-2023, Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -38,6 +39,8 @@ import qualified Control.Monad.State        as Lazy (State) import qualified Control.Monad.State.Strict as Strict   (State, MonadIO, MonadState, StateT)+import Data.Aeson                           (FromJSON(..))+import qualified Data.Aeson as Aeson import Data.Bits                            (testBit) import Data.Binary                          (Binary(..)) import Data.Function                        (on)@@ -48,6 +51,7 @@ import Data.IntMap                          (IntMap, empty) import Data.Map.Ordered                     (OMap) import Data.Map                             (Map)+import qualified Data.Map as Map import Data.Maybe                           (mapMaybe) import Data.Monoid                          (Ap(..)) import qualified Data.Set                   as Set@@ -65,13 +69,14 @@ import SrcLoc                               (SrcSpan) #endif +import Clash.Annotations.SynthesisAttributes(Attr) import Clash.Annotations.BitRepresentation  (FieldAnn) import Clash.Annotations.Primitive          (HDL(..)) import Clash.Annotations.TopEntity          (TopEntity)-import Clash.Backend                        (Backend)+import Clash.Backend                        (Backend, HasUsageMap (..)) import Clash.Core.HasType import Clash.Core.Type                      (Type)-import Clash.Core.Var                       (Attr', Id)+import Clash.Core.Var                       (Id) import Clash.Core.TyCon                     (TyConMap) import Clash.Core.VarEnv                    (VarEnv) import Clash.Driver.Types                   (BindingMap, ClashEnv(..), ClashOpts(..))@@ -202,7 +207,7 @@ -- identifiers internally. Any Identifier should be trivially printable to any -- HDL. ----- __NB__: use the functions in Clash.Netlist.Id. Don't use these constructors+-- __NB__: use the functions in "Clash.Netlist.Id". Don't use these constructors -- directly. data Identifier   -- | Unparsed identifier. Used for things such as port names, which should@@ -283,6 +288,7 @@   { cmWereVoids :: [Bool]   , cmLoc :: SrcSpan   , cmScope :: IdentifierSet+  , cmUsage :: UsageMap   } deriving (Generic, Show, NFData)  type ComponentMap = OMap Unique (ComponentMeta, Component)@@ -338,6 +344,10 @@   , _backend :: SomeBackend   -- ^ The current HDL backend   , _htyCache :: HWMap+  , _usages :: UsageMap+  -- ^ The current way signals are assigned in netlist. This is used to+  -- determine how signals are rendered in HDL (i.e. wire/reg in Verilog, or+  -- signal/variable in VHDL).   }  data ComponentPrefix@@ -365,7 +375,7 @@   = Component   { componentName :: !Identifier -- ^ Name of the component   , inputs        :: [(Identifier,HWType)] -- ^ Input ports-  , outputs       :: [(WireOrReg,(Identifier,HWType),Maybe Expr)] -- ^ Output ports+  , outputs       :: [(Usage,(Identifier,HWType),Maybe Expr)] -- ^ Output ports   , declarations  :: [Declaration] -- ^ Internal declarations   }   deriving (Show, Generic, NFData)@@ -373,11 +383,16 @@ -- | Check if an input port is really an inout port. -- isBiDirectional :: (Identifier, HWType) -> Bool-isBiDirectional (_, BiDirectional _ _) = True-isBiDirectional _ = False+isBiDirectional = go . snd+  where+    go BiDirectional{} = True+    go (Annotated _ hwty) = go hwty+    go _ = False  -- | Find the name and domain name of each clock argument of a component. --+-- This will not consider @ClockN@ to be a clock argument, which means only the+-- positive phase of a differential pair will be added to @sdcClock@. findClocks :: Component -> [(Text, Text)] findClocks (Component _ is _ _) =   mapMaybe isClock is@@ -437,6 +452,8 @@   -- ^ Sum-of-Product type: Name and Constructor names + field types   | Clock !DomainName   -- ^ Clock type corresponding to domain /DomainName/+  | ClockN !DomainName+  -- ^ ClockN type corresponding to domain /DomainName/   | Reset !DomainName   -- ^ Reset type corresponding to domain /DomainName/   | Enable !DomainName@@ -452,7 +469,7 @@   | CustomProduct !Text !DataRepr' !Size (Maybe [Text]) [(FieldAnn, HWType)]   -- ^ Same as Product, but with a user specified bit representation. For more   -- info, see: Clash.Annotations.BitRepresentations.-  | Annotated [Attr'] !HWType+  | Annotated [Attr Text] !HWType   -- ^ Annotated with HDL attributes   | KnownDomain !DomainName !Integer !ActiveEdge !ResetKind !InitBehavior !ResetPolarity   -- ^ Domain name, period, active edge, reset kind, initial value behavior@@ -460,9 +477,17 @@   -- ^ File type for simulation-level I/O   deriving (Eq, Ord, Show, Generic, NFData, Hashable) +-- | Smart constructor for 'Annotated'. Wraps the given type in an 'Annotated'+-- if the attribute list is non-empty. If it is empty, it will return the given+-- 'HWType' unchanged.+annotated :: [Attr Text] -> HWType -> HWType+annotated [] t = t+annotated attrs t = Annotated attrs t+ hwTypeDomain :: HWType -> Maybe DomainName hwTypeDomain = \case   Clock dom -> Just dom+  ClockN dom -> Just dom   Reset dom -> Just dom   Enable dom -> Just dom   KnownDomain dom _ _ _ _ _ -> Just dom@@ -470,7 +495,7 @@  -- | Extract hardware attributes from Annotated. Returns an empty list if -- non-Annotated given or if Annotated has an empty list of attributes.-hwTypeAttrs :: HWType -> [Attr']+hwTypeAttrs :: HWType -> [Attr Text] hwTypeAttrs (Annotated attrs _type) = attrs hwTypeAttrs _                       = [] @@ -503,6 +528,7 @@   -- | Signal assignment   = Assignment       !Identifier -- ^ Signal to assign+      !Usage      -- ^ How the signal is assigned       !Expr       -- ^ Assigned expression    -- | Conditional signal assignment:@@ -517,7 +543,7 @@   | InstDecl       EntityOrComponent                  -- ^ Whether it's an entity or a component       (Maybe Text)                       -- ^ Library instance is defined in-      [Attr']                            -- ^ Attributes to add to the generated code+      [Attr Text]                        -- ^ Attributes to add to the generated code       !Identifier                        -- ^ The component's (or entity's) name       !Identifier                        -- ^ Instance label       [(Expr,HWType,Expr)]               -- ^ List of parameters for this component (param name, param type, param value)@@ -532,12 +558,19 @@       !BlackBox                -- ^ Template tokens       BlackBoxContext          -- ^ Context in which tokens should be rendered +  -- | @component@ declaration (VHDL).+  --+  -- See [this tutorial](https://www.ics.uci.edu/~jmoorkan/vhdlref/compdec.html);+  -- refer to §4.5 of IEEE 1076-1993+  | CompDecl+      !Text+      [(Text, PortDirection, HWType)]+   -- | Signal declaration   | NetDecl'       (Maybe Comment)                -- ^ Note; will be inserted as a comment in target hdl-      WireOrReg                      -- ^ Wire or register       !Identifier                    -- ^ Name of signal-      (Either IdentifierText HWType) -- ^ Pointer to type of signal or type of signal+      HWType                         -- ^ Type of signal       (Maybe Expr)                   -- ^ Initial value       -- ^ Signal declaration @@ -578,14 +611,111 @@       [(Maybe Literal,[Seq])]  -- ^ List of: (Maybe match, RHS of Alternative)   deriving Show -data EntityOrComponent = Entity | Comp | Empty-  deriving Show+-- | Procedural assignment in HDL can be blocking or non-blocking. This+-- determines when the assignment takes place in simulation. The name refers to+-- whether evaluation of the remaining statements in a process is blocked+-- until the assignment is performed or not.+--+-- See Also:+--+-- IEEE 1364-2001, sections 9.2.1 and 9.2.2+-- IEEE 1076-1993, sections 8.4 and 8.5+--+data Blocking+  = NonBlocking+  -- ^ A non-blocking assignment means the new value is not observed until the+  -- next time step in simulation. Using the signal later in the process will+  -- continue to return the old value.+  | Blocking+  -- ^ A blocking assignment means the new value is observed immediately. Using+  -- the signal later in the process will return the new value.+  deriving (Binary, Eq, Generic, Hashable, NFData, Show) -data WireOrReg = Wire | Reg-  deriving (Show,Generic)+-- NOTE [`Semigroup` instances for `Blocking` and `Usage`]+instance Semigroup Blocking where+  NonBlocking <> y = y+  Blocking    <> _ = Blocking -instance NFData WireOrReg+-- | The usage of a signal refers to how the signal is written to in netlist.+-- This is used to determine if the signal should be a @wire@ or @reg@ in+-- (System)Verilog, or a @signal@ or @variable@ in VHDL.+--+data Usage+  = Cont+  -- ^ Continuous assignment, which occurs in a concurrent context.+  | Proc Blocking+  -- ^ Procedural assignment, which occurs in a sequential context.+  deriving (Binary, Eq, Generic, Hashable, NFData, Show) +-- NOTE [`Semigroup` instances for `Blocking` and `Usage`]+instance Semigroup Usage where+  Cont    <> y      = y+  Proc x  <> Proc y = Proc (x <> y)+  Proc x  <> _      = Proc x++{-+NOTE [`Semigroup` instances for `Blocking` and `Usage`]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Usages (and Blocking) are combined by taking the most restrictive usage, where+most restrictive means "has the most influence over the choice of declaration".+Clash produces three types of assignment:++  * continuous+  * prodecural non-blocking+  * prodecural blocking++Both VHDl and (System)Verilog have a type of declaration which only admits one+type of assignment. This is the most restrictive for that HDL. However, since+that would involve knowing the HDL type in these Semigroup instances, the+most restrictive here is based on ordering where the most restrictive for each+HDL is an extreme value (max for VHDL, min for Verilog). i.e.++          |-------------------------------------|+          | Continuous | NonBlocking | Blocking |+|---------|-------------------------------------|+|    VHDL |         signal           | variable |+|---------|-------------------------------------|+| Verilog |   wire     |          reg           |+|---------|-------------------------------------|+-}++instance FromJSON Usage where+  parseJSON = Aeson.withText "Usage" $ \case+    "Continuous"  -> pure Cont+    "NonBlocking" -> pure (Proc NonBlocking)+    "Blocking"    -> pure (Proc Blocking)+    str           -> fail $ mconcat+      [ "Could not parse usage: "+      , show str+      , "\nRecognized values are 'Continuous', 'NonBlocking' and 'Blocking'"+      ]++-- See NOTE [`Text` key for `UsageMap`]+type UsageMap = Map Text Usage++lookupUsage :: Identifier -> UsageMap -> Maybe Usage+lookupUsage i = Map.lookup (Id.toText i)++{-+NOTE [`Text` key for `UsageMap`]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We would like to use netlist identifiers as the key for the usage map, since+conceptually it is a map from an identifier to how it is used in assignments.+However, in practice we commonly end up with the same textual identifier+appearing in different ways in the netlist.++The most obvious example of this are identifiers that appear as both+`UniqueIdentifier` and `RawIdentifier`. If we track the usage on the raw+identifier, but the `NetDecl` uses the `UniqueIdentifier` then the wrong+declaration may be used in the rendered HDL.++Attempting to fix this by not generating the same textual identifier in+different ways proved difficult, so for now the key type is `Text` instead.+-}++data EntityOrComponent = Entity | Comp | Empty+  deriving Show+ pattern NetDecl   :: Maybe Comment   -- ^ Note; will be inserted as a comment in target hdl@@ -594,9 +724,9 @@   -> HWType   -- ^ Type of signal   -> Declaration-pattern NetDecl note d ty <- NetDecl' note Wire d (Right ty) _+pattern NetDecl note d ty <- NetDecl' note d ty _   where-    NetDecl note d ty = NetDecl' note Wire d (Right ty) Nothing+    NetDecl note d ty = NetDecl' note d ty Nothing  data PortDirection = In | Out   deriving (Eq,Ord,Show,Generic,NFData,Hashable)@@ -606,11 +736,18 @@  -- | Expression Modifier data Modifier-  = Indexed (HWType,Int,Int) -- ^ Index the expression: (Type of expression,DataCon tag,Field Tag)-  | DC (HWType,Int)          -- ^ See expression in a DataCon context: (Type of the expression, DataCon tag)-  | VecAppend                -- ^ See the expression in the context of a Vector append operation-  | RTreeAppend              -- ^ See the expression in the context of a Tree append operation-  | Sliced (HWType,Int,Int)  -- ^ Slice the identifier of the given type from start to end+  = Indexed (HWType, Int, Int)+  -- ^ Index the expression: (Type of expression, DataCon tag, Field Tag). Note+  -- that the type of the expression is the type we are slicing from, not the type+  -- returned by the index operation.+  | DC (HWType, Int)+  -- ^ See expression in a DataCon context: (Type of the expression, DataCon tag)+  | VecAppend+  -- ^ See the expression in the context of a Vector append operation+  | RTreeAppend+  -- ^ See the expression in the context of a Tree append operation+  | Sliced (HWType, Int, Int)+  -- ^ Slice the identifier of the given type from start to end   | Nested Modifier Modifier   deriving Show @@ -651,6 +788,24 @@ instance NFData Expr where   rnf x = x `seq` () +isConstExpr :: Expr -> Bool+isConstExpr = \case+  Literal{} -> True+  DataCon _ _ es -> all isConstExpr es+  Identifier{} -> False+  DataTag{} -> False+  BlackBoxE nm _ _ _ _ ctx _+    -- When using SimIO, `reg` creates (in Haskell) the mutable reference to+    -- some value. The blackbox for this however is simply `~ARG[0]`, so if+    -- the argument given is constant, the rendered HDL will also be constant.+    | nm == "Clash.Explicit.SimIO.reg" ->+        all (\(e, _, _) -> isConstExpr e) (bbInputs ctx)+    | otherwise -> False+  ToBv _ _ e -> isConstExpr e+  FromBv _ _ e -> isConstExpr e+  IfThenElse{} -> False+  Noop -> False+ -- | Literals used in an expression data Literal   = NumLit    !Integer          -- ^ Number literal@@ -689,7 +844,7 @@   , bbInputs :: [(Expr,HWType,Bool)]   -- ^ Argument names, types, and whether it is a literal   , bbFunctions :: IntMap [(Either BlackBox (Identifier,[Declaration])-                          ,WireOrReg+                          ,Usage                           ,[BlackBoxTemplate]                           ,[BlackBoxTemplate]                           ,[((Text,Text),BlackBox)]@@ -758,7 +913,7 @@   | MultiId [Id]   -- ^ A split identifier (into several sub-identifiers), needed to assign   -- expressions of types that have to be split apart (e.g. tuples of Files)-  deriving Show+  deriving (Eq, Show)  -- | Eliminator for 'NetlistId', fails on 'MultiId' netlistId1@@ -838,6 +993,12 @@  instance HasIdentifierSet IdentifierSet where   identifierSet = ($)++instance HasUsageMap NetlistState where+  usageMap = usages++instance HasIdentifierSet s => HasIdentifierSet (s, a) where+  identifierSet = Lens._1 . identifierSet  -- | An "IdentifierSetMonad" supports unique name generation for Clash Netlist class Monad m => IdentifierSetMonad m where
src/Clash/Netlist/Types.hs-boot view
@@ -1,6 +1,7 @@ {-|   Copyright   :  (C) 2018, Google Inc,                      2022, QBayLogic B.V.+                     2022, Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> -}@@ -11,7 +12,11 @@  import Control.DeepSeq (NFData) import Control.Lens (Lens')-import Data.Hashable+import Data.Aeson (FromJSON)+import Data.Binary (Binary)+import Data.Hashable (Hashable)+import Data.Map (Map)+import Data.Text (Text)  data IdentifierType data Identifier@@ -38,3 +43,26 @@ instance Eq PreserveCase instance Show PreserveCase instance NFData PreserveCase++data Blocking+  = NonBlocking+  | Blocking++instance Binary Blocking+instance Eq Blocking+instance Hashable Blocking+instance NFData Blocking+instance Show Blocking++data Usage+  = Cont+  | Proc Blocking++instance Binary Usage+instance Eq Usage+instance FromJSON Usage+instance Hashable Usage+instance NFData Usage+instance Show Usage++type UsageMap = Map Text Usage
src/Clash/Netlist/Util.hs view
@@ -2,7 +2,8 @@   Copyright  :  (C) 2012-2016, University of Twente,                     2017     , Myrtle Software Ltd                     2017-2018, Google Inc.-                    2021-2022, QBayLogic B.V.+                    2021-2023, QBayLogic B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -11,6 +12,7 @@  {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MagicHash #-} #if !MIN_VERSION_ghc(8,8,0) {-# LANGUAGE MonadFailDesugaring #-}@@ -26,7 +28,7 @@  import           Data.Coerce             (coerce) import           Control.Exception       (throw)-import           Control.Lens            ((.=))+import           Control.Lens            ((.=), (%=)) import qualified Control.Lens            as Lens import           Control.Monad           (when, zipWithM) import           Control.Monad.Extra     (concatMapM)@@ -39,6 +41,7 @@ import           Data.Bifunctor          (second) import           Data.Either             (partitionEithers) import           Data.Foldable           (Foldable(toList))+import           Data.Functor            (($>)) import           Data.Hashable           (Hashable) import           Data.HashMap.Strict     (HashMap) import qualified Data.HashMap.Strict     as HashMap@@ -73,7 +76,9 @@ import           Clash.Annotations.BitRepresentation.Internal   (CustomReprs, ConstrRepr'(..), DataRepr'(..), getDataRepr,    uncheckedGetConstrRepr)-import           Clash.Backend           (HWKind(..), hdlHWTypeKind)+import           Clash.Annotations.SynthesisAttributes (Attr)+import           Clash.Annotations.Primitive (HDL(VHDL))+import           Clash.Backend           (HasUsageMap (..), HWKind(..), hdlHWTypeKind, hdlKind) import           Clash.Core.DataCon      (DataCon (..)) import           Clash.Core.EqSolver     (typeEq) import           Clash.Core.FreeVars     (typeFreeVars, typeFreeVars')@@ -97,9 +102,10 @@ import           Clash.Core.Util   (substArgTys, tyLitShow) import           Clash.Core.Var-  (Id, Var (..), mkLocalId, modifyVarName, Attr')+  (Id, Var (..), mkLocalId, modifyVarName) import           Clash.Core.VarEnv   (InScopeSet, extendInScopeSetList, uniqAway, lookupVarEnv)+import qualified Clash.Data.UniqMap as UniqMap import {-# SOURCE #-} Clash.Netlist.BlackBox import {-# SOURCE #-} Clash.Netlist.BlackBox.Util import           Clash.Netlist.BlackBox.Types@@ -107,7 +113,6 @@ import qualified Clash.Netlist.Id as Id import           Clash.Netlist.Types     as HW import           Clash.Primitives.Types-import           Clash.Unique import           Clash.Util import qualified Clash.Util.Interpolate  as I @@ -432,7 +437,7 @@   | isRecursiveTy m tc   = throwE $ $(curLoc) ++ "Can't translate recursive type: " ++ tyString -mkADT builtInTranslation reprs m tyString tc args = case tyConDataCons (m `lookupUniqMap'` tc) of+mkADT builtInTranslation reprs m tyString tc args = case tyConDataCons (UniqMap.find tc m) of   []  -> return (FilteredHWType (Void Nothing) [])   dcs -> do     let tcName           = nameOcc tc@@ -576,7 +581,7 @@               Bool             isGenerative t efvs = case tyView t of               TyConApp tcNm _-                | Just (FunTyCon {}) <- lookupUniqMap tcNm tcm+                | Just (FunTyCon {}) <- UniqMap.lookup tcNm tcm                 -- For type families we can only "calculate" the `eTV` if it is                 -- the only free variable. e.g. we can work out from `n + 1 ~ 4`                 -- that `n ~ 3`, but can't do anything for `n + m ~ 4`.@@ -626,7 +631,7 @@ -- Without looking through type families, we would think that /SList/ is not -- recursive. This lead to issue #1921 isRecursiveTy :: TyConMap -> TyConName -> Bool-isRecursiveTy m tc = case tyConDataCons (m `lookupUniqMap'` tc) of+isRecursiveTy m tc = case tyConDataCons (UniqMap.find tc m) of     []  -> False     dcs -> let argTyss   = map dcArgTys dcs                argTycons = (map fst . catMaybes)@@ -674,6 +679,7 @@ typeSize Bool = 1 typeSize Bit = 1 typeSize (Clock _) = 1+typeSize (ClockN _) = 1 typeSize (Reset _) = 1 typeSize (Enable _) = 1 typeSize (BitVector i) = i@@ -725,10 +731,12 @@  isBiSignalIn :: HWType -> Bool isBiSignalIn (BiDirectional In _) = True+isBiSignalIn (Annotated _ ty)     = isBiSignalIn ty isBiSignalIn _                    = False  isBiSignalOut :: HWType -> Bool isBiSignalOut (BiDirectional Out _) = True+isBiSignalOut (Annotated _ ty)      = isBiSignalOut ty isBiSignalOut _                     = False  containsBiSignalIn@@ -739,6 +747,7 @@ containsBiSignalIn (SP _ tyss)       = any (any containsBiSignalIn . snd) tyss containsBiSignalIn (Vector _ ty)     = containsBiSignalIn ty containsBiSignalIn (RTree _ ty)      = containsBiSignalIn ty+containsBiSignalIn (Annotated _ ty)  = containsBiSignalIn ty containsBiSignalIn _                 = False  -- | Uniquely rename all the variables and their references in a normalized@@ -785,7 +794,6 @@   resM <- mkUniqueResult substArgs etopM res   case resM of     Just (oports, owrappers, res1, subst0) -> do-       -- Collect new names, see 'renameBinder' for more information       (listToMaybe -> resRenameM0, HashMap.fromList -> renames0) <-         partition ((== res) . fst) <$> concatMapM renameBinder binds@@ -814,7 +822,11 @@       let         -- Result binder is already unique, so don't rename that         renames1 = [(b, hmFindWithDefault b b renames0) | b <- bndrs]-        (renamesL0, (_:renamesR0)) = break ((==res) . fst) renames1+        (renamesL0, renamesR0) = case break ((==res) . fst) renames1 of+          (ls,_:rs) -> (ls,rs)+          _ -> error (concat [ "internal error: unable to find: "+                             , show res , " in: "+                             , show renames1 ])        (renamesL1, subst2) <- mkUnique subst1 (map snd renamesL0)       (renamesR1, subst3) <- mkUnique subst2 (map snd renamesR0)@@ -997,10 +1009,7 @@   hwTy <- unsafeCoreTypeToHWTypeM' $(curLoc) (coreTypeOf var)   if isVoid hwTy     then return Nothing-    else return (Just (id2identifier var, hwTy))--id2identifier :: Id -> Identifier-id2identifier = Id.unsafeMake . nameOcc . varName+    else return (Just (Id.unsafeFromCoreId var, hwTy))  setRepName :: Text -> Name a -> Name a setRepName s (Name sort' _ i loc) = Name sort' s i loc@@ -1037,7 +1046,7 @@   State.put state   pure val --- | Preserve the Netlist '_curCompNm','_seenIds' when executing+-- | Preserve the Netlist '_curCompNm','_seenIds','_usageMap' when executing -- a monadic action preserveVarEnv   :: NetlistMonad a@@ -1046,11 +1055,13 @@   -- store state   vComp <- Lens.use curCompNm   vSeen <- Lens.use seenIds+  vUses <- Lens.use usageMap   -- perform action   val <- action   -- restore state   curCompNm .= vComp   seenIds   .= vSeen+  usageMap  .= vUses   return val  dcToLiteral :: HWType -> Int -> Literal@@ -1070,9 +1081,214 @@ prefixParent parent (PortProduct "" ps) = PortProduct parent ps prefixParent parent (PortProduct p ps)  = PortProduct (parent <> "_" <> p) ps -mkAssign :: Identifier -> HWType -> Expr -> [Declaration]-mkAssign id_ hwty expr = [NetDecl Nothing id_ hwty, Assignment id_ expr]+-- | Make a new signal which is assigned with an initial value. This should be+-- used in place of NetDecl directly, as it also updates the usage map to+-- include the new identifier and usage.+--+mkInit+  :: HasCallStack+  => DeclarationType+  -- ^ Are we in a concurrent or sequential context?+  -> Usage+  -- ^ How is the initial value assigned if the assignment is separate+  -> Identifier+  -- ^ The identifier of the declared net+  -> HWType+  -- ^ The typr of the declared net+  -> Expr+  -- ^ The value assigned to the net+  -> NetlistMonad [Declaration]+  -- ^ The declarations needed to declare and assign the net+mkInit _ _ i ty e+  -- When the initial value is a constant, we can set the value at the same+  -- point the declaration happens. Initial assignments of this form do not+  -- count as a usage as they are always allowed.+  | isConstExpr e+  = pure [NetDecl' Nothing i ty (Just e)] +mkInit Concurrent Cont i ty e = do+  usageMap %= Map.insert (Id.toText i) Cont+  pure [NetDecl' Nothing i ty Nothing, Assignment i Cont e]++mkInit Concurrent proc i ty e = do+  usageMap %= Map.insert (Id.toText i) proc+  pure+    [ NetDecl' Nothing i ty Nothing+    , Seq [Initial [SeqDecl (Assignment i proc e)]]+    ]++mkInit Sequential Cont _ _ _ =+  error "mkInit: Cannot continuously assign in a sequential block"++mkInit Sequential proc i ty e = do+  usageMap %= Map.insert (Id.toText i) proc+  pure+    [ NetDecl' Nothing i ty Nothing+    , Seq [SeqDecl (Assignment i proc e)]+    ]++-- | Determine if for the specified HDL, the type of assignment wanted can be+-- performed on a signal which has been assigned another way. This identifies+-- when a new intermediary signal needs to be created, e.g.+--+--   * when attempting to use blocking and non-blocking procedural assignment+--     on the same signal in VHDL+--+--   * when attempting to use continuous and procedural assignment on the same+--     signal in (System)Verilog+--+canUse :: HDL -> Usage -> Usage -> Bool+canUse VHDL (Proc Blocking) = \case+  Proc Blocking -> True+  _ -> False++canUse VHDL _ = \case+  Proc Blocking -> False+  _ -> True++canUse _ Cont = \case+  Cont -> True+  _ -> False++canUse _ _ = \case+  Cont -> False+  _ -> True++declareUse :: Usage -> Identifier -> NetlistMonad ()+declareUse u i = usageMap %= Map.insertWith (<>) (Id.toText i) u++-- | Like 'declareUse', but will throw an exception if we run into a name+-- collision.+declareUseOnce :: HasUsageMap s => Usage -> Identifier -> State.State s ()+declareUseOnce u i = usageMap %= Map.alter go (Id.toText i)+ where+  go Nothing = Just u+  go Just{}  = error ("Internal error: unexpected re-declaration of usage for" ++ show i)++-- | Declare uses which occur as a result of a component being instantiated,+-- for example the following design (verilog)+--+--    @+--    module f ( input p; output reg r ) ... endmodule+--+--    module top ( ... )+--      ...+--      f f_inst ( .p(p), .r(foo));+--      ...+--    endmodule+--    @+--+-- would declare a usage of foo, since it is assigned by @f_inst@.+--+declareInstUses+  :: [(Expr, PortDirection, HWType, Expr)]+  -- ^ The port mappings (named)+  -> NetlistMonad ()+declareInstUses =+  mapM_ declare+ where+  -- Modifiers don't matter for these identifiers+  declare (Identifier _ _, Out, _, Identifier n _) =+    -- See NOTE [output ports are continuously assigned]+    declareUse Cont n++  declare (_, In, _, _) =+    pure ()++  declare portMapping =+    error ("declareInstUses: Unexpected port mapping: " <> show portMapping)++{-+NOTE [output ports are continuously assigned]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When a module is instantiated in Verilog, the output of the module is always+continuously assigned. This means if I have the module++  module f ( ..., output reg result)++and an instantiation++  f f_inst ( ..., .result(foo) );++then the assignment of result to foo is a continuous assignment. This may seem+strange, but consider++  * instantiations can only occur in a concurrent context, and concurrent+    contexts only admit continuous assignment++  * the usage being tracked is not for the result port, but for foo. Whenever+    the value of the port changes, the value of foo will change (i.e. there is+    a wire between them, it cannot "hold" state).++This means when we declare uses that occur as a result of an instantiation in+netlist, the uses are always continuous assignment, and not the usage of the+output port as given in the `outputs` field of the `Component` type.+-}++assignmentWith+  :: HasCallStack+  => (Identifier -> Declaration)+  -> Usage+  -> Identifier+  -> NetlistMonad Declaration+assignmentWith assign new i = do+  u <- Lens.use usageMap+  SomeBackend b <- Lens.use backend++  case lookupUsage i u of+    Just old | not $ canUse (hdlKind b) new old ->+      error $ mconcat+        [ "assignmentWith: Cannot assign as "+        , show new+        , " after "+        , show old+        , " for "+        , show i+        ]++    _ ->+      declareUse new i $> assign i++-- | Attempt to continuously assign an expression to the given identifier. If+-- the assignment is not allowed for the backend being used, a new signal is+-- created which allows the assignment. The identifier which holds the result+-- of the assignment is returned alongside the new declarations.+--+-- This function assumes the identifier being assigned is already declared. If+-- the identifier is not in the usage map then an error is thrown.+--+contAssign+  :: HasCallStack+  => Identifier+  -> Expr+  -> NetlistMonad Declaration+contAssign dst expr =+  assignmentWith (\i -> Assignment i Cont expr) Cont dst++procAssign+  :: HasCallStack+  => Blocking+  -> Identifier+  -> Expr+  -> NetlistMonad Declaration+procAssign block dst expr =+  assignmentWith (\i -> Assignment i (Proc block) expr) (Proc block) dst++condAssign+  :: Identifier+  -> HWType+  -> Expr+  -> HWType+  -> [(Maybe Literal, Expr)]+  -> NetlistMonad Declaration+condAssign dst dstTy scrut scrutTy alts = do+  -- Currently, all CondAssignment get rendered as `always @*` blocks in+  -- (System)Verilog. This means when we target these HDL, this is _really_ a+  -- blocking procedural assignment.+  SomeBackend b <- Lens.use backend+  let use = case hdlKind b of { VHDL -> Cont ; _ -> Proc Blocking }+  assignmentWith (\i -> CondAssignment i dstTy scrut scrutTy alts) use dst+ -- | See 'toPrimitiveType' / 'fromPrimitiveType' convPrimitiveType :: HWType -> a -> NetlistMonad a -> NetlistMonad a convPrimitiveType hwty a action = do@@ -1094,7 +1310,8 @@   -> NetlistMonad ([Declaration], Identifier, Expr, HWType) toPrimitiveType id0 hwty0 = convPrimitiveType hwty0 dflt $ do   id1 <- Id.next id0-  pure (mkAssign id1 hwty1 expr, id1, expr, hwty1)+  ds  <- mkInit Concurrent Cont id1 hwty1 expr+  pure (ds, id1, expr, hwty1)  where   dflt = ([], id0, Identifier id0 Nothing, hwty0)   hwty1 = BitVector (typeSize hwty0)@@ -1111,7 +1328,8 @@   -> NetlistMonad ([Declaration], Identifier, Expr, HWType) fromPrimitiveType id0 hwty0 = convPrimitiveType hwty0 dflt $ do   id1 <- Id.next id0-  pure (mkAssign id1 hwty0 expr, id1, expr, hwty1)+  ds <- mkInit Concurrent Cont id1 hwty0 expr+  pure (ds, id1, expr, hwty1)  where   dflt = ([], id0, Identifier id0 Nothing, hwty0)   hwty1 = BitVector (typeSize hwty0)@@ -1130,32 +1348,29 @@  mkTopInput epp@(ExpandedPortProduct p hwty ps) = do   pN <- Id.makeBasic p-  let netdecl = NetDecl Nothing pN hwty   case hwty of     Vector sz eHwty -> do       (ports, _, exprs, _) <- unzip4 <$> mapM mkTopInput ps       let vecExpr  = mkVectorChain sz eHwty exprs-          netassgn = Assignment pN vecExpr-      return (concat ports, [netdecl, netassgn], vecExpr, pN)+      decls <- mkInit Concurrent Cont pN hwty vecExpr+      return (concat ports, decls, vecExpr, pN)      RTree d eHwty -> do       (ports, _, exprs, _) <- unzip4 <$> mapM mkTopInput ps       let trExpr   = mkRTreeChain d eHwty exprs-          netassgn = Assignment pN trExpr-      return (concat ports, [netdecl, netassgn], trExpr, pN)+      decls <- mkInit Concurrent Cont pN hwty trExpr+      return (concat ports, decls, trExpr, pN)      Product _ _ _ -> do       (ports, _, exprs, _) <- unzip4 <$> mapM mkTopInput ps       case exprs of-        [expr] ->-          let netassgn = Assignment pN expr in-          return (concat ports, [netdecl, netassgn], expr, pN)-        _ ->-          let-            dcExpr   = DataCon hwty (DC (hwty, 0)) exprs-            netassgn = Assignment pN dcExpr-          in-            return (concat ports, [netdecl, netassgn], dcExpr, pN)+        [expr] -> do+          decls <- mkInit Concurrent Cont pN hwty expr+          return (concat ports, decls, expr, pN)+        _ -> do+          let dcExpr = DataCon hwty (DC (hwty, 0)) exprs+          decls <- mkInit Concurrent Cont pN hwty dcExpr+          return (concat ports, decls, dcExpr, pN)      SP _ ((concat . map snd) -> [elTy]) -> do       (ports, _, exprs, _) <- unzip4 <$> mapM mkTopInput ps@@ -1163,8 +1378,8 @@         [conExpr, elExpr] -> do           let dcExpr   = DataCon hwty (DC (BitVector (typeSize hwty), 0))                           [conExpr, ToBv Nothing elTy elExpr]-              netassgn = Assignment pN dcExpr-          return (concat ports, [netdecl, netassgn], dcExpr, pN)+          decls <- mkInit Concurrent Cont pN hwty dcExpr+          return (concat ports, decls, dcExpr, pN)         _ -> error $ $(curLoc) ++ "Internal error"      _ ->@@ -1247,7 +1462,7 @@ -- non-Annotated. Accumulates all attributes of nested annotations. stripAttributes   :: HWType-  -> ([Attr'], HWType)+  -> ([Attr Text], HWType) -- Recursively strip type, accumulate attrs: stripAttributes (Annotated attrs typ) =   let (attrs', typ') = stripAttributes typ@@ -1267,60 +1482,63 @@     -- No type conversion happened, so we can just request caller to assign to     -- port name directly.     return ([(i0, hwty0)], [], i0)-  else+  else do     -- Type conversion happened, so we must use intermediate variable.-    return ([(i0, hwty1)], [Assignment i0 bvExpr, NetDecl Nothing i1 hwty0], i1)+    assn <- contAssign i0 bvExpr+    pure ( [(i0, hwty1)], [NetDecl' Nothing i1 hwty0 Nothing, assn], i1)  mkTopOutput epp@(ExpandedPortProduct p hwty ps) = do   pN <- Id.makeBasic p-  let netdecl = NetDecl Nothing pN hwty+  let netdecl = NetDecl' Nothing pN hwty Nothing   case hwty of     Vector {} -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopOutput ps-      let assigns = zipWith (assignId pN hwty 10) ids [0..]-      return (concat ports, netdecl:assigns ++ concat decls, pN)+      assigns <- zipWithM (\i n -> assignId pN hwty 10 i n) ids [0..]+      return (concat ports, netdecl : assigns ++ concat decls, pN)      RTree {} -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopOutput ps-      let assigns = zipWith (assignId pN hwty 10) ids [0..]-      return (concat ports, netdecl:assigns ++ concat decls, pN)+      assigns <- zipWithM (\i n -> assignId pN hwty 10 i n) ids [0..]+      return (concat ports, netdecl : assigns ++ concat decls, pN)      Product {} -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopOutput ps       case ids of-        [i] -> let assign  = Assignment i (Identifier pN Nothing)-               in  return (concat ports, netdecl:assign:concat decls, pN)+        [i] -> do+          assn <- contAssign i (Identifier pN Nothing)+          pure (concat ports, netdecl : assn : concat decls, pN) -        _   -> let assigns = zipWith (assignId pN hwty 0) ids [0..]-               in return (concat ports, netdecl:assigns ++ concat decls, pN)+        _   -> do+          assigns <- zipWithM (\i n -> assignId pN hwty 0 i n) ids [0..]+          pure (concat ports, netdecl : assigns ++ concat decls, pN)      SP _ ((concat . map snd) -> [elTy]) -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopOutput ps       case ids of-        [conId, elId] ->+        [conId, elId] -> do           let conIx   = Sliced ( BitVector (typeSize hwty)                                , typeSize hwty - 1                                , typeSize elTy )               elIx    = Sliced ( BitVector (typeSize hwty)                                , typeSize elTy - 1                                , 0 )-              assigns = [ Assignment conId (Identifier pN (Just conIx))-                        , Assignment elId  (FromBv Nothing elTy-                                            (Identifier pN (Just elIx)))-                        ]-          in  return (concat ports, netdecl:assigns ++ concat decls, pN)++          conAssgn <- contAssign conId (Identifier pN (Just conIx))+          elAssgn <- contAssign elId (FromBv Nothing elTy (Identifier pN (Just elIx)))++          pure (concat ports, netdecl:conAssgn:elAssgn:concat decls, pN)         _ -> error $ $(curLoc) ++ "Internal error"     -- 'expandTopEntity' should have made sure this isn't possible     _ -> error $ $(curLoc) ++ "Internal error: " ++ show epp   where   assignId p_ hwty_ con i n =-    Assignment i (Identifier p_ (Just (Indexed (hwty_, con, n))))+    contAssign i (Identifier p_ (Just (Indexed (hwty_, con, n))))  mkTopCompDecl   :: Maybe Text   -- ^ Library entity is defined in-  -> [Attr']+  -> [Attr Text]   -- ^ Attributes to add to generate code   -> Identifier   -- ^ The component's (or entity's) name@@ -1366,11 +1584,11 @@    -- inputs   (iports, wrappers, idsI) <- unzip3 <$> mapM mkTopInstInput (catMaybes (et_inputs annM))-  let inpAssigns = zipWith Assignment idsI (map fst args)+  inpAssigns <- zipWithM (\i e -> contAssign i e) idsI (fst <$> args)    -- output   let-    iResult = inpAssigns ++ concat wrappers+    iResult = inpAssigns : wrappers     instLabel0 = Text.concat [topName, "_", Id.toText (fst dstId)]    instLabel1 <- fromMaybe instLabel0 <$> Lens.view setName@@ -1382,10 +1600,10 @@    case topOutputM of     Nothing ->-      pure (topDecl [] : iResult)+      pure (topDecl [] : concat iResult)     Just (oports, unwrappers, id0) -> do-      let outpAssign = Assignment (fst dstId) (Identifier id0 Nothing)-      pure (iResult ++ tickDecls ++ (topDecl oports:unwrappers) ++ [outpAssign])+      outpAssign <- contAssign (fst dstId) (Identifier id0 Nothing)+      pure (concat iResult ++ tickDecls ++ (topDecl oports:unwrappers) ++ [outpAssign])  data InstancePort = InstancePort   { ip_id :: Identifier@@ -1393,7 +1611,7 @@   -- arguments, so this doesn't hold a port name.   , ip_type :: HWType   -- ^ Type assigned to port-  }+  } deriving Show  -- | Generate input port(s) associated with a single argument for an -- instantiation of a top entity. This function composes the input ports into@@ -1407,21 +1625,21 @@   pN' <- Id.next pN   (decls, pN'', _bvExpr, hwty1) <- toPrimitiveType pN' hwty0   return ( [InstancePort pN'' hwty1]-          , NetDecl Nothing pN' hwty0 : decls+          , NetDecl' Nothing pN' hwty0 Nothing : decls           , pN' )  mkTopInstInput epp@(ExpandedPortProduct pNameHint hwty0 ps) = do   pName <- Id.makeBasic pNameHint+  let pDecl = NetDecl' Nothing pName hwty0 Nothing    let-    pDecl = NetDecl Nothing pName hwty0     (attrs, hwty1) = stripAttributes hwty0     indexPN constr n = Identifier pName (Just (Indexed (hwty0, constr, n)))    case hwty1 of     Vector {} -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopInstInput ps-      let assigns = zipWith Assignment ids (map (indexPN 10) [0..])+      let assigns = zipWith3 Assignment ids (repeat Cont) (map (indexPN 10) [0..])       if null attrs then         return (concat ports, pDecl:assigns ++ concat decls, pName)       else@@ -1429,7 +1647,7 @@      RTree {} -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopInstInput ps-      let assigns = zipWith Assignment ids (map (indexPN 10) [0..])+      let assigns = zipWith3 Assignment ids (repeat Cont) (map (indexPN 10) [0..])       if null attrs then         return (concat ports, pDecl:assigns ++ concat decls, pName)       else@@ -1437,7 +1655,7 @@      Product {} -> do       (ports, decls, ids) <- unzip3 <$> mapM mkTopInstInput ps-      let assigns = zipWith Assignment ids (map (indexPN 0) [0..])+      let assigns = zipWith3 Assignment ids (repeat Cont) (map (indexPN 0) [0..])       if null attrs then         return (concat ports, pDecl:assigns ++ concat decls, pName)       else@@ -1459,8 +1677,8 @@               , 0 )              assigns =-              [ Assignment conId (Identifier pName (Just conIx))-              , Assignment elId  (FromBv Nothing elTy (Identifier pName (Just elIx))) ]+              [ Assignment conId Cont (Identifier pName (Just conIx))+              , Assignment elId  Cont (FromBv Nothing elTy (Identifier pName (Just elIx))) ]            return (concat ports, pDecl:assigns ++ concat decls, pName)         _ -> error "Internal error: Unexpected error for PortProduct"@@ -1503,19 +1721,18 @@ mkTopInstOutput (ExpandedPortName hwty0 portName) = do   assignName0 <- Id.next portName   (decls, assignName1, _expr, hwty1) <- fromPrimitiveType assignName0 hwty0-  return ( [InstancePort assignName0 hwty1]-          , NetDecl Nothing assignName0 hwty1 : decls-          , assignName1 )+  let net = NetDecl' Nothing assignName0 hwty1 Nothing+  return ([InstancePort assignName0 hwty1], net : decls, assignName1)  mkTopInstOutput epp@(ExpandedPortProduct productNameHint hwty ps) = do   pName <- Id.makeBasic productNameHint-  let pDecl = NetDecl Nothing pName hwty-      (attrs, hwty') = stripAttributes hwty+  let pDecl = NetDecl' Nothing pName hwty Nothing+  let (attrs, hwty') = stripAttributes hwty   case hwty' of     Vector sz hwty'' -> do       (ports, decls, ids0) <- unzip3 <$> mapM mkTopInstOutput ps       let ids1 = map (flip Identifier Nothing) ids0-          netassgn = Assignment pName (mkVectorChain sz hwty'' ids1)+          netassgn = Assignment pName Cont (mkVectorChain sz hwty'' ids1)       if null attrs then         return (concat ports, pDecl:netassgn:concat decls, pName)       else@@ -1524,7 +1741,7 @@     RTree d hwty'' -> do       (ports, decls, ids0) <- unzip3 <$> mapM mkTopInstOutput ps       let ids1 = map (flip Identifier Nothing) ids0-          netassgn = Assignment pName (mkRTreeChain d hwty'' ids1)+          netassgn = Assignment pName Cont (mkRTreeChain d hwty'' ids1)       if null attrs then         return (concat ports, pDecl:netassgn:concat decls, pName)       else@@ -1533,7 +1750,7 @@     Product {} -> do       (ports, decls, ids0) <- unzip3 <$> mapM mkTopInstOutput ps       let ids1 = map (flip Identifier Nothing) ids0-          netassgn = Assignment pName (DataCon hwty (DC (hwty,0)) ids1)+          netassgn = Assignment pName Cont (DataCon hwty (DC (hwty,0)) ids1)       if null attrs then         return (concat ports, pDecl:netassgn:concat decls, pName)       else@@ -1545,7 +1762,7 @@           ids2 = case ids1 of                   [conId, elId] -> [conId, ToBv Nothing elTy elId]                   _ -> error "Unexpected error for PortProduct"-          netassgn = Assignment pName (DataCon hwty (DC (BitVector (typeSize hwty),0)) ids2)+          netassgn = Assignment pName Cont (DataCon hwty (DC (BitVector (typeSize hwty),0)) ids2)       return (concat ports, pDecl:netassgn:concat decls, pName)      _ ->@@ -1689,14 +1906,14 @@ -- | Errors 'expandTopEntity' might yield data ExpandError   -- | Synthesis attributes are not supported on PortProducts-  = AttrError [Attr']+  = AttrError [Attr Text]   -- | Something was annotated as being a PortProduct, but wasn't one   | PortProductError PortName HWType  -- | Same as 'expandTopEntity', but also adds identifiers to the identifier -- set of the monad. expandTopEntityOrErrM-  :: (HasCallStack, IdentifierSetMonad m)+  :: HasCallStack   => [(Maybe Id, FilteredHWType)]   -- ^ Arguments. Ids are used as name hints.   -> (Maybe Id, FilteredHWType)@@ -1704,36 +1921,13 @@   -> Maybe TopEntity   -- ^ If /Nothing/, an expanded top entity will be generated as if /defSyn/   -- was passed.-  -> m (ExpandedTopEntity Identifier)+  -> NetlistMonad (ExpandedTopEntity Identifier)   -- ^ Either some error (see "ExpandError") or and expanded top entity. All   -- identifiers in the expanded top entity will be added to NetlistState's   -- IdentifierSet. expandTopEntityOrErrM ihwtys ohwty topM = do   is <- identifierSetM id-  let ett = expandTopEntityOrErr is ihwtys ohwty topM-  Id.addMultiple (toList ett)-  pure ett --- | Take a top entity and /expand/ its port names. I.e., make sure that every--- port that should be generated in the HDL is part of the data structure.-expandTopEntityOrErr-  :: HasCallStack-  => IdentifierSet-  -- ^ Settings of this IdentifierSet will be used to generate valid-  -- identifiers. Note that the generated identifiers are /not/ guaranteed to be-  -- unique w.r.t. this set.-  -> [(Maybe Id, FilteredHWType)]-  -- ^ Arguments. Ids are used as name hints.-  -> (Maybe Id, FilteredHWType)-  -- ^ Result. Id is used as name hint.-  -> Maybe TopEntity-  -- ^ If /Nothing/, an expanded top entity will be generated as if /defSyn/-  -- was passed.-  -> ExpandedTopEntity Identifier-  -- ^ Either some error (see "ExpandError") or and expanded top entity. All-  -- identifiers in the expanded top entity will be added to NetlistState's-  -- IdentifierSet.-expandTopEntityOrErr is ihwtys ohwty topM = do   case expandTopEntity ihwtys ohwty topM of     Left (AttrError attrs) ->       (error [I.i|@@ -1754,8 +1948,10 @@          is not a product!       |])-    Right eTop ->-      evalState (traverse (either Id.addRaw Id.makeBasic) eTop) (Id.clearSet is)+    Right eTop -> do+      let ete = evalState (traverse (either Id.addRaw Id.makeBasic) eTop) (Id.clearSet is)+      Id.addMultiple (toList ete)+      pure ete  -- | Take a top entity and /expand/ its port names. I.e., make sure that every -- port that should be generated in the HDL is part of the data structure. It@@ -1773,13 +1969,13 @@   -- expanded top entity in turn contains an Either too. /Left/ means that   -- the name was supplied by the user and should be inserted at verbatim,   -- /Right/ is a name generated by Clash.-expandTopEntity ihwtys (oId, ohwty) topEntityM = do+expandTopEntity ihwtys (oId, ohwty) topEntityM+  | Synthesize {..} <- fromMaybe (defSyn (error $(curLoc))) topEntityM = do   -- TODO 1: Check sizes against number of PortProduct fields   -- TODO 2: Warn about duplicate fields   let-    Synthesize{..} = fromMaybe (defSyn (error $(curLoc))) topEntityM-    argHints = map (maybe "arg" (Id.toText . id2identifier) . fst) ihwtys-    resHint = maybe "result" (Id.toText . id2identifier) oId+    argHints = map (maybe "arg" (Id.toText . Id.unsafeFromCoreId) . fst) ihwtys+    resHint = maybe "result" (Id.toText . Id.unsafeFromCoreId) oId    inputs <- zipWith3M goInput argHints (map snd ihwtys) (extendPorts t_inputs) @@ -1917,3 +2113,6 @@    where     (attrs, hwty1) = stripAttributes hwty0     hints = map (\i -> hint <> "_" <> showt i) [(0::Int)..]++expandTopEntity _ _ topEntityM =+  error ("expandTopEntity expects a Synthesize annotation, but got: " <> show topEntityM)
src/Clash/Normalize.hs view
@@ -2,7 +2,7 @@   Copyright   :  (C) 2012-2016, University of Twente,                      2016     , Myrtle Software Ltd,                      2017     , Google Inc.,-                     2021-2022, QBayLogic B.V.+                     2021-2023, QBayLogic B.V.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -37,11 +37,7 @@ import           Data.Text.Prettyprint.Doc        (vcat) #endif -#if MIN_VERSION_ghc(9,0,0)-import           GHC.Types.Basic                  (InlineSpec (..))-#else-import           BasicTypes                       (InlineSpec (..))-#endif+import           GHC.BasicTypes.Extra             (isNoInline)  import           Clash.Annotations.BitRepresentation.Internal   (CustomReprs)@@ -75,7 +71,8 @@ import           Clash.Normalize.Transformations import           Clash.Normalize.Types import           Clash.Normalize.Util-import           Clash.Rewrite.Combinators        ((>->),(!->),repeatR,topdownR)+import           Clash.Rewrite.Combinators+  ((>->), (!->), bottomupR, repeatR, topdownR) import           Clash.Rewrite.Types   (RewriteEnv (..), RewriteState (..), bindings, debugOpts, extra,    tcCache, topEntities, newInlineStrategy)@@ -298,7 +295,7 @@ flattenNode   :: CallTree   -> NormalizeSession (Either CallTree ((Id,Term),[CallTree]))-flattenNode c@(CLeaf (_,(Binding _ _ NoInline _ _ _))) = return (Left c)+flattenNode c@(CLeaf (_,(Binding _ _ spec _ _ _))) | isNoInline spec = return (Left c) flattenNode c@(CLeaf (nm,(Binding _ _ _ _ e _))) = do   isTopEntity <- elemVarSet nm <$> Lens.view topEntities   if isTopEntity then return (Left c) else do@@ -312,7 +309,7 @@                return (Right ((nm,mkApps (mkTicks fun ticks) (reverse remainder)),[]))           _ -> return (Right ((nm,e),[]))       _ -> return (Right ((nm,e),[]))-flattenNode b@(CBranch (_,(Binding _ _ NoInline _ _ _)) _) =+flattenNode b@(CBranch (_,(Binding _ _ spec _ _ _)) _) | isNoInline spec =   return (Left b) flattenNode b@(CBranch (nm,(Binding _ _ _ _ e _)) us) = do   isTopEntity <- elemVarSet nm <$> Lens.view topEntities@@ -366,7 +363,7 @@   -- inline all components when the resulting expression after flattening   -- is still considered "cheap". This happens often at the topEntity which   -- wraps another functions and has some selectors and data-constructors.-  if inl /= NoInline && isCheapFunction newExpr+  if not (isNoInline inl) && isCheapFunction newExpr      then do         let (toInline',allUsed') = unzip (map goCheap allUsed)             subst' = extendGblSubstList (mkSubst emptyInScopeSet)@@ -382,15 +379,15 @@                  apply "caseCon" caseCon >->                  (apply "reduceConst" reduceConst !-> apply "deadcode" deadCode) >->                  apply "reduceNonRepPrim" reduceNonRepPrim >->-                 apply "removeUnusedExpr" removeUnusedExpr >->-                 apply "flattenLet" flattenLet)) !->+                 apply "removeUnusedExpr" removeUnusedExpr) >->+               bottomupR (apply "flattenLet" flattenLet)) !->       topdownSucR (apply "topLet" topLet)      goCheap c@(CLeaf   (nm2,(Binding _ _ inl2 _ e _)))-      | inl2 == NoInline = (Nothing     ,[c])+      | isNoInline inl2  = (Nothing     ,[c])       | otherwise        = (Just (nm2,e),[])     goCheap c@(CBranch (nm2,(Binding _ _ inl2 _ e _)) us)-      | inl2 == NoInline = (Nothing, [c])+      | isNoInline inl2  = (Nothing, [c])       | otherwise        = (Just (nm2,e),us)  callTreeToList :: [Id] -> CallTree -> ([Id], [(Id, Binding Term)])
src/Clash/Normalize/PrimitiveReductions.hs view
@@ -40,10 +40,14 @@  import qualified Control.Lens                     as Lens import           Control.Lens                     ((.=))+import           Control.Monad.Trans.Class        (lift)+import           Control.Monad.Trans.Maybe        (MaybeT (..)) import           Data.Bifunctor                   (second) import           Data.List                        (mapAccumR) import           Data.List.Extra                  (zipEqual)+import qualified Data.List.NonEmpty               as NE import qualified Data.Maybe                       as Maybe+import           Data.Semigroup                   (sconcat) import           Data.Text.Extra                  (showt) import           GHC.Stack                        (HasCallStack) @@ -82,14 +86,13 @@   (appendToVec, extractElems, extractTElems, mkRTree,    mkUniqInternalId, mkUniqSystemTyVar, mkVec, dataConInstArgTys, primCo) import           Clash.Core.Var                   (mkTyVar, mkLocalId)-import           Clash.Core.VarEnv-  (InScopeSet, extendInScopeSetList)+import           Clash.Core.VarEnv                (extendInScopeSetList)+import qualified Clash.Data.UniqMap as UniqMap import qualified Clash.Normalize.Primitives as NP (undefined) import {-# SOURCE #-} Clash.Normalize.Strategy import           Clash.Normalize.Types import           Clash.Rewrite.Types import           Clash.Rewrite.Util-import           Clash.Unique import           Clash.Util import qualified Clash.Util.Interpolate           as I @@ -177,25 +180,28 @@   -> Type   -- ^ Element type   -> Integer-  -- ^ Length of the vector+  -- ^ Length of the vector, must be positive   -> Term   -- ^ Vector to extract head from   -> (Term, Term)   -- ^ (head of vector, tail of vector) extractHeadTail consCon elTy n vec =-  ( Case vec elTy [(pat, Var el)]-  , Case vec restTy [(pat, Var rest)] )+  case dataConInstArgTys consCon tys of+    Just [coTy, _elTy, restTy] ->+      let+        mTV = mkTyVar typeNatKind (mkUnsafeSystemName "m" 0)+        co = mkLocalId coTy (mkUnsafeSystemName "_co_" 1)+        el = mkLocalId elTy (mkUnsafeSystemName "el" 2)+        rest = mkLocalId restTy (mkUnsafeSystemName "res" 3)++        pat = DataPat consCon [mTV] [co, el, rest]+      in+        ( Case vec elTy [(pat, Var el)]+        , Case vec restTy [(pat, Var rest)] )+    _ -> error "extractHeadTail: failed to instantiate Cons DC"  where   tys = [(LitTy (NumTy n)), elTy, (LitTy (NumTy (n-1)))]-  Just [coTy, _elTy, restTy] = dataConInstArgTys consCon tys -  mTV = mkTyVar typeNatKind (mkUnsafeSystemName "m" 0)-  co = mkLocalId coTy (mkUnsafeSystemName "_co_" 1)-  el = mkLocalId elTy (mkUnsafeSystemName "el" 2)-  rest = mkLocalId restTy (mkUnsafeSystemName "res" 3)--  pat = DataPat consCon [mTV] [co, el, rest]- -- | Create a vector of supplied elements mkVecCons   :: HasCallStack@@ -212,17 +218,16 @@   -> Term mkVecCons consCon resTy n h t   | n <= 0 = error "mkVecCons: n <= 0"-  | otherwise =-    mkApps (Data consCon) [ Right (LitTy (NumTy n))-                          , Right resTy-                          , Right (LitTy (NumTy (n-1)))-                          , Left (primCo consCoTy)-                          , Left h-                          , Left t ]-- where-  args = dataConInstArgTys consCon [LitTy (NumTy n), resTy, LitTy (NumTy (n-1))]-  Just (consCoTy : _) = args+  | otherwise+  = case dataConInstArgTys consCon [LitTy (NumTy n), resTy, LitTy (NumTy (n-1))] of+    Just (consCoTy : _) ->+      mkApps (Data consCon) [ Right (LitTy (NumTy n))+                            , Right resTy+                            , Right (LitTy (NumTy (n-1)))+                            , Left (primCo consCoTy)+                            , Left h+                            , Left t ]+    _ -> error "mkVecCons: failed to instantiate Cons DC"  -- | Create an empty vector mkVecNil@@ -231,42 +236,41 @@   -> Type   -- ^ The element type   -> Term-mkVecNil nilCon resTy =-  mkApps (Data nilCon) [ Right (LitTy (NumTy 0))-                       , Right resTy-                       , Left  (primCo nilCoTy) ]- where-  args = dataConInstArgTys nilCon [LitTy (NumTy 0), resTy]-  Just (nilCoTy : _ ) = args+mkVecNil nilCon resTy = case dataConInstArgTys nilCon [LitTy (NumTy 0), resTy] of+  Just (nilCoTy : _) ->+    mkApps (Data nilCon) [ Right (LitTy (NumTy 0))+                        , Right resTy+                        , Left  (primCo nilCoTy) ]+  _ -> error "mkVecNil: failed to instantiate Nil DC"  -- | Replace an application of the @Clash.Sized.Vector.reverse@ primitive on -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.reverse@ reduceReverse-  :: InScopeSet-  -> Integer-  -- ^ Length of the vector+  :: Integer+  -- ^ Length of the vector, must be positive   -> Type   -- ^ Element of type of the vector   -> Term   -- ^ The vector to reverse+  -> TransformContext   -> NormalizeSession Term-reduceReverse inScope0 n elTy vArg = do+reduceReverse n elTy vArg (TransformContext inScope0 _ctx) = do   tcm <- Lens.view tcCache   let ty = inferCoreTypeOf tcm vArg   go tcm ty  where   go tcm (coreView1 tcm -> Just ty') = go tcm ty'   go tcm (tyView -> TyConApp vecTcNm _)-    | Just vecTc <- lookupUniqMap vecTcNm tcm+    | Just vecTc <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"     , [nilCon, consCon] <- tyConDataCons vecTc     = do       uniqs0 <- Lens.use uniqSupply-      let (uniqs1,(vars,elems)) = second (second concat . unzip)+      let (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                 $ extractElems uniqs0 inScope0 consCon elTy 'V' n vArg-          lbody = mkVec nilCon consCon elTy n (reverse vars)-          lb    = Letrec (init elems) lbody+          lbody = mkVec nilCon consCon elTy n (reverse (NE.toList vars))+          lb    = Letrec (NE.init elems) lbody       uniqSupply Lens..= uniqs1       changed lb   go _ ty = error $ $(curLoc) ++ "reduceReverse: argument does not have a vector type: " ++ showPpr ty@@ -275,8 +279,7 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.zipWith@ reduceZipWith-  :: TransformContext-  -> PrimInfo -- ^ zipWith primitive info+  :: PrimInfo -- ^ zipWith primitive info   -> Integer  -- ^ Length of the vector(s)   -> Type -- ^ Element type of the lhs of the function   -> Type -- ^ Element type of the rhs of the function@@ -284,14 +287,15 @@   -> Term -- ^ The zipWith'd functions   -> Term -- ^ The 1st vector argument   -> Term -- ^ The 2nd vector argument+  -> TransformContext   -> NormalizeSession Term-reduceZipWith _ctx zipWithPrimInfo n lhsElTy rhsElTy resElTy fun lhsArg rhsArg = do+reduceZipWith zipWithPrimInfo n lhsElTy rhsElTy resElTy fun lhsArg rhsArg _ctx = do   tcm <- Lens.view tcCache   changed (go tcm (inferCoreTypeOf tcm lhsArg))  where   go tcm (coreView1 tcm -> Just ty) = go tcm ty   go tcm (tyView -> TyConApp vecTcNm _)-    | (Just vecTc) <- lookupUniqMap vecTcNm tcm+    | (Just vecTc) <- UniqMap.lookup vecTcNm tcm     , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"     , [nilCon, consCon] <- tyConDataCons vecTc     = if n == 0 then@@ -321,22 +325,22 @@ -- of a known length @n@, by the fully unrolled recursive "definition" of -- @Clash.Sized.Vector.map@ reduceMap-  :: TransformContext-  -> PrimInfo -- ^ map primitive info+  :: PrimInfo -- ^ map primitive info   -> Integer  -- ^ Length of the vector   -> Type -- ^ Argument type of the function   -> Type -- ^ Result type of the function   -> Term -- ^ The map'd function   -> Term -- ^ The map'd over vector+  -> TransformContext   -> NormalizeSession Term-reduceMap _ctx mapPrimInfo n argElTy resElTy fun arg = do+reduceMap mapPrimInfo n argElTy resElTy fun arg _ctx = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     changed (go tcm ty)   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+      | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [nilCon,consCon] <- tyConDataCons vecTc       = if n == 0 then@@ -364,21 +368,22 @@ -- of a known length @n@, by the fully unrolled recursive "definition" of -- @Clash.Sized.Vector.imap@ reduceImap-  :: TransformContext-  -> Integer  -- ^ Length of the vector+  :: Integer  -- ^ Length of the vector, must be positive   -> Type -- ^ Argument type of the function   -> Type -- ^ Result type of the function+  -> Term -- ^ Lenght of the vector (as a KnownNat)   -> Term -- ^ The imap'd function   -> Term -- ^ The imap'd over vector+  -> TransformContext   -> NormalizeSession Term-reduceImap (TransformContext is0 ctx) n argElTy resElTy fun arg = do+reduceImap n argElTy resElTy _kn fun arg (TransformContext is0 ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+      | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [nilCon,consCon] <- tyConDataCons vecTc       = do@@ -386,10 +391,12 @@         fun1 <- constantPropagation (TransformContext is0 (AppArg Nothing:ctx)) fun         let is1 = extendInScopeSetList is0 (collectTermIds fun1)             (uniqs1,nTv) = mkUniqSystemTyVar (uniqs0,is1) ("n",typeNatKind)-            (uniqs2,(vars,elems)) = second (second concat . unzip)+            (uniqs2,(vars,elems)) = second (second sconcat . NE.unzip)                                   $ uncurry extractElems uniqs1 consCon argElTy 'I' n arg-            (Right idxTy:_,_) = splitFunForallTy (inferCoreTypeOf tcm fun)-            (TyConApp idxTcNm _) = tyView idxTy+            idxTcNm = Maybe.fromMaybe (error "reduceImap: failed to create Index TC") $ do+              (Right idxTy:_,_) <- pure (splitFunForallTy (inferCoreTypeOf tcm fun))+              TyConApp nm _ <- pure (tyView idxTy)+              return nm             -- fromInteger# :: KnownNat n => Integer -> Index n             idxFromIntegerTy = ForAllTy nTv                                         (foldr mkFunTy@@ -400,9 +407,9 @@             idxs             = map (App (App (TyApp idxFromInteger (LitTy (NumTy n)))                                              (Literal (IntegerLiteral (toInteger n))))                                    . Literal . IntegerLiteral . toInteger) [0..(n-1)]-            funApps          = zipWith (\i v -> App (App fun1 i) v) idxs vars+            funApps          = zipWith (\i v -> App (App fun1 i) v) idxs (NE.toList vars)             lbody            = mkVec nilCon consCon resElTy n funApps-            lb               = Letrec (init elems) lbody+            lb               = Letrec (NE.init elems) lbody         uniqSupply Lens..= uniqs2         changed lb     go _ ty = error $ $(curLoc) ++ "reduceImap: argument does not have a vector type: " ++ showPpr ty@@ -411,20 +418,22 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.iterateI@ reduceIterateI-  :: TransformContext-  -> Integer+  :: Integer   -- ^ Length of vector   -> Type   -- ^ Vector's element type   -> Type   -- ^ Vector's type   -> Term+  -- ^ Length of the vector (as a KnownNat)+  -> Term   -- ^ iterateI's HO-function argument   -> Term   -- ^ iterateI's start value+  -> TransformContext   -> RewriteMonad NormalizeState Term   -- ^ Fully unrolled definition-reduceIterateI (TransformContext is0 ctx) n aTy vTy f0 a = do+reduceIterateI n aTy vTy _kn f0 a (TransformContext is0 ctx) = do   tcm <- Lens.view tcCache   f1 <- constantPropagation (TransformContext is0 (AppArg Nothing:ctx)) f0 @@ -440,11 +449,12 @@   uniqSupply .= uniqs1    let-    TyConApp vecTcNm _ = tyView vTy-    Just vecTc = lookupUniqMap vecTcNm tcm-    [nilCon, consCon] = tyConDataCons vecTc     elems = map (App f1) (a:map Var elementIds)-    vec = mkVec nilCon consCon aTy n (take (fromInteger n) (a:map Var elementIds))+    vec = Maybe.fromMaybe (error "reduceIterateI: failed to create Vec DCs") $ do+      TyConApp vecTcNm _ <- pure (tyView vTy)+      vecTc <- UniqMap.lookup vecTcNm tcm+      [nilCon, consCon] <- pure (tyConDataCons vecTc)+      return (mkVec nilCon consCon aTy n (take (fromInteger n) (a:map Var elementIds)))    -- Result:   --   let@@ -461,84 +471,86 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.traverse#@ reduceTraverse-  :: TransformContext-  -> Integer  -- ^ Length of the vector+  :: Integer  -- ^ Length of the vector, must be positive   -> Type -- ^ Element type of the argument vector   -> Type -- ^ The type of the applicative   -> Type -- ^ Element type of the result vector   -> Term -- ^ The @Applicative@ dictionary   -> Term -- ^ The function to traverse with   -> Term -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceTraverse (TransformContext is0 ctx) n aTy fTy bTy dict fun arg = do+reduceTraverse n aTy fTy bTy dict fun arg (TransformContext is0 ctx) = do     tcm <- Lens.view tcCache-    let (TyConApp apDictTcNm _) = tyView (inferCoreTypeOf tcm dict)-        ty = inferCoreTypeOf tcm arg-    go tcm apDictTcNm ty+    case tyView (inferCoreTypeOf tcm dict) of+      TyConApp apDictTcNm _ ->+        let ty = inferCoreTypeOf tcm arg+         in go tcm apDictTcNm ty+      t -> error ("reduceTraverse: expected a TC, but got: " <> show t)   where     go tcm apDictTcNm (coreView1 tcm -> Just ty') = go tcm apDictTcNm ty'     go tcm apDictTcNm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [nilCon,consCon] <- tyConDataCons vecTc-      = do-        uniqs0 <- Lens.use uniqSupply-        fun1 <- constantPropagation (TransformContext is0 (AppArg Nothing:ctx)) fun-        let is1 = extendInScopeSetList is0 (collectTermIds fun1)-            (Just apDictTc)    = lookupUniqMap apDictTcNm tcm-            [apDictCon]        = tyConDataCons apDictTc-            (Just apDictIdTys) = dataConInstArgTys apDictCon [fTy]-            (uniqs1,apDictIds@[functorDictId,pureId,apId,_,_,_]) =-              mapAccumR mkUniqInternalId (uniqs0,is1)-                (zipEqual ["functorDict","pure","ap","liftA2","apConstL","apConstR"]-                     apDictIdTys)+      = fmap (Maybe.fromMaybe (error "reduceTraverse: failed to build")) $ runMaybeT $ do+          uniqs0 <- Lens.use uniqSupply+          fun1 <- lift (constantPropagation (TransformContext is0 (AppArg Nothing:ctx)) fun)+          let is1 = extendInScopeSetList is0 (collectTermIds fun1)+          apDictTc <- hoistMaybe (UniqMap.lookup apDictTcNm tcm)+          apDictCon <- hoistMaybe (Maybe.listToMaybe (tyConDataCons apDictTc))+          apDictIdTys <- hoistMaybe (dataConInstArgTys apDictCon [fTy])+          (uniqs1,apDictIds@[functorDictId,pureId,apId,_,_,_]) <- pure $+                mapAccumR mkUniqInternalId (uniqs0,is1)+                  (zipEqual ["functorDict","pure","ap","liftA2","apConstL","apConstR"]+                      apDictIdTys) -            (TyConApp funcDictTcNm _) = tyView (head apDictIdTys)-            (Just funcDictTc) = lookupUniqMap funcDictTcNm tcm-            [funcDictCon] = tyConDataCons funcDictTc-            (Just funcDictIdTys) = dataConInstArgTys funcDictCon [fTy]-            (uniqs2,funcDicIds@[fmapId,_]) =-              mapAccumR mkUniqInternalId uniqs1-                (zipEqual ["fmap","fmapConst"] funcDictIdTys)+          TyConApp funcDictTcNm _ <- hoistMaybe (tyView <$> Maybe.listToMaybe apDictIdTys)+          funcDictTc <- hoistMaybe (UniqMap.lookup funcDictTcNm tcm)+          funcDictCon <- hoistMaybe (Maybe.listToMaybe (tyConDataCons funcDictTc))+          funcDictIdTys <- hoistMaybe (dataConInstArgTys funcDictCon [fTy])+          (uniqs2,funcDicIds@[fmapId,_]) <- pure $+                mapAccumR mkUniqInternalId uniqs1+                  (zipEqual ["fmap","fmapConst"] funcDictIdTys) -            apPat    = DataPat apDictCon   [] apDictIds-            fnPat    = DataPat funcDictCon [] funcDicIds+          let apPat    = DataPat apDictCon   [] apDictIds+              fnPat    = DataPat funcDictCon [] funcDicIds -            -- Extract the 'pure' function from the Applicative dictionary-            pureTy = coreTypeOf pureId-            pureTm = Case dict pureTy [(apPat,Var pureId)]+              -- Extract the 'pure' function from the Applicative dictionary+              pureTy = coreTypeOf pureId+              pureTm = Case dict pureTy [(apPat,Var pureId)] -            -- Extract the '<*>' function from the Applicative dictionary-            apTy   = coreTypeOf apId-            apTm   = Case dict apTy [(apPat, Var apId)]+              -- Extract the '<*>' function from the Applicative dictionary+              apTy   = coreTypeOf apId+              apTm   = Case dict apTy [(apPat, Var apId)] -            -- Extract the Functor dictionary from the Applicative dictionary-            funcTy = coreTypeOf functorDictId-            funcTm = Case dict funcTy-                               [(apPat,Var functorDictId)]+              -- Extract the Functor dictionary from the Applicative dictionary+              funcTy = coreTypeOf functorDictId+              funcTm = Case dict funcTy+                                [(apPat,Var functorDictId)] -            -- Extract the 'fmap' function from the Functor dictionary-            fmapTy = coreTypeOf fmapId-            fmapTm = Case (Var functorDictId) fmapTy-                          [(fnPat, Var fmapId)]+              -- Extract the 'fmap' function from the Functor dictionary+              fmapTy = coreTypeOf fmapId+              fmapTm = Case (Var functorDictId) fmapTy+                            [(fnPat, Var fmapId)] -            (uniqs3,(vars,elems)) = second (second concat . unzip)-                                  $ uncurry extractElems uniqs2 consCon aTy 'T' n arg+              (uniqs3,(vars,elems)) = second (second sconcat . NE.unzip)+                                    $ uncurry extractElems uniqs2 consCon aTy 'T' n arg -            funApps = map (fun1 `App`) vars+              funApps = map (fun1 `App`) (NE.toList vars) -            lbody   = mkTravVec vecTcNm nilCon consCon (Var (apDictIds!!1))-                                                       (Var (apDictIds!!2))-                                                       (Var (funcDicIds!!0))-                                                       bTy n funApps+              lbody   = mkTravVec vecTcNm nilCon consCon (Var (apDictIds!!1))+                                                        (Var (apDictIds!!2))+                                                        (Var (funcDicIds!!0))+                                                        bTy n funApps -            lb      = Letrec ([((apDictIds!!0), funcTm)-                              ,((apDictIds!!1), pureTm)-                              ,((apDictIds!!2), apTm)-                              ,((funcDicIds!!0), fmapTm)-                              ] ++ init elems) lbody-        uniqSupply Lens..= uniqs3-        changed lb+              lb      = Letrec ([((apDictIds!!0), funcTm)+                                ,((apDictIds!!1), pureTm)+                                ,((apDictIds!!2), apTm)+                                ,((funcDicIds!!0), fmapTm)+                                ] ++ NE.init elems) lbody+          uniqSupply Lens..= uniqs3+          lift (changed lb)     go _ _ ty = error $ $(curLoc) ++ "reduceTraverse: argument does not have a vector type: " ++ showPpr ty  -- | Create the traversable vector@@ -580,20 +592,22 @@                            ,Left  x])       ,Left (go (n-1) xs)] -    nilCoTy = head (Maybe.fromJust (dataConInstArgTys nilCon [(LitTy (NumTy 0))-                                                             ,bTy]))+    nilCoTy = case dataConInstArgTys nilCon [(LitTy (NumTy 0)), bTy] of+                Just (x:_) -> x+                _ -> error "impossible" -    consCoTy n = head (Maybe.fromJust (dataConInstArgTys consCon-                                                         [(LitTy (NumTy n))-                                                         ,bTy-                                                         ,(LitTy (NumTy (n-1)))]))+    consCoTy n = case dataConInstArgTys consCon+                                        [(LitTy (NumTy n))+                                        ,bTy+                                        ,(LitTy (NumTy (n-1)))] of+                   Just (x:_) -> x+                   _ -> error "impossible"  -- | Replace an application of the @Clash.Sized.Vector.foldr@ primitive on -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.foldr@ reduceFoldr-  :: TransformContext-  -> PrimInfo+  :: PrimInfo   -- ^ Primitive info for foldr blackbox   -> Integer   -- ^ Length of the vector@@ -605,9 +619,10 @@   -- ^ The starting value   -> Term   -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceFoldr _ _ 0 _ _ start _ = changed start-reduceFoldr _ctx foldrPrimInfo n aTy fun start arg = do+reduceFoldr _ 0 _ _ start _ _ = changed start+reduceFoldr foldrPrimInfo n aTy fun start arg _ctx = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     changed (go tcm ty)@@ -615,7 +630,7 @@     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)       | nameOcc vecTcNm == "Clash.Sized.Vector.Vec"-      , Just vecTc <- lookupUniqMap vecTcNm tcm+      , Just vecTc <- UniqMap.lookup vecTcNm tcm       , [_nilCon, consCon] <- tyConDataCons vecTc       = let           (a, as) = extractHeadTail consCon aTy n arg@@ -639,34 +654,34 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.fold@ reduceFold-  :: TransformContext-  -> Integer-  -- ^ Length of the vector+  :: Integer+  -- ^ Length of the vector, must be positive   -> Type   -- ^ Element type of the argument vector   -> Term   -- ^ The function to fold with   -> Term   -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceFold (TransformContext is0 ctx) n aTy fun arg = do+reduceFold n aTy fun arg (TransformContext is0 ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do         uniqs0 <- Lens.use uniqSupply         fun1 <- constantPropagation (TransformContext is0 (AppArg Nothing:ctx)) fun         let is1 = extendInScopeSetList is0 (collectTermIds fun1)-            (uniqs1,(vars,elems)) = second (second concat . unzip)+            (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                   $ extractElems uniqs0 is1 consCon aTy 'F' n arg-            lbody            = foldV fun1 vars-            lb               = Letrec (init elems) lbody+            lbody            = foldV fun1 (NE.toList vars)+            lb               = Letrec (NE.init elems) lbody         uniqSupply Lens..= uniqs1         changed lb     go _ ty = error $ $(curLoc) ++ "reduceFold: argument does not have a vector type: " ++ showPpr ty@@ -681,27 +696,31 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.dfold@ reduceDFold-  :: InScopeSet-  -> Integer+  :: Integer   -- ^ Length of the vector   -> Type   -- ^ Element type of the argument vector   -> Term+  -- ^ Length of the vector (as a KnownNat)+  -> Term+  -- ^ The motive+  -> Term   -- ^ Function to fold with   -> Term   -- ^ Starting value   -> Term   -- ^ The vector to fold+  -> TransformContext   -> NormalizeSession Term-reduceDFold _ 0 _ _ start _ = changed start-reduceDFold is0 n aTy fun start arg = do+reduceDFold 0 _   _   _       _   start _   _ = changed start+reduceDFold n aTy _kn _motive fun start arg (TransformContext is0 _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do@@ -709,14 +728,15 @@         let is1 = extendInScopeSetList is0 (collectTermIds fun)             -- TODO: Should 'constantPropagation' be used on 'fun'? It seems to             -- TOOD: be used for every other function in this module.-            (uniqs1,(vars,elems)) = second (second concat . unzip)+            (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                   $ extractElems uniqs0 is1 consCon aTy 'D' n arg-            (_ltv:Right snTy:_,_) = splitFunForallTy (inferCoreTypeOf tcm fun)-            (TyConApp snatTcNm _) = tyView snTy-            (Just snatTc)         = lookupUniqMap snatTcNm tcm-            [snatDc]              = tyConDataCons snatTc-            lbody = doFold (buildSNat snatDc) (n-1) vars-            lb    = Letrec (init elems) lbody+            snatDc = Maybe.fromMaybe (error "reduceDFold: faild to build SNat") $ do+              (_ltv:Right snTy:_,_) <- pure (splitFunForallTy (inferCoreTypeOf tcm fun))+              (TyConApp snatTcNm _) <- pure (tyView snTy)+              snatTc <- UniqMap.lookup snatTcNm tcm+              Maybe.listToMaybe (tyConDataCons snatTc)+            lbody = doFold (buildSNat snatDc) (n-1) (NE.toList vars)+            lb    = Letrec (NE.init elems) lbody         uniqSupply Lens..= uniqs1         changed lb     go _ ty = error $ $(curLoc) ++ "reduceDFold: argument does not have a vector type: " ++ showPpr ty@@ -733,26 +753,26 @@ -- vectors of a known length @n@, by a projection of the first element of a -- vector. reduceHead-  :: InScopeSet-  -> Integer  -- ^ Length of the vector+  :: Integer  -- ^ Length of the vector, must be positive   -> Type -- ^ Element type of the vector   -> Term -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceHead inScope n aTy vArg = do+reduceHead n aTy vArg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm vArg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do         uniqs0 <- Lens.use uniqSupply-        let (uniqs1,(vars,elems)) = second (second concat . unzip)+        let (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                   $ extractElems uniqs0 inScope consCon aTy 'H' n vArg-            lb = Letrec [head elems] (head vars)+            lb = Letrec [NE.head elems] (NE.head vars)         uniqSupply Lens..= uniqs1         changed lb     go _ ty = error $ $(curLoc) ++ "reduceHead: argument does not have a vector type: " ++ showPpr ty@@ -761,26 +781,26 @@ -- vectors of a known length @n@, by a projection of the tail of a -- vector. reduceTail-  :: InScopeSet-  -> Integer  -- ^ Length of the vector+  :: Integer  -- ^ Length of the vector, must be positive   -> Type -- ^ Element type of the vector   -> Term -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceTail inScope n aTy vArg = do+reduceTail n aTy vArg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm vArg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do         uniqs0 <- Lens.use uniqSupply-        let (uniqs1,(_,elems)) = second (second concat . unzip)+        let (uniqs1,(_,elems)) = second (second sconcat . NE.unzip)                                $ extractElems uniqs0 inScope consCon aTy 'L' n vArg-            b@(tB,_)     = elems !! 1+            b@(tB,_)     = elems NE.!! 1             lb           = Letrec [b] (Var tB)         uniqSupply Lens..= uniqs1         changed lb@@ -790,50 +810,50 @@ -- vectors of a known length @n@, by a projection of the last element of a -- vector. reduceLast-  :: InScopeSet-  -> Integer  -- ^ Length of the vector+  :: Integer  -- ^ Length of the vector, must be positive   -> Type -- ^ Element type of the vector   -> Term -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceLast inScope n aTy vArg = do+reduceLast n aTy vArg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm vArg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do         uniqs0 <- Lens.use uniqSupply-        let (uniqs1,(_,elems)) = second unzip+        let (uniqs1,(_,elems)) = second NE.unzip                                $ extractElems uniqs0 inScope consCon aTy 'L' n vArg-            (tB,_)       = head (last elems)+            (tB,_)       = NE.head (NE.last elems)         uniqSupply Lens..= uniqs1         case n of          0 -> changed (TyApp (Prim NP.undefined) aTy)-         _ -> changed (Letrec (init (concat elems)) (Var tB))+         _ -> changed (Letrec (NE.init (sconcat elems)) (Var tB))     go _ ty = error $ $(curLoc) ++ "reduceLast: argument does not have a vector type: " ++ showPpr ty  -- | Replace an application of the @Clash.Sized.Vector.init@ primitive on -- vectors of a known length @n@, by a projection of the init of a -- vector. reduceInit-  :: InScopeSet-  -> PrimInfo -- ^ Primitive info for 'init'+  :: PrimInfo -- ^ Primitive info for 'init'   -> Integer  -- ^ Length of the vector   -> Type -- ^ Element type of the vector   -> Term -- ^ The argument vector+  -> TransformContext   -> NormalizeSession Term-reduceInit _inScope initPrimInfo n aTy vArg = do+reduceInit initPrimInfo n aTy vArg _ctx = do   tcm <- Lens.view tcCache   let ty = inferCoreTypeOf tcm vArg   changed (go tcm ty)  where   go tcm (coreView1 tcm -> Just ty') = go tcm ty'   go tcm (tyView -> TyConApp vecTcNm _)-    | (Just vecTc) <- lookupUniqMap vecTcNm tcm+    | (Just vecTc) <- UniqMap.lookup vecTcNm tcm     , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"     , [nilCon, consCon]  <- tyConDataCons vecTc     = if n == 0 then@@ -857,29 +877,31 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.(++)@ reduceAppend-  :: InScopeSet-  -> Integer  -- ^ Length of the LHS arg+  :: Integer  -- ^ Length of the LHS arg   -> Integer  -- ^ Lenght of the RHS arg   -> Type -- ^ Element type of the vectors   -> Term -- ^ The LHS argument   -> Term -- ^ The RHS argument+  -> TransformContext   -> NormalizeSession Term-reduceAppend inScope n m aTy lArg rArg = do+reduceAppend 0 _ _   _    rArg _ = changed rArg+reduceAppend _ 0 _   lArg _    _ = changed lArg+reduceAppend n m aTy lArg rArg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm lArg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do uniqs0 <- Lens.use uniqSupply-           let (uniqs1,(vars,elems)) = second (second concat . unzip)+           let (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                      $ extractElems uniqs0 inScope consCon aTy                                          'C' n lArg-               lbody        = appendToVec consCon aTy rArg (n+m) vars-               lb           = Letrec (init elems) lbody+               lbody        = appendToVec consCon aTy rArg (n+m) (NE.toList vars)+               lb           = Letrec (NE.init elems) lbody            uniqSupply Lens..= uniqs1            changed lb     go _ ty = error $ $(curLoc) ++ "reduceAppend: argument does not have a vector type: " ++ showPpr ty@@ -887,22 +909,23 @@ -- | Replace an application of the @Clash.Sized.Vector.unconcat@ primitive on -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.unconcat@-reduceUnconcat :: InScopeSet-               -> PrimInfo -- ^ Unconcat primitive info+reduceUnconcat :: PrimInfo -- ^ Unconcat primitive info                -> Integer  -- ^ Length of the result vector                -> Integer  -- ^ Length of the elements of the result vector                -> Type -- ^ Element type+               -> Term -- ^ Length of the result vector (as a KnownNat)                -> Term -- ^ SNat "Length of the elements of the result vector"                -> Term -- ^ Argument vector+               -> TransformContext                -> NormalizeSession Term-reduceUnconcat inScope unconcatPrimInfo n m aTy sm arg = do+reduceUnconcat unconcatPrimInfo n m aTy _kn sm arg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+      | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [nilCon,consCon] <- tyConDataCons vecTc       , let innerVecTy = mkTyConApp vecTcNm [LitTy (NumTy m), aTy]@@ -917,17 +940,19 @@           uniqs0 <- Lens.use uniqSupply           let             (uniqs1,(vars,headsAndTails)) =-              second (second concat . unzip)+              second (second sconcat . NE.unzip)                      (extractElems uniqs0 inScope consCon aTy 'U' (n*m) arg)             -- Build a vector out of the first m elements-            mvec = mkVec nilCon consCon aTy m (take (fromInteger m) vars)+            mvec = mkVec nilCon consCon aTy m (NE.take (fromInteger m) vars)             -- Get the vector representing the next ((n-1)*m) elements             -- N.B. `extractElems (xs :: Vec 2 a)` creates:             -- x0  = head xs             -- xs0 = tail xs             -- x1  = head xs0             -- xs1 = tail xs0-            (lbs,head -> nextVec) = splitAt ((2*fromInteger m)-1) headsAndTails+            (lbs,nextVec) = case NE.splitAt ((2*fromInteger m)-1) headsAndTails of+                              (xs,y:_) -> (xs,y)+                              _ -> error "impossible"             -- recursively call unconcat             nextUnconcat = mkApps (Prim unconcatPrimInfo)                                   [ Right (LitTy (NumTy (n-1)))@@ -952,16 +977,18 @@ reduceTranspose :: Integer  -- ^ Length of the result vector                 -> Integer  -- ^ Length of the elements of the result vector                 -> Type -- ^ Element type+                -> Term -- ^ Lenght of the result vector (as a KnownNat)                 -> Term -- ^ Argument vector+                -> TransformContext                 -> NormalizeSession Term-reduceTranspose n 0 aTy arg = do+reduceTranspose n 0 aTy _kn arg _ctx = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+      | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [nilCon,consCon] <- tyConDataCons vecTc       = let nilVec           = mkVec nilCon consCon aTy 0 []@@ -970,20 +997,22 @@         in  changed retVec     go _ ty = error $ $(curLoc) ++ "reduceTranspose: argument does not have a vector type: " ++ showPpr ty -reduceTranspose _ _ _ _ = error $ $(curLoc) ++ "reduceTranspose: unimplemented"+reduceTranspose _ _ _ _ _ _ = error $ $(curLoc) ++ "reduceTranspose: unimplemented"  reduceReplicate :: Integer                 -> Type                 -> Type                 -> Term+                -> Term+                -> TransformContext                 -> NormalizeSession Term-reduceReplicate n aTy eTy arg = do+reduceReplicate n aTy eTy _sn arg _ctx = do     tcm <- Lens.view tcCache     go tcm eTy   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+      | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [nilCon,consCon] <- tyConDataCons vecTc       = let retVec = mkVec nilCon consCon aTy n (replicate (fromInteger n) arg)@@ -995,21 +1024,23 @@ -- TODO: Clash will eliminate one-by-one if the index turned out to be literal. -- TODO: It would of course be best to not create the cases in the first place! reduceReplace_int-  :: InScopeSet-  -> Integer-  -- ^ Size of vector+  :: Integer+  -- ^ Size of vector, must be positive   -> Type   -- ^ Type of vector element   -> Type   -- ^ Type of vector   -> Term+  -- ^ Size of vector (as a KnownNat)+  -> Term   -- ^ Vector   -> Term   -- ^ Index   -> Term   -- ^ Element+  -> TransformContext   -> NormalizeSession Term-reduceReplace_int is0 n aTy vTy v i newA = do+reduceReplace_int n aTy vTy _kn v i newA (TransformContext is0 _ctx) = do   tcm <- Lens.view tcCache   go tcm vTy  where@@ -1040,17 +1071,18 @@     -> Term   replace_intElement tcm iDc iTy oldA elIndex = case0    where-    (Just boolTc) = lookupUniqMap (getKey boolTyConKey) tcm-    [_,trueDc]    = tyConDataCons boolTc-    eqInt         = eqIntPrim iTy (mkTyConApp (tyConName boolTc) [])-    case0         = Case (mkApps eqInt [Left i-                                       ,Left (mkApps (Data iDc)-                                             [Left (Literal (IntLiteral elIndex))])-                                       ])-                         aTy-                         [(DefaultPat, oldA)-                         ,(DataPat trueDc [] [], newA)-                         ]+    case0 = Maybe.fromMaybe (error "replace_intElement: faild to build Truce DC") $ do+      boolTc <- UniqMap.lookup (getKey boolTyConKey) tcm+      [_,trueDc] <- pure (tyConDataCons boolTc)+      let eqInt = eqIntPrim iTy (mkTyConApp (tyConName boolTc) [])+      return (Case (mkApps eqInt [ Left i+                                 , Left (mkApps (Data iDc)+                                                [Left (Literal (IntLiteral elIndex))])+                                 ])+                   aTy+                   [ (DefaultPat, oldA)+                   , (DataPat trueDc [] [], newA)+                   ])    -- Equality on lifted Int that returns a Bool   eqIntPrim@@ -1067,19 +1099,20 @@    go tcm (coreView1 tcm -> Just ty') = go tcm ty'   go tcm (tyView -> TyConApp vecTcNm _)-    | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+    | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"     , [nilCon,consCon] <- tyConDataCons vecTc     = do       -- Get data constructors of 'Int'       uniqs0                   <- Lens.use uniqSupply       let iTy                   = inferCoreTypeOf tcm i-          (TyConApp iTcNm _)    = tyView iTy-          (Just iTc)            = lookupUniqMap iTcNm tcm-          [iDc]                 = tyConDataCons iTc+          iDc = Maybe.fromMaybe (error "replace_intElement: faild to build Int DC") $ do+            (TyConApp iTcNm _) <- pure (tyView iTy)+            iTc <- UniqMap.lookup iTcNm tcm+            Maybe.listToMaybe (tyConDataCons iTc)        -- Get elements from vector-          (uniqs1,(vars,elems)) = second (second concat . unzip)+          (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                 $ extractElems                                     uniqs0                                     is0@@ -1090,9 +1123,9 @@                                     v        -- Replace every element with (if i == elIndex then newA else oldA)-      let replacedEls = zipWith (replace_intElement tcm iDc iTy) vars [0..]+      let replacedEls = zipWith (replace_intElement tcm iDc iTy) (NE.toList vars) [0..]           lbody       = mkVec nilCon consCon aTy n replacedEls-          lb          = Letrec (init elems) lbody+          lb          = Letrec (NE.init elems) lbody       uniqSupply Lens..= uniqs1       changed lb   go _ ty = error $ $(curLoc) ++ "reduceReplace_int: argument does not have "@@ -1103,17 +1136,19 @@ -- TODO: Clash will eliminate one-by-one if the index turned out to be literal. -- TODO: It would of course be best to not create the cases in the first place! reduceIndex_int-  :: InScopeSet-  -> Integer-  -- ^ Size of vector+  :: Integer+  -- ^ Size of vector, must be positive   -> Type   -- ^ Type of vector element   -> Term+  -- ^ Size of vector (as a KnownNat)+  -> Term   -- ^ Vector   -> Term   -- ^ Index+  -> TransformContext   -> NormalizeSession Term-reduceIndex_int is0 n aTy v i = do+reduceIndex_int n aTy _kn v i (TransformContext is0 _ctx) = do   tcm <- Lens.view tcCache   let vTy = inferCoreTypeOf tcm v   go tcm vTy@@ -1145,17 +1180,18 @@     -> Term   index_intElement tcm iDc iTy (cur,elIndex) next = case0    where-    (Just boolTc) = lookupUniqMap (getKey boolTyConKey) tcm-    [_,trueDc]    = tyConDataCons boolTc-    eqInt         = eqIntPrim iTy (mkTyConApp (tyConName boolTc) [])-    case0         = Case (mkApps eqInt [Left i-                                       ,Left (mkApps (Data iDc)-                                             [Left (Literal (IntLiteral elIndex))])-                                       ])-                         aTy-                         [(DefaultPat, next)-                         ,(DataPat trueDc [] [], cur)-                         ]+    case0 = Maybe.fromMaybe (error "reduceIndex_int: faild to build True DC") $ do+      boolTc <- UniqMap.lookup (getKey boolTyConKey) tcm+      [_,trueDc] <- pure (tyConDataCons boolTc)+      let eqInt = eqIntPrim iTy (mkTyConApp (tyConName boolTc) [])+      return (Case (mkApps eqInt [ Left i+                                 , Left (mkApps (Data iDc)+                                        [Left (Literal (IntLiteral elIndex))])+                                 ])+                   aTy+                   [ (DefaultPat, next)+                   , (DataPat trueDc [] [], cur)+                   ])    -- Equality on lifted Int that returns a Bool   eqIntPrim@@ -1172,19 +1208,20 @@    go tcm (coreView1 tcm -> Just ty') = go tcm ty'   go tcm (tyView -> TyConApp vecTcNm _)-    | (Just vecTc)     <- lookupUniqMap vecTcNm tcm+    | (Just vecTc)     <- UniqMap.lookup vecTcNm tcm     , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"     , [_nilCon,consCon] <- tyConDataCons vecTc     = do       -- Get data constructors of 'Int'       uniqs0                   <- Lens.use uniqSupply       let iTy                   = inferCoreTypeOf tcm i-          (TyConApp iTcNm _)    = tyView iTy-          (Just iTc)            = lookupUniqMap iTcNm tcm-          [iDc]                 = tyConDataCons iTc+          iDc = Maybe.fromMaybe (error "reduceIndex_int: faild to build Int DC") $ do+              (TyConApp iTcNm _) <- pure (tyView iTy)+              iTc <- UniqMap.lookup iTcNm tcm+              Maybe.listToMaybe (tyConDataCons iTc)        -- Get elements from vector-          (uniqs1,(vars,elems)) = second (second concat . unzip)+          (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                 $ extractElems                                     uniqs0                                     is0@@ -1197,8 +1234,8 @@       -- Build a right-biased tree of case-expressions       let indexed = foldr (index_intElement tcm iDc iTy)                               (TyApp (Prim NP.undefined) aTy)-                              (zip vars [0..])-          lb      = Letrec (init elems) indexed+                              (zip (NE.toList vars) [0..])+          lb      = Letrec (NE.init elems) indexed       uniqSupply Lens..= uniqs1       changed lb   go _ ty = error $ $(curLoc) ++ "indexReplace_int: argument does not have "@@ -1208,33 +1245,36 @@ -- vectors of a known length @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.Vector.dtfold@ reduceDTFold-  :: InScopeSet-  -> Integer  -- ^ Length of the vector+  :: Integer  -- ^ Length of the vector   -> Type     -- ^ Element type of the argument vector+  -> Term     -- ^ Length of the vector (as a KnownNat)+  -> Term     -- ^ The motive   -> Term     -- ^ Function to convert elements with   -> Term     -- ^ Function to combine branches with   -> Term     -- ^ The vector to fold+  -> TransformContext   -> NormalizeSession Term-reduceDTFold inScope n aTy lrFun brFun arg = do+reduceDTFold n aTy _kn _motive lrFun brFun arg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp vecTcNm _)-      | (Just vecTc) <- lookupUniqMap vecTcNm tcm+      | (Just vecTc) <- UniqMap.lookup vecTcNm tcm       , nameOcc vecTcNm == "Clash.Sized.Vector.Vec"       , [_,consCon]  <- tyConDataCons vecTc       = do uniqs0 <- Lens.use uniqSupply-           let (uniqs1,(vars,elems)) = second (second concat . unzip)+           let (uniqs1,(vars,elems)) = second (second sconcat . NE.unzip)                                      $ extractElems uniqs0 inScope consCon aTy                                          'T' (2^n) arg-               (_ltv:Right snTy:_,_) = splitFunForallTy (inferCoreTypeOf tcm brFun)-               (TyConApp snatTcNm _) = tyView snTy-               (Just snatTc)         = lookupUniqMap snatTcNm tcm-               [snatDc]              = tyConDataCons snatTc-               lbody = doFold (buildSNat snatDc) (n-1) vars-               lb    = Letrec (init elems) lbody+               snatDc = Maybe.fromMaybe (error "reduceDTFold: faild to build SNat") $ do+                  (_ltv:Right snTy:_,_) <- pure (splitFunForallTy (inferCoreTypeOf tcm brFun))+                  (TyConApp snatTcNm _) <- pure (tyView snTy)+                  snatTc <- UniqMap.lookup snatTcNm tcm+                  Maybe.listToMaybe (tyConDataCons snatTc)+               lbody = doFold (buildSNat snatDc) (n-1) (NE.toList vars)+               lb = Letrec (NE.init elems) lbody            uniqSupply Lens..= uniqs1            changed lb     go _ ty = error $ $(curLoc) ++ "reduceDTFold: argument does not have a vector type: " ++ showPpr ty@@ -1256,31 +1296,34 @@ -- trees of a known depth @n@, by the fully unrolled recursive "definition" -- of @Clash.Sized.RTree.tdfold@ reduceTFold-  :: InScopeSet-  -> Integer -- ^ Depth of the tree+  :: Integer -- ^ Depth of the tree   -> Type    -- ^ Element type of the argument tree+  -> Term    -- ^ Depth of the tree (as a KnownNat)+  -> Term    -- ^ The motive   -> Term    -- ^ Function to convert elements with   -> Term    -- ^ Function to combine branches with   -> Term    -- ^ The tree to fold+  -> TransformContext   -> NormalizeSession Term-reduceTFold inScope n aTy lrFun brFun arg = do+reduceTFold n aTy _kn _motive lrFun brFun arg (TransformContext inScope _ctx) = do     tcm <- Lens.view tcCache     let ty = inferCoreTypeOf tcm arg     go tcm ty   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp treeTcNm _)-      | (Just treeTc) <- lookupUniqMap treeTcNm tcm+      | (Just treeTc) <- UniqMap.lookup treeTcNm tcm       , nameOcc treeTcNm == "Clash.Sized.RTree.RTree"       , [lrCon,brCon] <- tyConDataCons treeTc       = do uniqs0 <- Lens.use uniqSupply            let (uniqs1,(vars,elems)) = extractTElems uniqs0 inScope lrCon brCon aTy 'T' n arg-               (_ltv:Right snTy:_,_) = splitFunForallTy (inferCoreTypeOf tcm brFun)-               (TyConApp snatTcNm _) = tyView snTy-               (Just snatTc)         = lookupUniqMap snatTcNm tcm-               [snatDc]              = tyConDataCons snatTc+               snatDc = Maybe.fromMaybe (error "reduceTFold: faild to build SNat") $ do+                  (_ltv:Right snTy:_,_) <- pure (splitFunForallTy (inferCoreTypeOf tcm brFun))+                  (TyConApp snatTcNm _) <- pure (tyView snTy)+                  snatTc <- UniqMap.lookup snatTcNm tcm+                  Maybe.listToMaybe (tyConDataCons snatTc)                lbody = doFold (buildSNat snatDc) (n-1) vars-               lb    = Letrec elems lbody+               lb = (Letrec elems lbody)            uniqSupply Lens..= uniqs1            changed lb     go _ ty = error $ $(curLoc) ++ "reduceTFold: argument does not have a tree type: " ++ showPpr ty@@ -1300,15 +1343,17 @@ reduceTReplicate :: Integer -- ^ Depth of the tree                  -> Type    -- ^ Element type                  -> Type    -- ^ Result type+                 -> Term    -- ^ Depth of the tree (as an SNat)                  -> Term    -- ^ Element+                 -> TransformContext                  -> NormalizeSession Term-reduceTReplicate n aTy eTy arg = do+reduceTReplicate n aTy eTy _sn arg _ctx = do     tcm <- Lens.view tcCache     go tcm eTy   where     go tcm (coreView1 tcm -> Just ty') = go tcm ty'     go tcm (tyView -> TyConApp treeTcNm _)-      | (Just treeTc) <- lookupUniqMap treeTcNm tcm+      | (Just treeTc) <- UniqMap.lookup treeTcNm tcm       , nameOcc treeTcNm == "Clash.Sized.RTree.RTree"       , [lrCon,brCon] <- tyConDataCons treeTc       = let retVec = mkRTree lrCon brCon aTy n (replicate (2^n) arg)
src/Clash/Normalize/Transformations/Case.hs view
@@ -273,7 +273,8 @@       -- WHNF of subject is _|_, in the form of `absentError`: that means that       -- the entire case-expression is evaluates to _|_       (Prim pInfo,_:msgOrCallStack:_,ticks)-        | primName pInfo == "Control.Exception.Base.absentError" ->+        | primName pInfo `elem` ["Control.Exception.Base.absentError"+                                ,"GHC.Prim.Panic.absentError"] ->         let e1 = mkApps (mkTicks (Prim pInfo) ticks)                         [Right ty,msgOrCallStack]         in  changed e1@@ -579,18 +580,21 @@ {-# SCC collectFlat #-}  collectEqArgs :: Term -> Maybe (Term,Term)-collectEqArgs (collectArgsTicks -> (Prim p, args, ticks))+collectEqArgs f@(collectArgsTicks -> (Prim p, args, ticks))   | nm == Text.showt 'BV.eq#-    = let [_,_,Left scrut,Left val] = args-      in Just (mkTicks scrut ticks,val)+    = case args of+        [_,_,Left scrut,Left val] -> Just (mkTicks scrut ticks,val)+        _ -> error ("collectEqArgs: BV.eq expects 4 arguments, but got: " <> showPpr f)   | nm == Text.showt 'I.eq#  ||     nm == Text.showt 'S.eq# ||     nm == Text.showt 'U.eq#-    = let [_,Left scrut,Left val] = args-      in Just (mkTicks scrut ticks,val)+    = case args of+        [_,Left scrut,Left val] -> Just (mkTicks scrut ticks,val)+        _ -> error (show nm <> " expects 3 arguments, but got: " <> showPpr f)   | nm == "GHC.Classes.eqInt"-    = let [Left scrut,Left val] = args-      in  Just (mkTicks scrut ticks,val)+    = case args of+        [Left scrut,Left val] -> Just (mkTicks scrut ticks,val)+        _ -> error ("eqInt expects 2 arguments, but got: " <> showPpr f)  where   nm = primName p @@ -644,8 +648,8 @@       | otherwise       -> return e -caseOneAlt (Case _ _ alts@((pat,alt):_:_))-  | all ((== alt) . snd) (tail alts)+caseOneAlt (Case _ _ ((pat,alt):alts@(_:_)))+  | all ((== alt) . snd) alts   , (tvs,xs) <- patIds pat   , (coerce tvs ++ coerce xs) `localVarsDoNotOccurIn` alt   = changed alt
src/Clash/Normalize/Transformations/DEC.hs view
@@ -57,7 +57,9 @@ import qualified Data.Text as Text import GHC.Stack (HasCallStack) -#if MIN_VERSION_ghc(8,10,0)+#if MIN_VERSION_ghc(9,6,0)+import GHC.Core.Make (chunkify, mkChunkified)+#elif MIN_VERSION_ghc(8,10,0) import GHC.Hs.Utils (chunkify, mkChunkified) #else import HsUtils (chunkify, mkChunkified)@@ -88,13 +90,13 @@ import Clash.Core.VarEnv   ( InScopeSet, elemInScopeSet, extendInScopeSet, extendInScopeSetList   , notElemInScopeSet, unionInScope)+import qualified Clash.Data.UniqMap as UniqMap import Clash.Normalize.Transformations.Letrec (deadCode) import Clash.Normalize.Types (NormRewrite, NormalizeSession) import Clash.Rewrite.Combinators (bottomupR) import Clash.Rewrite.Types import Clash.Rewrite.Util (changed, isUntranslatableType) import Clash.Rewrite.WorkFree (isConstant)-import Clash.Unique (lookupUniqMap) import Clash.Util (MonadUnique, curLoc)  -- | This transformation lifts applications of global binders out of@@ -301,7 +303,7 @@     let (ids1,ids2) = splitSupply ids     uniqSupply Lens..= ids2     gh <- Lens.use globalHeap-    let eval = (Lens.view Lens._3) . whnf' evaluate bndrs tcm gh ids1 is0 False+    let eval = (Lens.view Lens._3) . whnf' evaluate bndrs mempty tcm gh ids1 is0 False     let eTy  = inferCoreTypeOf tcm e     untran <- isUntranslatableType False eTy     case untran of@@ -478,7 +480,8 @@     let argss    = Foldable.toList cs         argssT   = zip [0..] (List.transpose argss)         (sharedT,distinctT) = List.partition (areShared tcm inScope . fmap (first stripTicks) . snd) argssT-        shared   = map (second head) sharedT+        -- TODO: find a better solution than "maybe undefined fst . uncons"+        shared   = map (second (maybe (error "impossible") fst . List.uncons)) sharedT         distinct = map (Either.lefts) (List.transpose (map snd distinctT))         cs'      = fmap (zip [0..]) cs         cs''     = removeEmpty@@ -618,11 +621,12 @@  -- | Lookup the TyConName and DataCon for a tuple of size n findTup :: TyConMap -> IntMap TyConName -> Int -> (TyConName,DataCon)-findTup tcm tupTcm n = (tupTcNm,tupDc)-  where-    tupTcNm      = Maybe.fromMaybe (error $ $curLoc ++ "Can't find " ++ show n ++ "-tuple") $ IntMap.lookup n tupTcm-    Just tupTc   = lookupUniqMap tupTcNm tcm-    [tupDc]      = tyConDataCons tupTc+findTup tcm tupTcm n =+  Maybe.fromMaybe (error ("Cannot build " <> show n <> "-tuble")) $ do+    tupTcNm <- IntMap.lookup n tupTcm+    tupTc <- UniqMap.lookup tupTcNm tcm+    tupDc <- Maybe.listToMaybe (tyConDataCons tupTc)+    return (tupTcNm,tupDc)  mkBigTupTm :: TyConMap -> IntMap TyConName -> [(Type,Term)] -> Term mkBigTupTm tcm tupTcm args = snd $ mkBigTup tcm tupTcm args@@ -763,7 +767,7 @@     allNonPow2  = all (not . termIsPow2) lArgs     tailNonPow2 = case lArgs of                     [] -> True-                    _  -> all (not . termIsPow2) (tail lArgs)+                    _  -> all (not . termIsPow2) (drop 1 lArgs)     lastNotPow2 = case lArgs of                     [] -> True                     _  -> not (termIsPow2 (last lArgs))
src/Clash/Normalize/Transformations/EtaExpand.hs view
@@ -71,7 +71,7 @@   return $ Lam bndr e'  etaExpansionTL (TransformContext is0 ctx) (Let (NonRec i x) e) = do-  let ctx' = TransformContext (extendInScopeSet is0 i) (LetBody [i] : ctx)+  let ctx' = TransformContext (extendInScopeSet is0 i) (LetBody [(i,x)] : ctx)   e' <- etaExpansionTL ctx' e   case stripLambda e' of     (bs@(_:_),e2) -> do@@ -81,7 +81,7 @@  etaExpansionTL (TransformContext is0 ctx) (Let (Rec xes) e) = do   let bndrs = map fst xes-      ctx' = TransformContext (extendInScopeSetList is0 bndrs) (LetBody bndrs : ctx)+      ctx' = TransformContext (extendInScopeSetList is0 bndrs) (LetBody xes : ctx)   e' <- etaExpansionTL ctx' e   case stripLambda e' of     (bs@(_:_),e2) -> do
src/Clash/Normalize/Transformations/Inline.hs view
@@ -33,8 +33,9 @@  import qualified Control.Lens as Lens import qualified Control.Monad as Monad+import Control.Monad ((>=>)) import Control.Monad.Trans.Maybe (MaybeT(..))-import Control.Monad.Writer ((>=>),lift,listen)+import Control.Monad.Writer (lift,listen) import Data.Default (Default(..)) import Data.Either  (lefts) import qualified Data.HashMap.Lazy as HashMap@@ -44,12 +45,7 @@ import qualified Data.Text as Text import qualified Data.Text.Extra as Text import GHC.Stack (HasCallStack)--#if MIN_VERSION_ghc(9,0,0)-import GHC.Types.Basic             (InlineSpec (..))-#else-import BasicTypes                  (InlineSpec (..))-#endif+import GHC.BasicTypes.Extra (isNoInline)  import qualified Clash.Explicit.SimIO as SimIO import qualified Clash.Sized.Internal.BitVector as BV (Bit(Bit), BitVector(BV))@@ -464,12 +460,16 @@   case r of     (e1, Monoid.getAny -> True) ->       return e1-    (~(Case subj0 typ alts), _) -> do+    (e1, _) -> do       -- If a term _in_ the subject triggers 'inlineNonRepWorker', inline and       -- propagate might eliminate this case. We therefore don't explore the       -- alternatives. Note that this makes it substantially different from a       -- 'topdownSucR' transformation.       let+        (subj0,typ,alts) = case e1 of+          Case s t a -> (s,t,a)+          _ -> error ("internal error, inlineNonRep triggered on a non-Case:" <>+                      showPpr e1)         TransformContext inScope ctx1 = ctx0         ctx2 = TransformContext inScope (CaseScrut:ctx1) @@ -602,7 +602,7 @@         -- Don't inline recursive expressions         Just b -> do           isRecBndr <- isRecursiveBndr f-          if not isRecBndr && bindingSpec b /= NoInline && termSize (bindingTerm b) < sizeLimit+          if not isRecBndr && not (isNoInline (bindingSpec b)) && termSize (bindingTerm b) < sizeLimit              then do                let tm = mkTicks (bindingTerm b) (mkInlineTick f : ticks)                changed $ mkApps tm args
src/Clash/Normalize/Transformations/Letrec.hs view
@@ -33,6 +33,7 @@ import Data.List ((\\)) import qualified Data.List as List import qualified Data.List.Extra as List+import Data.Maybe (fromMaybe) import qualified Data.Monoid as Monoid (Any(..)) import qualified Data.Text as Text import qualified Data.Text.Extra as Text@@ -62,6 +63,7 @@ import Clash.Core.VarEnv   ( InScopeSet, elemInScopeSet, emptyVarEnv, extendInScopeSetList, lookupVarEnv   , unionVarEnvWith, unitVarEnv, mkVarSet)+import qualified Clash.Data.UniqMap as UniqMap import Clash.Netlist.BlackBox.Types () import Clash.Netlist.BlackBox.Util (getUsedArguments) import Clash.Netlist.Util (splitNormalized)@@ -74,7 +76,6 @@ import Clash.Rewrite.Util   (changed, isFromInt, isUntranslatable, mkTmBinderFor, removeUnusedBinders, setChanged) import Clash.Rewrite.WorkFree-import Clash.Unique (lookupUniqMap)  {- [Note: Name re-creation] The names of heap bound variables are safely generate with mkUniqSystemId in@@ -160,10 +161,11 @@         | (con, _) <- collectArgs nil         , not (isCon con)         -> let eTy = inferCoreTypeOf tcm e-               (TyConApp vecTcNm _) = tyView eTy-               (Just vecTc) = lookupUniqMap vecTcNm tcm-               [nilCon,consCon] = tyConDataCons vecTc-               v = mkTicks (mkVec nilCon consCon aTy 1 [a]) ticks+               v = fromMaybe (error "removeUnusedExpr: failed to create Vec DCs") $ do+                  (TyConApp vecTcNm _) <- pure (tyView eTy)+                  vecTc <- UniqMap.lookup vecTcNm tcm+                  [nilCon,consCon] <- pure (tyConDataCons vecTc)+                  return (mkTicks (mkVec nilCon consCon aTy 1 [a]) ticks)            in  changed v       _ -> return e @@ -181,10 +183,11 @@ flattenLet ctx@(TransformContext is0 _) (Letrec binds0 body0@Letrec{}) = do   -- deshadow binds1, so binds0 and binds1 don't conflict when merged   let is1 = extendInScopeSetList is0 (fmap fst binds0)-      Letrec binds1 body1 = deShadowTerm is1 body0--  setChanged-  flattenLet ctx{tfInScope=is1} (Letrec (binds0 <> binds1) body1)+  case deShadowTerm is1 body0 of+    Letrec binds1 body1 -> do+      setChanged+      flattenLet ctx{tfInScope=is1} (Letrec (binds0 <> binds1) body1)+    _ -> error "internal error"  flattenLet (TransformContext is0 _) (Letrec binds body) = do   let is1 = extendInScopeSetList is0 (map fst binds)@@ -222,8 +225,10 @@             -- This is much better than blindly calling freshenTm, and saves             -- almost 30% run-time of the normalization phase on some examples.             if any (`elemInScopeSet` isN) bs1 then-              let Letrec bindsN bodyN = deShadowTerm isN (Letrec binds1 body1)-              in  (bindsN,bodyN,extendInScopeSetList isN (map fst bindsN))+              case deShadowTerm isN (Letrec binds1 body1) of+                Letrec bindsN bodyN ->+                  (bindsN,bodyN,extendInScopeSetList isN (map fst bindsN))+                _ -> error "internal error"             else               (binds1,body1,extendInScopeSetList isN bs1)       let bodyOccs = Lens.foldMapByOf@@ -398,8 +403,8 @@ -- On the two examples that were tested, Reducer and PipelinesViaFolds, this new -- version of CSE removed the same amount of let-binders. simpleCSE :: HasCallStack => NormRewrite-simpleCSE (TransformContext is0 _) term@Letrec{} = do-  let Letrec bndrs body = inverseTopSortLetBindings term+simpleCSE (TransformContext is0 _) term@(Letrec bndrsX body) = do+  let bndrs = inverseTopSortLetBindings bndrsX   let is1 = extendInScopeSetList is0 (map fst bndrs)   ((subst,bndrs1), change) <- listen $ reduceBinders (mkSubst is1) [] bndrs   -- TODO: check whether a substitution over the body is enough, the reason I'm
src/Clash/Normalize/Transformations/Reduce.hs view
@@ -9,6 +9,7 @@   Transformations for compile-time reduction of expressions / primitives. -} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-}  module Clash.Normalize.Transformations.Reduce@@ -23,25 +24,28 @@ import qualified Data.List as List import qualified Data.List.Extra as List import qualified Data.Maybe as Maybe+import Data.Maybe (fromMaybe, listToMaybe) import GHC.Stack (HasCallStack)  import Clash.Core.FreeVars (typeFreeVars) import Clash.Core.HasType import Clash.Core.Name (nameOcc)+import Clash.Core.Pretty (showPpr) import Clash.Core.Subst (Subst, extendIdSubst, substTm) import Clash.Core.Term-  ( LetBinding, PrimInfo(..), Term(..), TickInfo(..), collectArgs-  , collectArgsTicks, mkApps, mkTicks)+  ( CoreContext(..), LetBinding, PrimInfo(..), Term(..), TickInfo(..), collectArgs+  , collectArgsTicks, mkApps, mkTicks, mkTmApps) import Clash.Core.TyCon (tyConDataCons)-import Clash.Core.Type (TypeView(..), mkTyConApp, tyView)-import Clash.Core.Util (mkVec, shouldSplit, tyNatSize)+import Clash.Core.Type (Type, TypeView(..), mkTyConApp, splitFunForallTy, tyView)+import Clash.Core.Util (mkVec, shouldSplit, tyNatSize, mkInternalVar)+import Clash.Core.VarEnv (extendInScopeSet)+import qualified Clash.Data.UniqMap as UniqMap import Clash.Normalize.PrimitiveReductions import Clash.Normalize.Primitives (removedArg) import Clash.Normalize.Types (NormRewrite, NormalizeSession) import Clash.Normalize.Util (shouldReduce) import Clash.Rewrite.Types (TransformContext(..), tcCache, normalizeUltra) import Clash.Rewrite.Util (changed, isUntranslatableType, setChanged, whnfRW)-import Clash.Unique (lookupUniqMap)  -- | XXX: is given inverse topologically sorted binders, but returns -- topologically sorted binders@@ -146,24 +150,26 @@ -- -- See https://github.com/clash-lang/clash-compiler/issues/1606 reduceNonRepPrim :: HasCallStack => NormRewrite-reduceNonRepPrim c@(TransformContext is0 ctx) e@(App _ _) | (Prim p, args, ticks) <- collectArgsTicks e = do+reduceNonRepPrim c@(TransformContext _ ctx) e@(App _ _) | (Prim p, args, ticks) <- collectArgsTicks e = do   tcm <- Lens.view tcCache   ultra <- Lens.view normalizeUltra   let eTy = inferCoreTypeOf tcm e-  case tyView eTy of+  let resTy = snd (splitFunForallTy eTy)+  case tyView resTy of     (TyConApp vecTcNm@(nameOcc -> "Clash.Sized.Vector.Vec")               [runExcept . tyNatSize tcm -> Right 0, aTy]) -> do-      let (Just vecTc) = lookupUniqMap vecTcNm tcm-          [nilCon,consCon] = tyConDataCons vecTc-          nilE = mkVec nilCon consCon aTy 0 []+      let nilE = fromMaybe (error "reduceNonRepPrim: unable to create Vec DCs") $ do+            vecTc <- UniqMap.lookup vecTcNm tcm+            [nilCon,consCon] <- pure (tyConDataCons vecTc)+            return (mkVec nilCon consCon aTy 0 [])       changed (mkTicks nilE ticks)     tv -> let argLen = length args in case primName p of-      "Clash.Sized.Vector.zipWith" | argLen == 7 -> do-        let [lhsElTy,rhsElty,resElTy,nTy] = Either.rights args-            TyConApp vecTcNm _ = tv-            lhsTy = mkTyConApp vecTcNm [nTy,lhsElTy]-            rhsTy = mkTyConApp vecTcNm [nTy,rhsElty]-        case runExcept (tyNatSize tcm nTy) of+      "Clash.Sized.Vector.zipWith"+        | (tmArgs,[lhsElTy,rhsElty,resElTy,nTy]) <- Either.partitionEithers args+        , TyConApp vecTcNm _ <- tv+        , let lhsTy = mkTyConApp vecTcNm [nTy,lhsElTy]+        , let rhsTy = mkTyConApp vecTcNm [nTy,rhsElty]+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n < 2)                                  , shouldReduce ctx@@ -171,18 +177,20 @@                                         [lhsElTy,rhsElty,resElTy]                                  -- Note [Unroll shouldSplit types]                                  , pure (any (Maybe.isJust . shouldSplit tcm)-                                             [lhsTy,rhsTy,eTy]) ]+                                             [lhsTy,rhsTy,resTy]) ]             if shouldReduce1-               then let [fun,lhsArg,rhsArg] = Either.lefts args-                    in  (`mkTicks` ticks) <$>-                        reduceZipWith c p n lhsElTy rhsElty resElTy fun lhsArg rhsArg+               then abstractOverMissingArgs ticks tmArgs eTy c+                      (reduceZipWith p n lhsElTy rhsElty resElTy)                else return e           _ -> return e-      "Clash.Sized.Vector.map" | argLen == 5 -> do-        let [argElTy,resElTy,nTy] = Either.rights args-            TyConApp vecTcNm _ = tv-            argTy = mkTyConApp vecTcNm [nTy,argElTy]-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 4+        -> error ("reduceNonRepPrim: zipWith bad args" <> showPpr e)++      "Clash.Sized.Vector.map"+        | (tmArgs,[argElTy,resElTy,nTy]) <- Either.partitionEithers args+        , TyConApp vecTcNm _ <- tv+        , let argTy = mkTyConApp vecTcNm [nTy,argElTy]+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n < 2 )                                  , shouldReduce ctx@@ -190,23 +198,27 @@                                         [argElTy,resElTy]                                  -- Note [Unroll shouldSplit types]                                  , pure (any (Maybe.isJust . shouldSplit tcm)-                                             [argTy,eTy]) ]+                                             [argTy,resTy]) ]             if shouldReduce1-               then let [fun,arg] = Either.lefts args-                    in  (`mkTicks` ticks) <$> reduceMap c p n argElTy resElTy fun arg+               then abstractOverMissingArgs ticks tmArgs eTy c+                      (reduceMap p n argElTy resElTy)                else return e           _ -> return e-      "Clash.Sized.Vector.traverse#" | argLen == 7 ->-        let [aTy,fTy,bTy,nTy] = Either.rights args-        in  case runExcept (tyNatSize tcm nTy) of-          Right n ->-            let [dict,fun,arg] = Either.lefts args-            in  (`mkTicks` ticks) <$> reduceTraverse c n aTy fTy bTy dict fun arg+        | argLen >= 3+        -> error ("reduceNonRepPrim: map bad args" <> showPpr e)++      "Clash.Sized.Vector.traverse#"+        | (tmArgs,[aTy,fTy,bTy,nTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of+          Right n -> abstractOverMissingArgs ticks tmArgs eTy c (reduceTraverse n aTy fTy bTy)           _ -> return e-      "Clash.Sized.Vector.fold" | argLen == 4 -> do-        let ([fun,arg],[nTy,aTy]) = Either.partitionEithers args-            argTy = inferCoreTypeOf tcm arg-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 4+        -> error ("reduceNonRepPrim: traverse# bad args" <> showPpr e)++      "Clash.Sized.Vector.fold"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        , (_:Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,aTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n == 0)                                  , shouldReduce ctx@@ -214,13 +226,16 @@                                  -- Note [Unroll shouldSplit types]                                  , pure (Maybe.isJust (shouldSplit tcm argTy))]             if shouldReduce1 then-              (`mkTicks` ticks) <$> reduceFold c (n + 1) aTy fun arg+              abstractOverMissingArgs ticks tmArgs eTy c (reduceFold (n + 1) aTy)             else return e           _ -> return e-      "Clash.Sized.Vector.foldr" | argLen == 6 ->-        let ([fun,start,arg],[aTy,bTy,nTy]) = Either.partitionEithers args-            argTy = inferCoreTypeOf tcm arg-        in  case runExcept (tyNatSize tcm nTy) of+        | argLen >= 2+        -> error ("reduceNonRepPrim: fold bad args" <> showPpr e)++      "Clash.Sized.Vector.foldr"+        | (tmArgs,[aTy,bTy,nTy]) <- Either.partitionEithers args+        , (_:_:Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [aTy,bTy,nTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx@@ -228,63 +243,73 @@                                  -- Note [Unroll shouldSplit types]                                  , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1-              then (`mkTicks` ticks) <$> reduceFoldr c p n aTy fun start arg+              then abstractOverMissingArgs ticks tmArgs eTy c (reduceFoldr p n aTy)               else return e           _ -> return e-      "Clash.Sized.Vector.dfold" | argLen == 8 ->-        let ([_kn,_motive,fun,start,arg],[_mTy,nTy,aTy]) = Either.partitionEithers args-        in  case runExcept (tyNatSize tcm nTy) of-          Right n -> (`mkTicks` ticks) <$> reduceDFold is0 n aTy fun start arg+        | argLen >= 3+        -> error ("reduceNonRepPrim: foldr bad args" <> showPpr e)++      "Clash.Sized.Vector.dfold"+        | (tmArgs,[_mTy,nTy,aTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of+          Right n -> abstractOverMissingArgs ticks tmArgs eTy c (reduceDFold n aTy)           _ -> return e-      "Clash.Sized.Vector.++" | argLen == 5 ->-        let [nTy,aTy,mTy] = Either.rights args-            [lArg,rArg]   = Either.lefts args-        in case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy)) of-              (Right n, Right m)-                | n == 0 -> changed rArg-                | m == 0 -> changed lArg-                | otherwise -> do-                    shouldReduce1 <- List.orM [ shouldReduce ctx+        | argLen >= 3+        -> error ("reduceNonRepPrim: dfold bad args" <> showPpr e)++      "Clash.Sized.Vector.++"+        | (tmArgs,[nTy,aTy,mTy]) <- Either.partitionEithers args+        -> case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy)) of+              (Right n, Right m) -> do+                    shouldReduce1 <- List.orM [ pure (n==0)+                                         , pure (m==0)+                                         , shouldReduce ctx                                          , isUntranslatableType_not_poly aTy                                          -- Note [Unroll shouldSplit types]-                                         , pure (Maybe.isJust (shouldSplit tcm eTy)) ]+                                         , pure (Maybe.isJust (shouldSplit tcm resTy)) ]                     if shouldReduce1-                       then (`mkTicks` ticks) <$> reduceAppend is0 n m aTy lArg rArg+                       then abstractOverMissingArgs ticks tmArgs eTy c (reduceAppend n m aTy)                        else return e               _ -> return e-      "Clash.Sized.Vector.head" | argLen == 3 -> do-        let [nTy,aTy] = Either.rights args-            [vArg]    = Either.lefts args-            argTy     = inferCoreTypeOf tcm vArg-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 3+        -> error ("reduceNonRepPrim: ++ bad args" <> showPpr e)++      "Clash.Sized.Vector.head"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        , (Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,aTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  -- Note [Unroll shouldSplit types]                                  , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceHead is0 (n+1) aTy vArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceHead (n+1) aTy)                else return e           _ -> return e-      "Clash.Sized.Vector.tail" | argLen == 3 -> do-        let [nTy,aTy] = Either.rights args-            [vArg]    = Either.lefts args-            argTy     = inferCoreTypeOf tcm vArg-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 2+        -> error ("reduceNonRepPrim: head bad args" <> showPpr e)++      "Clash.Sized.Vector.tail"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        , (Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,aTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  -- Note [Unroll shouldSplit types]                                  , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceTail is0 (n+1) aTy vArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceTail (n+1) aTy)                else return e           _ -> return e-      "Clash.Sized.Vector.last" | argLen == 3 -> do-        let [nTy,aTy] = Either.rights args-            [vArg]    = Either.lefts args-            argTy     = inferCoreTypeOf tcm vArg-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 2+        -> error ("reduceNonRepPrim: tail bad args" <> showPpr e)++      "Clash.Sized.Vector.last"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        , (Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,aTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy@@ -292,27 +317,32 @@                                  , pure (Maybe.isJust (shouldSplit tcm argTy))                                  ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceLast is0 (n+1) aTy vArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceLast (n+1) aTy)                else return e           _ -> return e-      "Clash.Sized.Vector.init" | argLen == 3 -> do-        let [nTy,aTy] = Either.rights args-            [vArg]    = Either.lefts args-            argTy     = inferCoreTypeOf tcm vArg-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 2+        -> error ("reduceNonRepPrim: last bad args" <> showPpr e)++      "Clash.Sized.Vector.init"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        , (Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,aTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  -- Note [Unroll shouldSplit types]                                  , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceInit is0 p n aTy vArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceInit p n aTy)                else return e           _ -> return e-      "Clash.Sized.Vector.unconcat" | argLen == 6 -> do-        let ([_knN,sm,arg],[nTy,mTy,aTy]) = Either.partitionEithers args-            argTy = inferCoreTypeOf tcm arg-        case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy)) of+        | argLen >= 2+        -> error ("reduceNonRepPrim: init bad args" <> showPpr e)++      "Clash.Sized.Vector.unconcat"+        | (tmArgs,[nTy,mTy,aTy]) <- Either.partitionEithers args+        , (_:_:Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,mTy,aTy]))+        -> case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy)) of           (Right n, Right m) -> do             shouldReduce1 <- List.orM [ pure (m==0)                                       , shouldReduce ctx@@ -321,48 +351,59 @@                                       , pure (Maybe.isJust (shouldSplit tcm argTy))                                       ]             if shouldReduce1 then-              (`mkTicks` ticks) <$> reduceUnconcat is0 p n m aTy sm arg+              abstractOverMissingArgs ticks tmArgs eTy c (reduceUnconcat p n m aTy)             else               return e           _ -> return e-      "Clash.Sized.Vector.transpose" | argLen == 5 -> do-        let ([_knN,arg],[mTy,nTy,aTy]) = Either.partitionEithers args-        case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy)) of-          (Right n, Right 0) -> (`mkTicks` ticks) <$> reduceTranspose n 0 aTy arg+        | argLen >= 3+        -> error ("reduceNonRepPrim: unconcat bad args" <> showPpr e)++      "Clash.Sized.Vector.transpose"+        | (tmArgs,[mTy,nTy,aTy]) <- Either.partitionEithers args+        -> case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy)) of+          (Right n, Right 0) -> abstractOverMissingArgs ticks tmArgs eTy c (reduceTranspose n 0 aTy)           _ -> return e-      "Clash.Sized.Vector.replicate" | argLen == 4 -> do-        let ([_sArg,vArg],[nTy,aTy]) = Either.partitionEithers args-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 3+        -> error ("reduceNonRepPrim: transpose bad args" <> showPpr e)++      "Clash.Sized.Vector.replicate"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  -- Note [Unroll shouldSplit types]-                                 , pure (Maybe.isJust (shouldSplit tcm eTy))+                                 , pure (Maybe.isJust (shouldSplit tcm resTy))                                  ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceReplicate n aTy eTy vArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceReplicate n aTy resTy)                else return e           _ -> return e+        | argLen >= 2+        -> error ("reduceNonRepPrim: replicate bad args" <> showPpr e)+        -- replace_int :: KnownNat n => Vec n a -> Int -> a -> Vec n a-      "Clash.Sized.Vector.replace_int" | argLen == 6 -> do-        let ([_knArg,vArg,iArg,aArg],[nTy,aTy]) = Either.partitionEithers args-        case runExcept (tyNatSize tcm nTy) of+      "Clash.Sized.Vector.replace_int"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx                                  , isUntranslatableType_not_poly aTy                                  -- Note [Unroll shouldSplit types]-                                 , pure (Maybe.isJust (shouldSplit tcm eTy))+                                 , pure (Maybe.isJust (shouldSplit tcm resTy))                                  ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceReplace_int is0 n aTy eTy vArg iArg aArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceReplace_int n aTy resTy)                else return e           _ -> return e+        | argLen >= 2+        -> error ("reduceNonRepPrim: replace_int bad args" <> showPpr e) -      "Clash.Sized.Vector.index_int" | argLen == 5 -> do-        let ([_knArg,vArg,iArg],[nTy,aTy]) = Either.partitionEithers args-            argTy = inferCoreTypeOf tcm vArg-        case runExcept (tyNatSize tcm nTy) of+      "Clash.Sized.Vector.index_int"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        , (_:Right argTy:_) <- fst (splitFunForallTy (piResultTys tcm (primType p) [nTy,aTy]))+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure ultra                                  , shouldReduce ctx@@ -370,104 +411,122 @@                                  -- Note [Unroll shouldSplit types]                                  , pure (Maybe.isJust (shouldSplit tcm argTy)) ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceIndex_int is0 n aTy vArg iArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceIndex_int n aTy)                else return e           _ -> return e+        | argLen >= 2+        -> error ("reduceNonRepPrim: index_int bad args" <> showPpr e) -      "Clash.Sized.Vector.imap" | argLen == 6 -> do-        let [nTy,argElTy,resElTy] = Either.rights args-            TyConApp vecTcNm _ = tv-            argTy = mkTyConApp vecTcNm [nTy,argElTy]-        case runExcept (tyNatSize tcm nTy) of+      "Clash.Sized.Vector.imap"+        | (tmArgs,[nTy,argElTy,resElTy]) <- Either.partitionEithers args+        , TyConApp vecTcNm _ <- tv+        , let argTy = mkTyConApp vecTcNm [nTy,argElTy]+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ pure (ultra || n < 2)                                  , shouldReduce ctx                                  , List.anyM isUntranslatableType_not_poly [argElTy,resElTy]                                  -- Note [Unroll shouldSplit types]                                  , pure (any (Maybe.isJust . shouldSplit tcm)-                                             [argTy,eTy]) ]+                                             [argTy,resTy]) ]             if shouldReduce1-               then let [_,fun,arg] = Either.lefts args-                    in  (`mkTicks` ticks) <$> reduceImap c n argElTy resElTy fun arg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceImap n argElTy resElTy)                else return e           _ -> return e-      "Clash.Sized.Vector.iterateI" | argLen == 5 ->-        let ([_kn,f,a],[nTy,aTy]) = Either.partitionEithers args in-        case runExcept (tyNatSize tcm nTy) of+        | argLen >= 3+        -> error ("reduceNonRepPrim: imap bad args" <> showPpr e)++      "Clash.Sized.Vector.iterateI"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM               [ pure (ultra || n < 2)               , shouldReduce ctx               , isUntranslatableType_not_poly aTy               -- Note [Unroll shouldSplit types]-              , pure (Maybe.isJust (shouldSplit tcm eTy)) ]+              , pure (Maybe.isJust (shouldSplit tcm resTy)) ]              if shouldReduce1 then-              (`mkTicks` ticks) <$> reduceIterateI c n aTy eTy f a+              abstractOverMissingArgs ticks tmArgs eTy c (reduceIterateI n aTy resTy)             else               return e           _ -> return e-      "Clash.Sized.Vector.dtfold" | argLen == 8 ->-        let ([_kn,_motive,lrFun,brFun,arg],[_mTy,nTy,aTy]) = Either.partitionEithers args-        in  case runExcept (tyNatSize tcm nTy) of-          Right n -> (`mkTicks` ticks) <$> reduceDTFold is0 n aTy lrFun brFun arg+        | argLen >= 2+        -> error ("reduceNonRepPrim: iterateI bad args" <> showPpr e)++      "Clash.Sized.Vector.dtfold"+        | (tmArgs,[_mTy,nTy,aTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of+          Right n -> abstractOverMissingArgs ticks tmArgs eTy c (reduceDTFold n aTy)           _ -> return e+        | argLen >= 3+        -> error ("reduceNonRepPrim: dtfold bad args" <> showPpr e)        "Clash.Sized.Vector.reverse"         | ultra-        , ([vArg],[nTy,aTy]) <- Either.partitionEithers args+        , (tmArgs,[nTy,aTy]) <- Either.partitionEithers args         , Right n <- runExcept (tyNatSize tcm nTy)-        -> (`mkTicks` ticks) <$> reduceReverse is0 n aTy vArg+        -> abstractOverMissingArgs ticks tmArgs eTy c (reduceReverse n aTy) -      "Clash.Sized.RTree.tdfold" | argLen == 8 ->-        let ([_kn,_motive,lrFun,brFun,arg],[_mTy,nTy,aTy]) = Either.partitionEithers args-        in  case runExcept (tyNatSize tcm nTy) of-          Right n -> (`mkTicks` ticks) <$> reduceTFold is0 n aTy lrFun brFun arg+      "Clash.Sized.RTree.tdfold"+        | (tmArgs,[_mTy,nTy,aTy]) <- Either.partitionEithers args+        -> case runExcept (tyNatSize tcm nTy) of+          Right n -> abstractOverMissingArgs ticks tmArgs eTy c (reduceTFold n aTy)           _ -> return e-      "Clash.Sized.RTree.treplicate" | argLen == 4 -> do-        let ([_sArg,vArg],[nTy,aTy]) = Either.partitionEithers args+        | argLen >= 3+        -> error ("reduceNonRepPrim: tdfold bad args" <> showPpr e)+      "Clash.Sized.RTree.treplicate"+        | (tmArgs,[nTy,aTy]) <- Either.partitionEithers args ->         case runExcept (tyNatSize tcm nTy) of           Right n -> do             shouldReduce1 <- List.orM [ shouldReduce ctx                                  , isUntranslatableType False aTy ]             if shouldReduce1-               then (`mkTicks` ticks) <$> reduceTReplicate n aTy eTy vArg+               then abstractOverMissingArgs ticks tmArgs eTy c (reduceTReplicate n aTy resTy)                else return e           _ -> return e-      "Clash.Sized.Internal.BitVector.split#" | argLen == 4 -> do-        let ([_knArg,bvArg],[nTy,mTy]) = Either.partitionEithers args+        | argLen >= 2+        -> error ("reduceNonRepPrim: treplicate bad args" <> showPpr e)+      "Clash.Sized.Internal.BitVector.split#"+        | (tmArgs,[nTy,mTy]) <- Either.partitionEithers args ->         case (runExcept (tyNatSize tcm nTy), runExcept (tyNatSize tcm mTy), tv) of           (Right n, Right m, TyConApp tupTcNm [lTy,rTy])-            | n == 0 -> do-              let (Just tupTc) = lookupUniqMap tupTcNm tcm-                  [tupDc]      = tyConDataCons tupTc-                  tup          = mkApps (Data tupDc)-                                    [Right lTy-                                    ,Right rTy-                                    ,Left  bvArg-                                    ,Left  (TyApp (Prim removedArg) rTy)-                                    ]+            | n == 0 -> abstractOverMissingArgs ticks tmArgs eTy c $ \(_kn :: Term) bvArg (_ctx :: TransformContext) -> do+              let tup = mkApps (Data tupDc)+                           [Right lTy+                           ,Right rTy+                           ,Left  bvArg+                           ,Left  (TyApp (Prim removedArg) rTy)+                           ] -              changed (mkTicks tup ticks)-            | m == 0 -> do-              let (Just tupTc) = lookupUniqMap tupTcNm tcm-                  [tupDc]      = tyConDataCons tupTc-                  tup          = mkApps (Data tupDc)-                                    [Right lTy-                                    ,Right rTy-                                    ,Left  (TyApp (Prim removedArg) lTy)-                                    ,Left  bvArg-                                    ]+              (changed (mkTicks tup ticks) :: NormalizeSession Term)+            | m == 0 -> abstractOverMissingArgs ticks tmArgs eTy c $ \(_kn :: Term) bvArg (_ctx :: TransformContext) -> do+              let tup = mkApps (Data tupDc)+                           [Right lTy+                           ,Right rTy+                           ,Left  (TyApp (Prim removedArg) lTy)+                           ,Left  bvArg+                           ] -              changed (mkTicks tup ticks)+              (changed (mkTicks tup ticks) :: NormalizeSession Term)+           where+            tupDc = fromMaybe (error "reduceNonRepPrim: faield to create tup DC") $ do+                    tupTc <- UniqMap.lookup tupTcNm tcm+                    listToMaybe (tyConDataCons tupTc)           _ -> return e+        | argLen >= 3+        -> error ("reduceNonRepPrim: split# bad args" <> showPpr e)       "Clash.Sized.Internal.BitVector.eq#"-        | ([_,_],[nTy]) <- Either.partitionEithers args+        | (tmArgs,[nTy]) <- Either.partitionEithers args         , Right 0 <- runExcept (tyNatSize tcm nTy)         , TyConApp boolTcNm [] <- tv-        -> let (Just boolTc) = lookupUniqMap boolTcNm tcm-               [_falseDc,trueDc] = tyConDataCons boolTc-           in  changed (mkTicks (Data trueDc) ticks)+        -> abstractOverMissingArgs ticks tmArgs eTy c $ \(_kn :: Term) (_l :: Term) (_r :: Term) (_ctx :: TransformContext) -> do+           let trueDc = fromMaybe (error "reduceNonRepPrim: failed to create True DC") $ do+                  boolTc <- UniqMap.lookup boolTcNm tcm+                  [_falseDc,dc] <- pure (tyConDataCons boolTc)+                  return dc+            in (changed (Data trueDc) :: NormalizeSession Term)       _ -> return e   where     isUntranslatableType_not_poly t = do@@ -478,3 +537,29 @@  reduceNonRepPrim _ e = return e {-# SCC reduceNonRepPrim #-}++class AbstractOverMissingArgs a where+  -- | Abstract over a primitive until it is saturated+  abstractOverMissingArgs ::+    HasCallStack =>+    -- | Ticks originally tagged to the applied primitive+    [TickInfo] ->+    -- | Available arguments+    [Term] ->+    -- | The type of the expression containing the applied primitive+    Type ->+    -- | The context in which reduceNonRepPrim was called+    TransformContext ->+    a ->+    NormalizeSession Term++instance AbstractOverMissingArgs (TransformContext -> NormalizeSession Term) where+  abstractOverMissingArgs ticks args _ is f = (`mkTmApps` args) <$> (`mkTicks` ticks) <$> f is++instance AbstractOverMissingArgs a => AbstractOverMissingArgs (Term -> a) where+  abstractOverMissingArgs ticks (t:ts) ty ctx f = abstractOverMissingArgs ticks ts ty ctx (f t)+  abstractOverMissingArgs ticks []     (tyView -> FunTy argTy resTy) (TransformContext is0 ctx) f = do+     newId <- mkInternalVar is0 "arg" argTy+     let ctx1 = TransformContext (extendInScopeSet is0 newId) (LamBody newId : ctx)+     Lam newId <$> abstractOverMissingArgs ticks [] resTy ctx1 (f (Var newId))+  abstractOverMissingArgs _ _ ty _ _ = error ("not a funty: " <> showPpr ty)
src/Clash/Normalize/Transformations/Specialize.hs view
@@ -2,7 +2,7 @@   Copyright  :  (C) 2012-2016, University of Twente,                     2016-2017, Myrtle Software Ltd,                     2017-2018, Google Inc.,-                    2021-2022, QBayLogic B.V.+                    2021-2023, QBayLogic B.V.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -80,6 +80,7 @@ import Clash.Core.VarEnv   ( InScopeSet, extendInScopeSet, extendInScopeSetList, lookupVarEnv   , mkInScopeSet, mkVarSet, unionInScope, elemVarSet)+import qualified Clash.Data.UniqMap as UniqMap import Clash.Debug (traceIf, traceM) import Clash.Driver.Types (Binding(..), TransformationInfo(..), hasTransformationInfo) import Clash.Netlist.Util (representableType)@@ -95,9 +96,6 @@   ( NormRewrite, NormalizeSession, specialisationCache, specialisationHistory) import Clash.Normalize.Util   (constantSpecInfo, csrFoundConstant, csrNewBindings, csrNewTerm)-import Clash.Unique-  ( eltsUniqMap, eltsUniqSet, extendUniqMapWith, unitUniqSet, filterUniqMap-  , lookupUniqMap) import Clash.Util (ClashException(..))  -- | Propagate arguments of application inwards; except for 'Lam' where the@@ -343,6 +341,27 @@ miss on virtually every lookup which could add to normalization time. -} +-- | Given two 'InlineSpec's, return the \"strongest\" one. I.e., the one that's+-- closest to @NoInline@ (or @Opaque@ for newer GHCs).+preferNoInline :: InlineSpec -> InlineSpec -> InlineSpec+preferNoInline is0 is1+  | enumInlineSpec is0 >= enumInlineSpec is1 = is0+  | otherwise                                = is1+ where+  enumInlineSpec :: InlineSpec -> Int+  enumInlineSpec = \case+#if MIN_VERSION_ghc(9,2,0)+    NoUserInlinePrag {} -> -1+#else+    NoUserInline {} -> -1+#endif+    Inline {} -> 0+    Inlinable {} -> 1+    NoInline {} -> 2+#if MIN_VERSION_ghc(9,4,0)+    Opaque {} -> 3+#endif+ -- | Specialize an application on its argument specialize'   :: TransformContext@@ -400,11 +419,11 @@     -- Create new specialized function     Nothing -> do       -- Determine if we can specialize f-      bodyMaybe <- fmap (lookupUniqMap (varName f)) $ Lens.use bindings+      bodyMaybe <- fmap (UniqMap.lookup f) $ Lens.use bindings       case bodyMaybe of         Just (Binding _ sp inl _ bodyTm _) -> do           -- Determine if we see a sequence of specializations on a growing argument-          specHistM <- lookupUniqMap f <$> Lens.use (extra.specialisationHistory)+          specHistM <- UniqMap.lookup f <$> Lens.use (extra.specialisationHistory)           specLim   <- Lens.view specializationLimit           if maybe False (> specLim) specHistM             then throw (ClashException@@ -443,21 +462,32 @@                       -- binding @g'@ where both the body of @mealy@ and @g@                       -- are inlined, meaning the state-transition-function                       -- and the memory element will be in a single function.-                      gTmM <- fmap (lookupUniqMap (varName g)) $ Lens.use bindings-                      return (g,maybe inl bindingSpec gTmM, maybe specArg (Left . (`mkApps` gArgs) . bindingTerm) gTmM)+                      gTmM <- fmap (UniqMap.lookup g) $ Lens.use bindings+                      return+                        ( g+                        , preferNoInline inl (maybe noUserInline bindingSpec gTmM)+                        , maybe specArg (Left . (`mkApps` gArgs) . bindingTerm) gTmM+                        )                     else return (f,inl,specArg)                 _ -> return (f,inl,specArg)               -- Create specialized functions               let newBody = mkAbstraction (mkApps bodyTm (argVars ++ [specArg'])) (boundArgs ++ specBndrs)               newf <- mkFunction (varName fId) sp inl' newBody               -- Remember specialization-              (extra.specialisationHistory) %= extendUniqMapWith f 1 (+)+              (extra.specialisationHistory) %= UniqMap.insertWith (+) f 1               (extra.specialisationCache)  %= Map.insert (f,argLen,specAbs) newf               -- use specialized function               let newExpr = mkApps (mkTicks (Var newf) ticks) (args ++ specVars)               newf `deepseq` changed newExpr         Nothing -> return e   where+    noUserInline :: InlineSpec+#if MIN_VERSION_ghc(9,2,0)+    noUserInline = NoUserInlinePrag+#else+    noUserInline = NoUserInline+#endif+     collectBndrsMinusApps :: Term -> [Name a]     collectBndrsMinusApps = reverse . go []       where@@ -479,11 +509,15 @@       newBody = mkAbstraction specArg specBndrs   -- See if there's an existing binder that's alpha-equivalent to the   -- specialized function-  existing <- filterUniqMap ((`aeqTerm` newBody) . bindingTerm) <$> Lens.use bindings+  existing <- UniqMap.filter ((`aeqTerm` newBody) . bindingTerm) <$> Lens.use bindings   -- Create a new function if an alpha-equivalent binder doesn't exist-  newf <- case eltsUniqMap existing of+  newf <- case UniqMap.elems existing of     [] -> do (cf,sp) <- Lens.use curFun+#if MIN_VERSION_ghc(9,2,0)+             mkFunction (appendToName (varName cf) "_specF") sp NoUserInlinePrag newBody+#else              mkFunction (appendToName (varName cf) "_specF") sp NoUserInline newBody+#endif     (b:_) -> return (bindingId b)   -- Create specialized argument   let newArg  = Left $ mkApps (Var newf) specVars@@ -530,7 +564,9 @@       (specFTVs,specFVs) = case specArg of         Left tm  -> (OSet.toListL *** OSet.toListL) . getConst $                     Lens.foldMapOf freeLocalVars unitFV tm-        Right ty -> (eltsUniqSet (Lens.foldMapOf typeFreeVars unitUniqSet ty),[] :: [Id])+        Right ty -> ( UniqMap.elems+                        (Lens.foldMapOf typeFreeVars (\x -> UniqMap.singletonUnique (coerce x)) ty)+                    , [] :: [Id])        specTyBndrs = map Right specFTVs       specTmBndrs = map Left  specFVs@@ -648,7 +684,7 @@      -- where all fields are also zero-width.      | otherwise      -> do-       tc <- lookupUniqMap tcNm tcm+       tc <- UniqMap.lookup tcNm tcm         case tyConDataCons tc of          [dc] -> do
src/Clash/Normalize/Util.hs view
@@ -74,6 +74,7 @@ import           Clash.Core.VarEnv   (VarEnv, emptyInScopeSet, emptyVarEnv, extendVarEnv, extendVarEnvWith,    lookupVarEnv, unionVarEnvWith, unitVarEnv, extendInScopeSetList, mkInScopeSet, mkVarSet)+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Debug             (traceIf) import           Clash.Driver.Types   (BindingMap, Binding(..), TransformationInfo(FinalTerm), hasTransformationInfo)@@ -348,8 +349,8 @@ collectCallGraphUniques :: CallGraph -> HashSet.HashSet Unique collectCallGraphUniques cg = HashSet.fromList (us0 ++ us1)  where-  us0 = keysUniqMap cg-  us1 = concatMap keysUniqMap (eltsUniqMap cg)+  us0 = UniqMap.keys cg+  us1 = concatMap UniqMap.keys (UniqMap.elems cg)  -- | Create a call graph for a set of global binders, given a root callGraph@@ -359,12 +360,12 @@ callGraph bndrs rt = go emptyVarEnv (varUniq rt)   where     go cg root-      | Nothing     <- lookupUniqMap root cg-      , Just rootTm <- lookupUniqMap root bndrs =+      | Nothing     <- UniqMap.lookup root cg+      , Just rootTm <- UniqMap.lookup root bndrs =       let used = Lens.foldMapByOf globalIds (unionVarEnvWith (+))-                  emptyVarEnv (`unitUniqMap` 1) (bindingTerm rootTm)-          cg'  = extendUniqMap root used cg-      in  List.foldl' go cg' (keysUniqMap used)+                  emptyVarEnv (`UniqMap.singleton` 1) (bindingTerm rootTm)+          cg'  = UniqMap.insert root used cg+      in  List.foldl' go cg' (UniqMap.keys used)     go cg _ = cg  -- | Give a "performance/size" classification of a function in normal form.
+ src/Clash/Primitives/Annotations/SynthesisAttributes.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE TemplateHaskellQuotes #-}+{-# LANGUAGE OverloadedStrings #-}++module Clash.Primitives.Annotations.SynthesisAttributes where++import Prelude++import Control.Monad.State (State)+import Data.Either (lefts, rights)+import Data.List.Infinite((...), Infinite((:<)))+import Data.Proxy (Proxy(..))+import Data.Text (Text)+import Data.Text.Prettyprint.Doc.Extra (Doc)+import GHC.Stack (HasCallStack)+import GHC.TypeLits (someNatVal)+import GHC.TypeNats (KnownNat, SomeNat(..))+import Text.Show.Pretty (ppShow)++import qualified Control.Lens as Lens+import qualified Data.Text as T++import Clash.Annotations.SynthesisAttributes+import Clash.Backend (Backend)+import Clash.Core.TermLiteral (termToDataError)+import Clash.Core.Type (Type(LitTy), LitTy(NumTy), coreView)+import Clash.Netlist.BlackBox.Types+import Clash.Netlist.Types+import Clash.Sized.Vector (Vec, toList)++import qualified Clash.Primitives.DSL as DSL++usedArguments :: [Int]+usedArguments = [attrs, signal]+ where+  attrs :< signal :< _ = (0...)++annotateBBF :: HasCallStack => BlackBoxFunction+annotateBBF _isD _primName args _resTys = Lens.view tcCache >>= go+ where+  go tcm+    | ((coreView tcm -> LitTy (NumTy n)) : _) <- rights args+    , Just (SomeNat (Proxy :: Proxy n)) <- someNatVal n+    , (attrs0 : _) <- lefts args+    = case termToDataError attrs0 of+        Left msg -> error msg+        Right attrs1 -> pure $ Right (bbMeta, bb @n (fmap T.pack <$> attrs1))+  go _ = error $ "Unexpected args:\n " <> ppShow args++  bbMeta :: BlackBoxMeta+  bbMeta = emptyBlackBoxMeta{bbKind = TDecl}++  bb :: KnownNat n => Vec n (Attr Text) -> BlackBox+  bb attrs = BBFunction (show 'annotateTF) 0 (annotateTF attrs)++annotateTF :: HasCallStack => KnownNat n => Vec n (Attr Text) -> TemplateFunction+annotateTF attrs = TemplateFunction usedArguments (const True) (annotateBBTF attrs)++annotateBBTF ::+  (Backend s, KnownNat n, HasCallStack) =>+  Vec n (Attr Text) ->+  BlackBoxContext ->+  State s Doc+annotateBBTF attrs0 bbCtx+  | (_attrs : signal0 : _) <- map fst $ DSL.tInputs bbCtx+  = DSL.declarationReturn bbCtx "annotate_block" $ do+      let+        attrs1 = toList attrs0+        signal1ty = Annotated attrs1 (DSL.ety signal0)+        signal1 = DSL.TExpr{DSL.eex=DSL.eex signal0, DSL.ety=signal1ty}+      resultExpr <- DSL.assign (getSignalName (bbCtxName bbCtx)) signal1+      pure [resultExpr]+ where+  -- Return user-friendly name given a context name hint.+  getSignalName :: Maybe T.Text -> T.Text+  getSignalName Nothing = "result"+  getSignalName (Just "__VOID_TDECL_NOOP__") = getSignalName Nothing+  getSignalName (Just s) = s++annotateBBTF _attrs bbCtx = error $ "Unexpected context:\n " <> ppShow bbCtx
src/Clash/Primitives/DSL.hs view
@@ -1,7 +1,8 @@ {-|-  Copyright   :  (C) 2019, Myrtle Software Ltd.-                     2020-2022, QBayLogic B.V.-                     2021, Myrtle.ai+  Copyright   :  (C) 2019,      Myrtle Software Ltd.+                     2020-2023, QBayLogic B.V.+                     2021,      Myrtle.ai+                     2022-2023, Google Inc   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -9,8 +10,11 @@ instantiations. -} +{-# LANGUAGE CPP               #-} {-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms   #-} {-# LANGUAGE QuasiQuotes       #-}@@ -27,9 +31,14 @@    -- * Declarations   , BlockState (..)-  , TExpr+  , TExpr(..)+  , addDeclaration+  , assign+  , compInBlock   , declaration   , declarationReturn+  , declare+  , declareN   , instDecl   , instHO   , viaAnnotatedSignal@@ -48,14 +57,18 @@   , tResults   , getStr   , getBool+  , getVec   , exprToInteger   , tExprToInteger   , deconstructProduct   , untuple   , unvec+  , deconstructMaybe    -- ** Conversion+  , bitCoerce   , toBV+  , toBvWithAttrs   , fromBV   , enableToBit   , boolToBit@@ -64,6 +77,9 @@   , unsignedFromBitVector   , boolFromBits +  , unsafeToActiveHigh+  , unsafeToActiveLow+   -- ** Operations   , andExpr   , notExpr@@ -72,12 +88,16 @@   , open    -- ** Utilities+  , clog2+  , litTExpr   , toIdentifier   , tySize-  , clog2   ) where  import           Control.Lens                    hiding (Indexed, assign)+#if MIN_VERSION_mtl(2,3,0)+import           Control.Monad                   (forM, forM_, zipWithM)+#endif import           Control.Monad.State import           Data.Default                    (Default(def)) import           Data.IntMap                     (IntMap)@@ -95,10 +115,11 @@ import           GHC.Stack                       (HasCallStack)  import           Clash.Annotations.Primitive     (HDL (..), Primitive (..))-import           Clash.Backend                   hiding (fromBV, toBV)+import           Clash.Annotations.SynthesisAttributes (Attr)+import           Clash.Backend                   hiding (Usage, fromBV, toBV) import           Clash.Backend.VHDL              (VHDLState)-import           Clash.Core.Var                  (Attr')-import           Clash.Netlist.BlackBox.Util     (exprToString, renderElem)+import           Clash.Explicit.Signal           (ResetPolarity(..), vResetPolarity)+import           Clash.Netlist.BlackBox.Util     (exprToString, getDomainConf, renderElem) import           Clash.Netlist.BlackBox.Types   (BlackBoxTemplate, Element(Component, Text), Decl(..)) import qualified Clash.Netlist.Id                as Id@@ -106,7 +127,6 @@ import           Clash.Netlist.Util import           Clash.Util                      (clogBase) import qualified Data.String.Interpolate         as I-import           Data.String.Interpolate.Util    (unindent) import           Language.Haskell.TH             (Name) import           Prelude @@ -139,7 +159,7 @@ -- | Create a blackBoxHaskell primitive. To be used as part of an annotation: -- -- @--- {-\# ANN myFunction (blackBoxHaskell 'myFunction 'myBBF def{_ignoredArguments=[1,2]}) \#-}+-- {-\# ANN myFunction (blackBoxHaskell 'myFunction 'myBBF def{bo_ignoredArguments=[1,2]}) \#-} -- @ -- -- @[1,2]@ would mean this blackbox __ignores__ its second and third argument.@@ -152,19 +172,17 @@   -- ^ Options, see data structure for more information   -> Primitive blackBoxHaskell bb tf BlackBoxHaskellOpts{..} =-  InlinePrimitive bo_supportedHdls $ unindent [I.i|-  [ { "BlackBoxHaskell" :-      { "name" : "#{bb}"-      , "templateFunction" : "#{tf}"-      , "ignoredArguments" : #{show bo_ignoredArguments}-      , "multiResult" : #{toJsonBool bo_multiResult}-      }-    }-  ] |]+  InlineYamlPrimitive bo_supportedHdls [I.__i|+    BlackBoxHaskell:+      name: #{bb}+      templateFunction: #{tf}+      ignoredArguments : #{bo_ignoredArguments}+      multiResult : #{toYamlBool bo_multiResult}+    |]  where-  toJsonBool :: Bool -> String-  toJsonBool True = "true"-  toJsonBool False = "false"+  toYamlBool :: Bool -> String+  toYamlBool True = "true"+  toYamlBool False = "false"  -- | The state of a block. Contains a list of declarations and a the --   backend state.@@ -183,6 +201,20 @@   identifierSet :: Lens' (BlockState backend) IdentifierSet   identifierSet = bsBackend . identifierSet +instance HasUsageMap backend => HasUsageMap (BlockState backend) where+  usageMap = bsBackend.usageMap++liftToBlockState+  :: forall backend a. Backend backend+   => State backend a -> State (BlockState backend) a+liftToBlockState (StateT f) = StateT g+ where+  g :: BlockState backend -> Identity (a, BlockState backend)+  g sbsIn = do+    let sIn = _bsBackend sbsIn+    (res,sOut) <- f sIn+    pure (res, sbsIn{_bsBackend = sOut})+ -- | A typed expression. data TExpr = TExpr   { ety :: HWType@@ -205,10 +237,19 @@ declarationReturn bbCtx blockName blockBuilder =   declaration blockName $ do     res <- blockBuilder-    forM_ (zip (bbResults bbCtx) res) $ \(rNm, r) -> do-      let (Identifier resultNm Nothing, _) = rNm-      addDeclaration (Assignment resultNm (eex r))+    forM_ (zip (bbResults bbCtx) res) $ \(rNm, r) -> case rNm of+      (Identifier resultNm Nothing, _) ->+        addDeclaration (Assignment resultNm Cont (eex r))+      (t,_) -> error ("declarationReturn expected an Identifier, but got: " <> show t) ++emptyBlockState :: backend -> BlockState backend+emptyBlockState bck = BlockState+  { _bsDeclarations = []+  , _bsHigherOrderCalls = IntMap.empty+  , _bsBackend = bck+  }+ -- | Run a block declaration. declaration   :: Backend backend@@ -218,13 +259,13 @@   -- ^ block builder   -> State backend Doc   -- ^ pretty printed block-declaration blockName s = do+declaration blockName c = do   backend0 <- get-  let initState = BlockState [] IntMap.empty backend0-      BlockState decs _hoCalls backend1 = execState s initState-  put backend1+  let initState = emptyBlockState backend0+      (BlockState {..}) = execState c initState+  put _bsBackend   blockNameUnique <- Id.makeBasic blockName-  getAp $ blockDecl blockNameUnique (reverse decs)+  getAp $ blockDecl blockNameUnique (reverse _bsDeclarations)  -- | Add a declaration to the state. addDeclaration :: Declaration -> State (BlockState backend) ()@@ -235,15 +276,13 @@   :: Backend backend   => Text   -- ^ Name hint-  -> WireOrReg-  -- ^ Should signal be declared as a wire or a reg   -> HWType   -- ^ Type of new signal   -> State (BlockState backend) Identifier   -- ^ Expression pointing the the new signal-declare' decName wireOrReg ty = do+declare' decName ty = do   uniqueName <- Id.makeBasic decName-  addDeclaration (NetDecl' Nothing wireOrReg uniqueName (Right ty) Nothing)+  addDeclaration (NetDecl' Nothing uniqueName ty Nothing)   pure uniqueName  -- | Declare a new signal with the given name and type.@@ -251,16 +290,33 @@   :: Backend backend   => Text   -- ^ Name hint-  -> WireOrReg-  -- ^ Should signal be declared as a wire or a reg   -> HWType   -- ^ Type of new signal   -> State (BlockState backend) TExpr   -- ^ Expression pointing the the new signal-declare decName wireOrReg ty = do-  uniqueName <- declare' decName wireOrReg ty+declare decName ty = do+  uniqueName <- declare' decName ty   pure (TExpr ty (Identifier uniqueName Nothing)) +-- | Declare /n/ new signals with the given type and based on the given name+declareN+  :: Backend backend+  => Text+  -- ^ Name hint+  -> [HWType]+  -- ^ Types of the signals+  -> State (BlockState backend) [TExpr]+  -- ^ Expressions pointing the the new signals+declareN decName tys = do+  firstName <- Id.makeBasic decName+  nextNames <- Id.nextN (length tys - 1) firstName+  let uniqueNames = firstName : nextNames+  zipWithM+    (\uniqueName ty -> do+      addDeclaration $ NetDecl' Nothing uniqueName ty Nothing+      pure $ TExpr ty (Identifier uniqueName Nothing)+    ) uniqueNames tys+ -- | Assign an expression to an identifier, returns the new typed --   identifier expression. assign@@ -268,12 +324,16 @@   => Text   -- ^ Name hint for assignment   -> TExpr-  -- ^ expression to be assigned to+  -- ^ expression to be assigned to freshly generated identifier   -> State (BlockState backend) TExpr   -- ^ the identifier of the expression that actually got assigned assign aName (TExpr ty aExpr) = do-  texp@(~(TExpr _ (Identifier uniqueName Nothing))) <- declare aName Wire ty-  addDeclaration (Assignment uniqueName aExpr)+  texp <- declare aName ty+  let uniqueName = case texp of+        TExpr _ (Identifier x Nothing) -> x+        t' -> error ("assign expected an Identifier, but got: " <> show t')++  addDeclaration (Assignment uniqueName Cont aExpr)   pure texp  -- | Extract the elements of a vector expression and return expressions@@ -288,11 +348,49 @@   -> State (BlockState backend) [TExpr]   -- ^ Vector elements unvec vName v@(ety -> Vector vSize eType) = do-  ~(TExpr _ (Identifier vUniqueName Nothing)) <- toIdentifier vName v+  texp <- toIdentifier vName v+  let vUniqueName = case texp of+        TExpr _ (Identifier x Nothing) -> x+        t' -> error ("unvec expected an Identifier, but got: " <> show t')+   let vIndex i = Identifier vUniqueName (Just (Indexed (ety v, 10, i)))   pure (map (TExpr eType . vIndex) [0..vSize-1]) unvec _ e = error $ "unvec: cannot be called on non-vector: " <> show (ety e) +-- | Deconstruct a 'Maybe' into its constructor 'Bit' and contents of its 'Just'+-- field. Note that the contents might be undefined, if the constructor bit is+-- set to 'Nothing'.+deconstructMaybe ::+  (HasCallStack, Backend backend) =>+  -- | Maybe expression+  TExpr ->+  -- | Name hint for constructor bit, data+  (Text, Text) ->+  -- | Constructor represented as a Bit, contents of Just+  State (BlockState backend) (TExpr, TExpr)+deconstructMaybe e@TExpr{ety} (bitName, contentName)+  | SP tyName [(_nothing, []),(_just, [aTy])] <- ety+  , tyName == fromString (show ''Maybe)+  = do+    eBv <- toBV (bitName <> "_and_" <> contentName <> "_bv") e+    eId <- toIdentifier' (bitName <> "_and_" <> contentName) eBv+    let eSize = typeSize ety++    bitExpr <- fromBV bitName Bit TExpr+      { eex = Identifier eId (Just (Sliced (BitVector eSize, eSize - 1, eSize - 1)))+      , ety = BitVector 1+      }++    contentExpr <- fromBV contentName aTy TExpr+      { eex = Identifier eId (Just (Sliced (BitVector eSize, eSize - 1 - 1, 0)))+      , ety = BitVector (eSize - 1)+      }++    pure (bitExpr, contentExpr)++deconstructMaybe e _ =+  error $ "deconstructMaybe: cannot be called on non-Maybe: " <> show (ety e)+ -- | Extract the fields of a product type and return expressions --   to them. These new expressions are given unique names and get --   declared in the block scope.@@ -303,10 +401,15 @@   -> [Text]   -- ^ Name hints for element assignments   -> State (BlockState backend) [TExpr]-deconstructProduct (TExpr ty@(Product _ _ tys) (Identifier resName _)) vals = do-  newNames <- zipWithM (flip declare Wire) vals tys-  addDeclaration $ Assignment resName $ DataCon ty (DC (ty, 0)) (fmap eex newNames)-  pure newNames+deconstructProduct (TExpr ty@(Product _ _ fieldTys) (Identifier resName Nothing)) nameHints =+  forM (zip3 [0..] nameHints fieldTys) $ \(fieldIndex, nameHint, fieldTy) ->+    assign nameHint $+      TExpr fieldTy (Identifier resName (Just (Indexed (ty, 0, fieldIndex))))++deconstructProduct t0@(TExpr (Product {}) _) nameHints = do+  t1 <- toIdentifier "product" t0+  deconstructProduct t1 nameHints+ deconstructProduct e i =   error $ "deconstructProduct: " <> show e <> " " <> show i @@ -365,12 +468,16 @@   T -> pure High   F -> pure Low   TExpr Bool boolExpr -> do-    texp@(~(TExpr _ (Identifier uniqueBitName Nothing))) <- declare bitName Wire Bit+    texp <- declare bitName Bit+    let uniqueBitName = case texp of+          TExpr _ (Identifier x Nothing) -> x+          t' -> error ("boolFromBit expected an Identifier, but got: " <> show t')     addDeclaration $       CondAssignment uniqueBitName Bit boolExpr Bool         [ (Just (BoolLit True), Literal Nothing (BitLit H))         , (Nothing            , Literal Nothing (BitLit L))         ]+    declareUseOnce (Proc NonBlocking) uniqueBitName     pure texp   tExpr -> error $ "boolToBit: Got \"" <> show tExpr <> "\" expected Bool" @@ -383,13 +490,17 @@   -> State (BlockState backend) TExpr enableToBit bitName = \case   TExpr ena@(Enable _) enableExpr -> do-    texp@(~(TExpr _ (Identifier uniqueBitName Nothing))) <- declare bitName Wire Bit+    texp <- declare bitName Bit+    let uniqueBitName = case texp of+          TExpr _ (Identifier x Nothing) -> x+          t' -> error ("boolFromBit expected an Identifier, but got: " <> show t')     addDeclaration $       CondAssignment uniqueBitName Bit enableExpr ena         -- Enable normalizes to Bool for all current backends         [ (Just (BoolLit True), Literal Nothing (BitLit H))         , (Nothing            , Literal Nothing (BitLit L))         ]+    declareUseOnce (Proc NonBlocking) uniqueBitName     pure texp   tExpr -> error $ "enableToBit: Got \"" <> show tExpr <> "\" expected Enable" @@ -398,11 +509,27 @@ --   Returns a reference to a declared `Bit` that should get assigned --   by something (usually the output port of an entity). boolFromBit-  :: Text+  :: (HasCallStack, Backend backend)+  => Text   -- ^ Name hint for intermediate signal   -> TExpr-  -> State (BlockState VHDLState) TExpr-boolFromBit = outputCoerce Bit Bool (<> " = '1'")+  -> State (BlockState backend) TExpr+boolFromBit boolName = \case+  High -> pure T+  Low -> pure F+  TExpr Bit bitExpr -> do+    texp <- declare boolName Bool+    let uniqueBoolName = case texp of+          TExpr _ (Identifier x Nothing) -> x+          t' -> error ("boolFromBit expected an Identifier, but got: " <> show t')+    addDeclaration $+      CondAssignment uniqueBoolName Bool bitExpr Bit+        [ (Just (BitLit H), Literal Nothing (BoolLit True))+        , (Nothing        , Literal Nothing (BoolLit False))+        ]+    declareUseOnce (Proc NonBlocking) uniqueBoolName+    pure texp+  tExpr -> error $ "boolFromBit: Got \"" <> show tExpr <> "\" expected Bit"  -- | Used to create an output `Bool` from a `BitVector` of given size. -- Works in a similar way to `boolFromBit` above.@@ -419,17 +546,18 @@  -- | Used to create an output `Unsigned` from a `BitVector` of given -- size. Works in a similar way to `boolFromBit` above.------ TODO: Implement for (System)Verilog-unsignedFromBitVector-  :: HasCallStack-  => Size-  -> Text-  -- ^ Name hint for intermediate signal-  -> TExpr-  -> State (BlockState VHDLState) TExpr-unsignedFromBitVector n =-  outputCoerce (BitVector n) (Unsigned n) (\i -> "unsigned(" <> i <> ")")+unsignedFromBitVector ::+  (HasCallStack, Backend backend) =>+  -- | Name hint for intermediate signal+  Text ->+  -- | BitVector expression+  TExpr ->+  -- | Unsigned expression+  State (BlockState backend) TExpr+unsignedFromBitVector nameHint e@TExpr{ety=BitVector n} =+  fromBV nameHint (Unsigned n) e+unsignedFromBitVector _nameHint TExpr{ety} =+  error $ "unsignedFromBitVector: Expected BitVector, got: " <> show ety  -- | Used to create an output `Bool` from a number of `Bit`s, using -- conjunction. Similarly to `untuple`, it returns a list of@@ -465,7 +593,7 @@       let inName2 = Id.unsafeMake (exprStringFn (Id.toText inName1))           exprIdent = Identifier inName2 Nothing       addDeclaration (NetDecl Nothing inName1 fromType)-      addDeclaration (Assignment outName exprIdent)+      addDeclaration (Assignment outName Cont exprIdent)       pure (TExpr fromType (Identifier inName1 Nothing)) outputCoerce _ toType _ _ texpr = error $ "outputCoerce: the expression " <> show texpr                                   <> " must be an Identifier with type " <> show toType@@ -491,7 +619,7 @@           exprIdent = Identifier idExpr Nothing       sequenceOf_ each [ addDeclaration (NetDecl Nothing nm t)                        | (nm, t) <- zip inNames1 fromTypes ]-      addDeclaration (Assignment outName exprIdent)+      addDeclaration (Assignment outName Cont exprIdent)       pure [ TExpr t (Identifier nm Nothing)            | (nm,t) <- zipEqual inNames1 fromTypes ] outputFn _ outType _ _ texpr =@@ -539,6 +667,17 @@ getBool (TExpr _ (Literal _ (BoolLit b))) = Just b getBool _ = Nothing +-- | Try to get a Vector of expressions.+getVec :: TExpr -> Maybe [TExpr]+getVec (TExpr (Void (Just (Vector 0 _) )) _) =+  pure []+getVec (TExpr (Vector 1 elementTy) (DataCon _ VecAppend [e])) =+  pure [TExpr elementTy e]+getVec (TExpr (Vector n elementTy) (DataCon _ VecAppend [e, es0])) = do+  es1 <- getVec (TExpr (Vector (n-1) elementTy) es0)+  pure (TExpr elementTy e:es1)+getVec _ = Nothing+ -- | Try to get the literal nat value of an expression. tExprToInteger :: TExpr -> Maybe Integer tExprToInteger (TExpr _ e) = exprToInteger e@@ -548,41 +687,72 @@ exprToInteger (Literal _ (NumLit n)) = Just n exprToInteger _ = Nothing --- | Assign an input bitvector to an expression. Declares a new---   bitvector if the expression is not already a bitvector.-toBV-  :: Backend backend-  => Text-  -- ^ BitVector name hint-  -> TExpr-  -- ^ expression-  -> State (BlockState backend) TExpr-  -- ^ BitVector expression-toBV bvName a = case a of-  TExpr BitVector{} _ -> pure a-  TExpr aTy aExpr     -> assign bvName $-    TExpr (BitVector (typeSize aTy)) (ToBv Nothing aTy aExpr)+-- | Convert an expression from one type to another. Errors if result type and+-- given expression are sized differently.+bitCoerce ::+  (HasCallStack, Backend backend) =>+  -- | Name hints for intermediate variables+  Text ->+  -- | Type to convert to+  HWType ->+  -- | Expression to convert+  TExpr ->+  -- | Converted expression+  State (BlockState backend) TExpr+bitCoerce nameHint destType e@(TExpr ety _)+  | tySize ety /= tySize @Int destType = error "Size mismatch"+  | ety == destType = pure e+  | BitVector _ <- ety = fromBV nameHint destType e+  | otherwise = bitCoerce nameHint destType =<< toBV nameHint e --- | Assign an output bitvector to an expression. Declares a new---   bitvector if the expression is not already a bitvector.+-- | Convert an expression to a BitVector+toBV ::+  Backend backend =>+  -- | BitVector name hint+  Text ->+  -- | Expression to convert to BitVector+  TExpr ->+  -- | BitVector expression+  State (BlockState backend) TExpr+toBV = toBvWithAttrs []++-- | Convert an expression to a BitVector and add the given HDL attributes+toBvWithAttrs ::+  Backend backend =>+  [Attr Text] ->+  -- | BitVector name hint+  Text ->+  -- | Expression to convert to BitVector+  TExpr ->+  -- | BitVector expression+  State (BlockState backend) TExpr+toBvWithAttrs attrs bvName (TExpr aTy aExpr) =+  assign bvName $+    TExpr+      (annotated attrs (BitVector (tySize aTy)))+      (ToBv Nothing aTy aExpr)++-- | Convert an expression from a 'BitVector' into some type. If the expression+-- is 'Annotated', only convert the expression within. fromBV-  :: (HasCallStack, Backend backend)-  => Text-  -- ^ BitVector name hint-  -> TExpr-  -- ^ expression-  -> State (BlockState backend) TExpr-  -- ^ bv expression-fromBV _ a@(TExpr BitVector{} _) = pure a-fromBV bvName (TExpr aTy (Identifier aName Nothing)) = do-  bvName' <- Id.makeBasic bvName-  let bvExpr = FromBv Nothing aTy (Identifier bvName' Nothing)-      bvTy   = BitVector (typeSize aTy)-  addDeclaration (NetDecl Nothing bvName' bvTy)-  addDeclaration (Assignment aName bvExpr)-  pure (TExpr bvTy (Identifier bvName' Nothing))-fromBV _ texpr = error $-  "fromBV: the expression " <> show texpr <> "must be an Identifier"+  :: (HasCallStack, Backend backend) =>+  -- | Result name hint+  Text ->+  -- | Type to convert to+  HWType ->+  -- | 'BitVector' expression+  TExpr ->+  -- | Converted 'BitVector' expression+  State (BlockState backend) TExpr+fromBV resultName resultType e@TExpr{eex, ety = BitVector _} =+  case resultType of+    BitVector{} -> pure e+    _ -> assign resultName (TExpr resultType (FromBv Nothing resultType eex))+fromBV resultName resultType e@TExpr{ety = Annotated _ bv@(BitVector _)} =+  case resultType of+    BitVector{} -> pure (TExpr bv (eex e))+    _ -> assign resultName (TExpr resultType (FromBv Nothing resultType (eex e)))+fromBV _ _ TExpr{ety} = error $ "fromBV: expected BitVector, got: " <> show ety  clog2 :: Num i => Integer -> i clog2 = fromIntegral . fromMaybe 0 . clogBase 2@@ -618,11 +788,11 @@   -> Int   -- ^ Position of HO-argument. For example:   ---  --   fold :: forall n a . (a -> a -> a) -> Vec (n + 1) a -> a+  -- > fold :: forall n a . (a -> a -> a) -> Vec (n + 1) a -> a   --   -- would have its HO-argument at position 0, while   ---  --  iterateI :: forall n a. KnownNat n => (a -> a) -> a -> Vec n a+  -- > iterateI :: forall n a. KnownNat n => (a -> a) -> a -> Vec n a   --   -- would have it at position 1.   -> (HWType, BlackBoxTemplate)@@ -646,15 +816,8 @@   let     args2 = map (pure . Text . Id.toLazyText) args1 -    -- Create result identifier-    -- See https://github.com/clash-lang/clash-compiler/issues/919 for info on-    -- logic of 'resWireOrReg'-    resWireOrReg =-      case IntMap.lookup fPos (bbFunctions bbCtx) of-        Just ((_,rw,_,_,_,_):_) -> rw-        _ -> error "internal error"   resName <- declare' (ctxName <> "_" <> "ho" <> showt fPos <> "_"-                               <> showt fSubPos <> "_res") resWireOrReg resTy+                               <> showt fSubPos <> "_res") resTy   let res = ([Text (Id.toLazyText resName)], bbResTy)    -- Render HO argument to plain text@@ -674,33 +837,76 @@    pure (TExpr resTy (Identifier resName Nothing)) --- | Instantiate a component/entity in a block state.+-- | This creates a component declaration (for VHDL) given in and out port+-- names, updating the 'BlockState backend' stored in the 'State' monad.+--+-- A typical result is that a+--+-- @+-- component fifo port+--    ( rst : in std_logic+--    ...+--    ; full : out std_logic+--    ; empty : out std_logic );+--  end component;+-- @+--+-- declaration would be added in the appropriate place.+compInBlock+  :: forall backend+   . Backend backend+  => Text+  -- ^ Component name+  -> [(Text, HWType)]+  -- ^ in ports+  -> [(Text, HWType)]+  -- ^ out ports+  -> State (BlockState backend) ()+compInBlock compName inPorts0 outPorts0 =+  addDeclaration (CompDecl compName (inPorts1 ++ outPorts1))+ where+  mkPort inOut (nm, ty) = (nm, inOut, ty)+  inPorts1 = mkPort In <$> inPorts0+  outPorts1 = mkPort Out <$> outPorts0++-- | Convert a 'LitHDL' to a 'TExpr'+--+-- __N.B.__: Clash 1.8 changed 'instDecl'\'s type signature. Where it would+--           previously accept 'LitHDL' in its generics/parameters argument, it+--           now accepts a 'TExpr'. This function is mostly there to ease this+--           transition.+litTExpr :: LitHDL -> TExpr+litTExpr (B b) = TExpr Bool    (Literal Nothing (BoolLit b))+litTExpr (S s) = TExpr String  (Literal Nothing (StringLit s))+litTExpr (I i) = TExpr Integer (Literal Nothing (NumLit i))++-- | Instantiate a component/entity in a block state instDecl   :: forall backend    . Backend backend   => EntityOrComponent   -- ^ Type of instantiation   -> Identifier-  -- ^ component/entity name+  -- ^ Component/entity name   -> Identifier-  -- ^ instantiation label-  -> [(Text, LitHDL)]-  -- ^ attributes+  -- ^ Instantiation label   -> [(Text, TExpr)]-  -- ^ in ports+  -- ^ Generics / parameters   -> [(Text, TExpr)]-  -- ^ out ports+  -- ^ In ports+  -> [(Text, TExpr)]+  -- ^ Out ports   -> State (BlockState backend) ()-instDecl entOrComp compName instLbl attrs inPorts outPorts = do+instDecl entOrComp compName instLbl params inPorts outPorts = do    inPorts' <- mapM (mkPort In) inPorts   outPorts' <- mapM (mkPort Out) outPorts    addDeclaration $     InstDecl-      entOrComp Nothing [] compName instLbl (mkAttrs attrs)+      entOrComp Nothing [] compName instLbl (mkParams params)       (NamedPortMap (inPorts' ++ outPorts'))-    where+   where     mkPort       :: PortDirection       -> (Text, TExpr)@@ -709,21 +915,12 @@       TExpr ty pExpr' <- toIdentifier (nmText <> "_port")  pExpr       pure (Identifier (Id.unsafeMake nmText) Nothing, inOrOut, ty, pExpr') -    -- Convert a list of name attributes to the form clash wants-    mkAttrs :: [(Text.Text, LitHDL)] -> [(Expr, HWType, Expr)]-    mkAttrs = map (\(s, ty) -> ( Identifier (Id.unsafeMake s) Nothing-                               , hdlTy ty, litExpr ty) )--    litExpr :: LitHDL -> Expr-    litExpr (B b) = Literal Nothing (BoolLit b)-    litExpr (S s) = Literal Nothing (StringLit s)-    litExpr (I i) = Literal Nothing (NumLit i)--    hdlTy :: LitHDL -> HWType-    hdlTy = \case-      B{} -> Bool-      S{} -> String-      I{} -> Integer+    -- Convert a list of name generics / parameters to the form clash wants+    mkParams :: [(Text.Text, TExpr)] -> [(Expr, HWType, Expr)]+    mkParams = map $ \(paramName, texpr) ->+      ( Identifier (Id.unsafeMake paramName) Nothing+      , ety texpr+      , eex texpr )  -- | Wires the two given `TExpr`s together using a newly declared -- signal with (exactly) the given name `sigNm`. The new signal has an@@ -736,14 +933,14 @@   -- ^ expression the signal is assigned to   -> TExpr   -- ^ expression (must be identifier) to which the signal is assigned-  -> [Attr']+  -> [Attr Text]   -- ^ the attributes to annotate the signal with   -> State (BlockState backend) () viaAnnotatedSignal sigNm (TExpr fromTy fromExpr) (TExpr toTy (Identifier outNm Nothing)) attrs   | fromTy == toTy = do       addDeclaration (NetDecl Nothing sigNm (Annotated attrs fromTy))-      addDeclaration (Assignment sigNm fromExpr)-      addDeclaration (Assignment outNm (Identifier sigNm Nothing))+      addDeclaration (Assignment sigNm Cont fromExpr)+      addDeclaration (Assignment outNm Cont (Identifier sigNm Nothing)) viaAnnotatedSignal _ inTExpr outTExpr@(TExpr _ (Identifier _ _)) _ =   error $ "viaAnnotatedSignal: The in and out expressions \"" <> show inTExpr <>   "\" and \"" <> show outTExpr <> "\" have non-matching types."@@ -771,7 +968,10 @@   -- ^ identifier to expression toIdentifier' _ (TExpr _ (Identifier aExpr Nothing)) = pure aExpr toIdentifier' nm texp = do-  ~(TExpr _ (Identifier nm' Nothing)) <- assign nm texp+  t <- assign nm texp+  let nm' = case t of+              TExpr _ (Identifier x Nothing) -> x+              t' -> error ("toIdentifier' expected an Identifier, but got: " <> show t')   pure nm'  -- | Get an identifier to an expression, creating a new assignment if@@ -818,15 +1018,43 @@       SystemVerilog -> aIdent <> " && " <> bIdent   assign nm $ TExpr Bool (Identifier (Id.unsafeMake andTxt) Nothing) +-- | Massage a reset to work as active-high reset.+unsafeToActiveHigh+  :: Backend backend+  => Text+  -- ^ Name hint+  -> TExpr+  -- ^ Reset signal+  -> State (BlockState backend) TExpr+unsafeToActiveHigh nm rExpr = do+  resetLevel <- vResetPolarity <$> liftToBlockState (getDomainConf (ety rExpr))+  case resetLevel of+    ActiveHigh -> pure rExpr+    ActiveLow -> notExpr nm rExpr++-- | Massage a reset to work as active-low reset.+unsafeToActiveLow+  :: Backend backend+  => Text+  -- ^ Name hint+  -> TExpr+  -- ^ Reset signal+  -> State (BlockState backend) TExpr+unsafeToActiveLow nm rExpr = do+  resetLevel <- vResetPolarity <$> liftToBlockState (getDomainConf (ety rExpr))+  case resetLevel of+    ActiveLow -> pure rExpr+    ActiveHigh -> notExpr nm rExpr+ -- | Negate @(not)@ an expression, assigning it to a new identifier. notExpr   :: Backend backend   => Text   -- ^ name hint   -> TExpr-  -- ^ a+  -- ^ @a@   -> State (BlockState backend) TExpr-  -- ^ not a+  -- ^ @not a@ notExpr _ T = pure F notExpr _ F = pure T notExpr nm aExpr = do@@ -851,9 +1079,9 @@   -> Int   -- ^ Size (n)   -> TExpr-  -- ^ ARG+  -- ^ @ARG@   -> State (BlockState VHDLState) TExpr-  -- ^ (0 to n => ARG)+  -- ^ @(0 to n => ARG)@ pureToBV nm n arg = do   arg' <- Id.toText <$> toIdentifier' nm arg   -- This is very hard coded and hacky@@ -863,7 +1091,7 @@ -- | Creates a BV that produces the following vhdl: -- -- @---    std_logic_vector(resize(ARG, Size))+--    std_logic_vector(resize(ARG, n)) -- @ -- -- TODO: Implement for (System)Verilog@@ -875,7 +1103,7 @@   -> TExpr   -- ^ ARG   -> State (BlockState VHDLState) TExpr-  -- ^ std_logic_vector(resize(ARG, Size))+  -- ^ @std_logic_vector(resize(ARG, n))@ pureToBVResized nm n arg = do   arg' <- Id.toText <$> toIdentifier' nm arg   -- This is very hard coded and hacky
src/Clash/Primitives/GHC/Int.hs view
@@ -5,13 +5,14 @@    Blackbox generation for GHC.Int.IntX# data constructors. (System)Verilog only! -}++{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}  module Clash.Primitives.GHC.Int (intTF) where -import           Clash.Core.Literal-  (Literal(IntegerLiteral, IntLiteral, Int64Literal))+import           Clash.Core.Literal           (Literal(..)) import           Clash.Core.Term              (Term(Literal)) import           Clash.Core.Type              (Type) import           Clash.Primitives.GHC.Literal@@ -28,6 +29,11 @@   \case     IntegerLiteral i -> Just i     IntLiteral i     -> Just i+#if MIN_VERSION_ghc(8,8,0)+    Int8Literal i    -> Just i+    Int16Literal i   -> Just i+    Int32Literal i   -> Just i+#endif     Int64Literal i   -> Just i     _                -> Nothing 
src/Clash/Primitives/GHC/Word.hs view
@@ -5,11 +5,13 @@    Blackbox generation for GHC.Word.WordX# data constructors. (System)Verilog only! -}+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}  module Clash.Primitives.GHC.Word (wordTF) where -import           Clash.Core.Literal           (Literal(WordLiteral))+import           Clash.Core.Literal           (Literal(..)) import           Clash.Core.Term              (Term(Literal)) import           Clash.Core.Type              (Type) import           Clash.Primitives.GHC.Literal@@ -24,6 +26,20 @@ wordTF :: BlackBoxFunction wordTF = literalTF "GHC.Word.W" wordTF' +getWordLit+  :: Literal+  -> Maybe Integer+getWordLit =+  \case+    WordLiteral i   -> Just i+#if MIN_VERSION_ghc(8,8,0)+    Word8Literal i  -> Just i+    Word16Literal i -> Just i+    Word32Literal i -> Just i+#endif+    Word64Literal i -> Just i+    _               -> Nothing+ wordTF'   :: Bool   -- ^ Is declaration@@ -32,12 +48,12 @@   -> Int   -- ^ Word size   -> (BlackBoxMeta, BlackBox)-wordTF' False [Left (Literal (WordLiteral n))] wordSize =+wordTF' False [Left (Literal (getWordLit -> Just n))] wordSize =   -- Literal as expression:   ( emptyBlackBoxMeta   , BBTemplate [unsignedLiteral wordSize n]) -wordTF' True [Left (Literal (WordLiteral n))] wordSize =+wordTF' True [Left (Literal (getWordLit -> Just n))] wordSize =   -- Literal as declaration:   ( emptyBlackBoxMeta   , BBTemplate (assign Result [unsignedLiteral wordSize n]))
src/Clash/Primitives/Intel/ClockGen.hs view
@@ -1,10 +1,11 @@ {-|   Copyright   :  (C) 2018     , Google Inc.,-                     2021-2022, QBayLogic B.V.+                     2021-2023, QBayLogic B.V.,+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> -  Blackbox template functions for Clash.Intel.ClockGen.{alteraPll,altpll}+  Blackbox template functions for Clash.Intel.ClockGen -}  {-# LANGUAGE OverloadedStrings #-}@@ -13,271 +14,302 @@  module Clash.Primitives.Intel.ClockGen where +import Control.Monad.State+import Data.List (zip4)+import Data.List.Infinite (Infinite(..), (...))+import Data.Maybe (fromMaybe)+import Data.Text.Prettyprint.Doc.Extra+import Text.Show.Pretty (ppShow)+ import Clash.Backend-import Clash.Netlist.BlackBox.Util import qualified Clash.Netlist.Id as Id import Clash.Netlist.Types import Clash.Netlist.Util--import Control.Monad.State-import Data.Monoid (Ap(getAp))-import qualified Data.String.Interpolate.IsString as I-import Data.Text.Prettyprint.Doc.Extra+import qualified Clash.Primitives.DSL as DSL+import Clash.Signal (periodToHz)+import Data.Text.Extra (showt) +import qualified Data.String.Interpolate as I import qualified Data.Text as TextS-import Data.Text.Extra (showt)+import qualified Prettyprinter.Interpolate as I -altpllTF :: TemplateFunction-altpllTF = TemplateFunction used valid altpllTemplate+data Variant = Altpll | AlteraPll++hdlUsed :: [Int]+hdlUsed = [ clk, rst ]  where-  used         = [0..4]-  valid bbCtx-    | [_,_,(nm,_,_),_,_] <- bbInputs bbCtx-    , Just _ <- exprToString nm-    , [(Identifier _ Nothing,Product {})] <- bbResults bbCtx-    = True-  valid _ = False+  _knownDomIn+    :< _clocksClass+    :< _clocksCxt+    :< _numOutClocks+    :< clk+    :< rst+    :< _ = (0...) +hdlValid :: BlackBoxContext -> Bool+hdlValid bbCtx | [(_,Product {})] <- bbResults bbCtx = True+hdlValid _ = False++qsysUsed :: [Int]+qsysUsed = [ knownDomIn, clocksCxt ]+ where+  knownDomIn+    :< _clocksClass+    :< clocksCxt+    :< _ = (0...)++altpllTF :: TemplateFunction+altpllTF = TemplateFunction hdlUsed hdlValid (hdlTemplate Altpll)+ altpllQsysTF :: TemplateFunction-altpllQsysTF = TemplateFunction used valid altpllQsysTemplate+altpllQsysTF = TemplateFunction qsysUsed valid altpllQsysTemplate  where-  used = [0..4]-  valid bbCtx-    | [_,_,(nm,_,_),_,_] <- bbInputs bbCtx-    , Just _ <- exprToString nm-    , [(Identifier _ Nothing,Product {})] <- bbResults bbCtx-    = True-  valid _ = False+  valid = const True  alteraPllTF :: TemplateFunction-alteraPllTF = TemplateFunction used valid alteraPllTemplate- where-  used         = [1..20]-  valid bbCtx-    | ((nm,_,_):_) <- drop 3 (bbInputs bbCtx)-    , Just _ <- exprToString nm-    = True-  valid _ = False+alteraPllTF = TemplateFunction hdlUsed hdlValid (hdlTemplate AlteraPll)  alteraPllQsysTF :: TemplateFunction-alteraPllQsysTF = TemplateFunction used valid alteraPllQsysTemplate+alteraPllQsysTF = TemplateFunction qsysUsed valid alteraPllQsysTemplate  where-  used  = [1..20]-  valid bbCtx-    | ((nm,_,_):_) <- drop 3 (bbInputs bbCtx)-    , Just _ <- exprToString nm-    = True-  valid _ = False+  valid = const True -alteraPllTemplate-  :: forall s-   . Backend s-  => BlackBoxContext-  -> State s Doc-alteraPllTemplate bbCtx = do- locked <- Id.makeBasic "locked"- pllLock <- Id.makeBasic "pllLock"- alteraPll <- Id.makeBasic "altera_pll_block"- alteraPll_inst <- Id.makeBasic instname0+hdlTemplate ::+  forall s .+  Backend s =>+  Variant ->+  BlackBoxContext ->+  State s Doc+hdlTemplate variant bbCtx+  | [ _knownDomIn+    , _clocksClass+    , _clocksCxt+    , _numOutClocks+    , clk+    , rst+    ] <- map fst (DSL.tInputs bbCtx)+  , [DSL.ety -> resultTy] <- DSL.tResults bbCtx+  , Product _ _ (init -> pllOutTys) <- resultTy+  , [compName] <- bbQsysIncName bbCtx+  = do+    let+      stdName Altpll = "altpll"+      stdName AlteraPll = "altera_pll"+      pllOutName Altpll = "c"+      pllOutName AlteraPll = "outclk_"+      clkInName Altpll = "clk"+      clkInName AlteraPll = "refclk"+      rstName Altpll = "areset"+      rstName AlteraPll = "rst" - clocks <- Id.nextN (length tys) =<< Id.make "pllOut"+    instName <- Id.makeBasic $ fromMaybe (stdName variant) $ bbCtxName bbCtx -  -- TODO: unsafeMake is dubious here: I don't think we take names in-  -- TODO: bbQsysIncName into account when generating fresh ids- let compName = Id.unsafeMake (head (bbQsysIncName bbCtx))+    -- TODO: unsafeMake is dubious here: I don't think we take names in+    -- TODO: bbQsysIncName into account when generating fresh ids+    let compNameId = Id.unsafeMake compName - let outclkPorts = map (\n -> instPort ("outclk_" <> showt n)) [(0 :: Int)..length clocks-1]+    DSL.declarationReturn bbCtx (stdName variant <> "_block") $ do - getAp $ blockDecl alteraPll $ concat-  [[ NetDecl Nothing locked Bit-   , NetDecl' Nothing Reg pllLock (Right Bool) Nothing]-  ,[ NetDecl Nothing clkNm ty | (clkNm,ty) <- zip clocks tys]-  ,[ InstDecl Comp Nothing [] compName alteraPll_inst [] $ NamedPortMap $ concat-      [ [ (instPort "refclk", In, clkTy, clk)-        , (instPort "rst", In, rstTy, rst)]-      , [ (p, Out, ty, Identifier k Nothing) | (k, ty, p) <- zip3 clocks tys outclkPorts ]-      , [(instPort "locked", Out, Bit, Identifier locked Nothing)]]-   , CondAssignment pllLock Bool (Identifier locked Nothing) Bit-      [(Just (BitLit H),Literal Nothing (BoolLit True))-      ,(Nothing        ,Literal Nothing (BoolLit False))]-   , Assignment result (DataCon resTy (DC (resTy,0)) $ concat-                          [[Identifier k Nothing | k <- clocks]-                          ,[Identifier pllLock Nothing]])+      rstHigh <- DSL.unsafeToActiveHigh "reset" rst+      pllOuts <- DSL.declareN "pllOut" pllOutTys+      locked <- DSL.declare "locked" Bit+      pllLock <- DSL.boolFromBit "pllLock" locked -   ]-  ]- where-  [(Identifier result Nothing,resTy@(Product _ _ (init -> tys)))] = bbResults bbCtx-  [(nm,_,_),(clk,clkTy,_),(rst,rstTy,_)] = drop 3 (bbInputs bbCtx)-  Just nm' = exprToString nm-  instname0 = TextS.pack nm'+      let+        pllOutNames =+          map (\n -> pllOutName variant <> showt n)+            [0 .. length pllOutTys - 1]+        compInps =+          [ (clkInName variant, DSL.ety clk)+          , (rstName variant, DSL.ety rstHigh)+          ]+        compOuts = zip pllOutNames pllOutTys  <> [("locked", Bit)]+        inps =+          [ (clkInName variant, clk)+          , (rstName variant, rstHigh)+          ]+        outs = zip pllOutNames pllOuts <> [("locked", locked)] -altpllTemplate+      DSL.compInBlock compName compInps compOuts+      DSL.instDecl Empty compNameId instName [] inps outs++      pure [DSL.constructProduct resultTy (pllOuts <> [pllLock])]+  | otherwise+  = error $ ppShow bbCtx++altpllQsysTemplate   :: Backend s   => BlackBoxContext   -> State s Doc-altpllTemplate bbCtx = do- pllOut <- Id.make "pllOut"- locked <- Id.make "locked"- pllLock <- Id.make "pllLock"- alteraPll <- Id.make "altpll_block"- alteraPll_inst <- Id.make instname0+altpllQsysTemplate bbCtx+  |   (_,stripVoid -> (KnownDomain _ clkInPeriod _ _ _ _),_)+    : _clocksClass+    : (_,stripVoid -> Product _ _ (init -> kdOuts),_)+    : _ <- bbInputs bbCtx+  = let+    clkPeriod (KnownDomain _ p _ _ _ _) = p+    clkPeriod _ =+      error $ "Internal error: not a KnownDomain\n" <> ppShow bbCtx - -- TODO: unsafeMake is dubious here: I don't think we take names in- -- TODO: bbQsysIncName into account when generating fresh ids- let compName = Id.unsafeMake (head (bbQsysIncName bbCtx))+    clkFreq p = periodToHz (fromInteger p) / 1e6 :: Double - getAp $ blockDecl alteraPll-  [ NetDecl Nothing locked  Bit-  , NetDecl' Nothing Reg pllLock (Right Bool) Nothing-  , NetDecl Nothing pllOut clkOutTy-  , InstDecl Comp Nothing [] compName alteraPll_inst [] $ NamedPortMap $-      [ (instPort "clk", In, clkTy, clk)-      , (instPort "areset", In, rstTy, rst)-      , (instPort "c0", Out, clkOutTy, Identifier pllOut Nothing)-      , (instPort "locked", Out, Bit, Identifier locked Nothing)]-  , CondAssignment pllLock Bool (Identifier locked Nothing) Bit-      [(Just (BitLit H),Literal Nothing (BoolLit True))-      ,(Nothing        ,Literal Nothing (BoolLit False))]-  , Assignment result (DataCon resTy (DC (resTy,0))-                        [Identifier pllOut Nothing-                        ,Identifier pllLock Nothing])+    clkOutPeriods = map clkPeriod kdOuts+    clkLcms = map (lcm clkInPeriod) clkOutPeriods+    clkMults = zipWith quot clkLcms clkOutPeriods+    clkDivs = map (`quot` clkInPeriod) clkLcms+    clkOutFreqs = map clkFreq clkOutPeriods -  ]- where-  [_,_,(nm,_,_),(clk,clkTy,_),(rst,rstTy,_)] = bbInputs bbCtx-  [(Identifier result Nothing,resTy@(Product _ _ [clkOutTy,_]))] = bbResults bbCtx-  Just nm' = exprToString nm-  instname0 = TextS.pack nm'+    qsysParams = TextS.intercalate "\n  "+      [[I.__i|+        <parameter name="PORT_clk#{n}" value="PORT_USED" />+          <parameter name="CLK#{n}_MULTIPLY_BY" value="#{clkMult}" />+          <parameter name="CLK#{n}_DIVIDE_BY" value="#{clkDiv}" />+          <parameter name="CLK#{n}_DUTY_CYCLE" value="50" />+          <parameter name="CLK#{n}_PHASE_SHIFT" value="0" />+        |]+      | (clkMult, clkDiv, n) <- zip3 clkMults clkDivs [(0 :: Word)..]+      ] -altpllQsysTemplate-  :: Backend s-  => BlackBoxContext-  -> State s Doc-altpllQsysTemplate bbCtx = pure bbText- where-  ((_,stripVoid -> kdIn,_):(_,stripVoid -> kdOut,_):_) = bbInputs bbCtx-  KnownDomain _ clkInPeriod _ _ _ _ = kdIn-  KnownDomain _ clkOutPeriod _ _ _ _ = kdOut-  clkOutFreq :: Double-  clkOutFreq = (1.0 / (fromInteger clkOutPeriod * 1.0e-12)) / 1e6-  clklcm = lcm clkInPeriod clkOutPeriod-  clkmult = clklcm `quot` clkOutPeriod-  clkdiv = clklcm `quot` clkInPeriod-  -- Note [QSys file templates]-  -- This QSys file template was derived from a "full" QSys system with a single-  -- "altpll" IP. Module parameters were then stripped on a trial-and-error-  -- basis to get a template that has the minimal number of parameters, but-  -- still has the desired, working, configuration.-  bbText = [I.i|<?xml version="1.0" encoding="UTF-8"?>-<system name="$${FILENAME}">-  <module-    name="altpll0"-    kind="altpll"-    enabled="1"-    autoexport="1">-  <parameter name="AVALON_USE_SEPARATE_SYSCLK" value="NO" />-  <parameter name="BANDWIDTH" value="" />-  <parameter name="BANDWIDTH_TYPE" value="AUTO" />-  <parameter name="CLK0_DIVIDE_BY" value="#{clkdiv}" />-  <parameter name="CLK0_DUTY_CYCLE" value="50" />-  <parameter name="CLK0_MULTIPLY_BY" value="#{clkmult}" />-  <parameter name="CLK0_PHASE_SHIFT" value="0" />-  <parameter name="COMPENSATE_CLOCK" value="CLK0" />-  <parameter name="INCLK0_INPUT_FREQUENCY" value="#{clkInPeriod}" />-  <parameter name="OPERATION_MODE" value="NORMAL" />-  <parameter name="PLL_TYPE" value="AUTO" />-  <parameter name="PORT_ARESET" value="PORT_USED" />-  <parameter name="PORT_INCLK0" value="PORT_USED" />-  <parameter name="PORT_LOCKED" value="PORT_USED" />-  <parameter name="PORT_clk0" value="PORT_USED" />-  <parameter name="HIDDEN_IS_FIRST_EDIT" value="0" />-  <parameter name="HIDDEN_CONSTANTS">-    CT#PORT_clk0 PORT_USED-    CT#CLK0_MULTIPLY_BY #{clkmult}-    CT#WIDTH_CLOCK 5-    CT#LPM_TYPE altpll-    CT#PLL_TYPE AUTO-    CT#CLK0_PHASE_SHIFT 0-    CT#OPERATION_MODE NORMAL-    CT#COMPENSATE_CLOCK CLK0-    CT#INCLK0_INPUT_FREQUENCY #{clkInPeriod}-    CT#PORT_INCLK0 PORT_USED-    CT#PORT_ARESET PORT_USED-    CT#BANDWIDTH_TYPE AUTO-    CT#CLK0_DUTY_CYCLE 50-    CT#CLK0_DIVIDE_BY #{clkdiv}-    CT#PORT_LOCKED PORT_USED</parameter>-  <parameter name="HIDDEN_IF_PORTS">-    IF#phasecounterselect {input 4}-    IF#locked {output 0}-    IF#reset {input 0}-    IF#clk {input 0}-    IF#phaseupdown {input 0}-    IF#scandone {output 0}-    IF#readdata {output 32}-    IF#write {input 0}-    IF#scanclk {input 0}-    IF#phasedone {output 0}-    IF#address {input 2}-    IF#c0 {output 0}-    IF#writedata {input 32}-    IF#read {input 0}-    IF#areset {input 0}-    IF#scanclkena {input 0}-    IF#scandataout {output 0}-    IF#configupdate {input 0}-    IF#phasestep {input 0}-    IF#scandata {input 0}</parameter>-  <parameter name="HIDDEN_MF_PORTS">-    MF#areset 1-    MF#clk 1-    MF#locked 1-    MF#inclk 1</parameter>-  <parameter name="HIDDEN_PRIVATES">-    PT#PHASE_SHIFT0 0.00000000-    PT#DIV_FACTOR0 #{clkdiv}-    PT#EFF_OUTPUT_FREQ_VALUE0 #{clkOutFreq}-    PT#MULT_FACTOR0 #{clkmult}-    PT#DUTY_CYCLE0 50.00000000</parameter>-  </module>-</system>|]+    qsysConsts = TextS.intercalate "\n    "+      [[I.__i|+        CT\#PORT_clk#{n} PORT_USED+            CT\#CLK#{n}_MULTIPLY_BY #{clkMult}+            CT\#CLK#{n}_DIVIDE_BY #{clkDiv}+            CT\#CLK#{n}_DUTY_CYCLE 50+            CT\#CLK#{n}_PHASE_SHIFT 0+        |]+      | (clkMult, clkDiv, n) <- zip3 clkMults clkDivs [(0 :: Word)..]+      ] +    qsysPorts =+      TextS.intercalate "\n    "+        [[I.i|IF\#c#{n} {output 0}|] | n <- [0 .. length kdOuts - 1]]++    qsysPrivs = TextS.intercalate "\n    "+      [[I.__i|+        PT\#MULT_FACTOR#{n} #{clkMult}+            PT\#DIV_FACTOR#{n} #{clkDiv}+            PT\#EFF_OUTPUT_FREQ_VALUE#{n} #{clkOutFreq}+            PT\#DUTY_CYCLE#{n} 50.00000000+            PT\#PHASE_SHIFT0 0.00000000+        |]+      | (clkMult, clkDiv, clkOutFreq, n) <-+          zip4 clkMults clkDivs clkOutFreqs [(0 :: Word)..]+      ]++    -- Note [QSys file templates]+    -- This QSys file template was derived from a "full" QSys system with a single+    -- "altpll" IP. Module parameters were then stripped on a trial-and-error+    -- basis to get a template that has the minimal number of parameters, but+    -- still has the desired, working, configuration.+    bbText = [I.__di|+      <?xml version="1.0" encoding="UTF-8"?>+      <system name="$${FILENAME}">+        <module+          name="altpll0"+          kind="altpll"+          enabled="1"+          autoexport="1">+        <parameter name="AVALON_USE_SEPARATE_SYSCLK" value="NO" />+        <parameter name="BANDWIDTH" value="" />+        <parameter name="BANDWIDTH_TYPE" value="AUTO" />+        #{qsysParams}+        <parameter name="COMPENSATE_CLOCK" value="CLK0" />+        <parameter name="INCLK0_INPUT_FREQUENCY" value="#{clkInPeriod}" />+        <parameter name="OPERATION_MODE" value="NORMAL" />+        <parameter name="PLL_TYPE" value="AUTO" />+        <parameter name="PORT_ARESET" value="PORT_USED" />+        <parameter name="PORT_INCLK0" value="PORT_USED" />+        <parameter name="PORT_LOCKED" value="PORT_USED" />+        <parameter name="HIDDEN_IS_FIRST_EDIT" value="0" />+        <parameter name="HIDDEN_CONSTANTS">+          #{qsysConsts}+          CT\#WIDTH_CLOCK 5+          CT\#LPM_TYPE altpll+          CT\#PLL_TYPE AUTO+          CT\#OPERATION_MODE NORMAL+          CT\#COMPENSATE_CLOCK CLK0+          CT\#INCLK0_INPUT_FREQUENCY #{clkInPeriod}+          CT\#PORT_INCLK0 PORT_USED+          CT\#PORT_ARESET PORT_USED+          CT\#BANDWIDTH_TYPE AUTO+          CT\#PORT_LOCKED PORT_USED</parameter>+        <parameter name="HIDDEN_IF_PORTS">+          IF\#phasecounterselect {input 4}+          IF\#locked {output 0}+          IF\#reset {input 0}+          IF\#clk {input 0}+          IF\#phaseupdown {input 0}+          IF\#scandone {output 0}+          IF\#readdata {output 32}+          IF\#write {input 0}+          IF\#scanclk {input 0}+          IF\#phasedone {output 0}+          IF\#address {input 2}+          #{qsysPorts}+          IF\#writedata {input 32}+          IF\#read {input 0}+          IF\#areset {input 0}+          IF\#scanclkena {input 0}+          IF\#scandataout {output 0}+          IF\#configupdate {input 0}+          IF\#phasestep {input 0}+          IF\#scandata {input 0}</parameter>+        <parameter name="HIDDEN_MF_PORTS">+          MF\#areset 1+          MF\#clk 1+          MF\#locked 1+          MF\#inclk 1</parameter>+        <parameter name="HIDDEN_PRIVATES">+          #{qsysPrivs}</parameter>+        </module>+      </system>+      |]+    in+      pure bbText+  | otherwise+  = error $ ppShow bbCtx+ alteraPllQsysTemplate   :: Backend s   => BlackBoxContext   -> State s Doc-alteraPllQsysTemplate bbCtx = pure bbText- where-  (_:(_,stripVoid -> kdIn,_):(_,stripVoid -> kdOutsProd,_):_) = bbInputs bbCtx-  kdOuts = case kdOutsProd of-    Product _ _ ps -> ps-    KnownDomain {} -> [kdOutsProd]-    _ -> error "internal error: not a Product or KnownDomain"--  cklFreq (KnownDomain _ p _ _ _ _)-    = (1.0 / (fromInteger p * 1.0e-12 :: Double)) / 1e6-  cklFreq _ = error "internal error: not a KnownDomain"+alteraPllQsysTemplate bbCtx+  |   (_,stripVoid -> kdIn,_)+    : _clocksClass+    : (_,stripVoid -> Product _ _ (init -> kdOuts),_)+    : _ <- bbInputs bbCtx+  = let+    clkFreq (KnownDomain _ p _ _ _ _)+      = periodToHz (fromIntegral p) / 1e6 :: Double+    clkFreq _ =+      error $ "Internal error: not a KnownDomain\n" <> ppShow bbCtx -  clkOuts = TextS.unlines-    [[I.i|<parameter name="gui_output_clock_frequency#{n}" value="#{f}"/>|]-    | (n,f) <- zip [(0 :: Word)..] (map cklFreq kdOuts)-    ]+    clkOuts = TextS.intercalate "\n"+      [[I.i|  <parameter name="gui_output_clock_frequency#{n}" value="#{f}"/>|]+      | (n,f) <- zip [(0 :: Word)..] (map clkFreq kdOuts)+      ] -  -- See Note [QSys file templates] on how this qsys template was derived.-  bbText = [I.i|<?xml version="1.0" encoding="UTF-8"?>-<system name="$${FILENAME}">- <module-    name="pll_0"-    kind="altera_pll"-    enabled="1"-    autoexport="1">-  <parameter name="gui_feedback_clock" value="Global Clock" />-  <parameter name="gui_number_of_clocks" value="#{length kdOuts}" />-  <parameter name="gui_operation_mode" value="direct" />-  #{clkOuts}-  <parameter name="gui_pll_mode" value="Integer-N PLL" />-  <parameter name="gui_reference_clock_frequency" value="#{cklFreq kdIn}" />-  <parameter name="gui_use_locked" value="true" />- </module>-</system>|]+    -- See Note [QSys file templates] on how this qsys template was derived.+    bbText = [I.__di|+      <?xml version="1.0" encoding="UTF-8"?>+      <system name="$${FILENAME}">+      <module+          name="pll_0"+          kind="altera_pll"+          enabled="1"+          autoexport="1">+        <parameter name="gui_feedback_clock" value="Global Clock" />+        <parameter name="gui_number_of_clocks" value="#{length kdOuts}" />+        <parameter name="gui_operation_mode" value="direct" />+      #{clkOuts}+        <parameter name="gui_pll_mode" value="Integer-N PLL" />+        <parameter name="gui_reference_clock_frequency" value="#{clkFreq kdIn}" />+        <parameter name="gui_use_locked" value="true" />+      </module>+      </system>+      |]+    in+      pure bbText+  | otherwise+  = error $ ppShow bbCtx
+ src/Clash/Primitives/Magic.hs view
@@ -0,0 +1,31 @@+{-|+  Copyright   :  (C) 2022     , Myrtle.ai,+                     2023     , QBayLogic B.V.,+  License     :  BSD2 (see the file LICENSE)+  Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>++  Blackbox functions for primitives in the @Clash.Magic@ module.+-}++{-# LANGUAGE TemplateHaskellQuotes #-}++module Clash.Primitives.Magic+  ( clashCompileErrorBBF+  ) where++import Data.Either (lefts)+import GHC.Stack (HasCallStack)+import Text.Show.Pretty++import Clash.Core.TermLiteral (termToDataError)+import Clash.Netlist.BlackBox.Types (BlackBoxFunction)+import Clash.Netlist.Types ()++clashCompileErrorBBF :: HasCallStack => BlackBoxFunction+clashCompileErrorBBF _isD _primName args _ty+  |   _hasCallstack+    : (either error id . termToDataError -> msg)+    : _ <- lefts args+  = pure $ Left $ "clashCompileError: " <> msg+  | otherwise+  = pure $ Left $ show 'clashCompileErrorBBF <> ": bad args:\n" <> ppShow args
src/Clash/Primitives/Sized/Signed.hs view
@@ -32,9 +32,9 @@   :: Backend s   => BlackBoxContext   -> State s Doc-fromIntegerTFTemplateVhdl bbCtx = getAp $ do-  let [(Literal _ (NumLit sz),_,_), (i, Signed szI, _)] = bbInputs bbCtx-  case compare sz (toInteger szI) of+fromIntegerTFTemplateVhdl bbCtx+  | [(Literal _ (NumLit sz),_,_), (i, Signed szI, _)] <- bbInputs bbCtx+  = getAp $ case compare sz (toInteger szI) of     LT -> case i of            Identifier iV m ->             let sl = Sliced (Signed szI,fromInteger sz-1,0)@@ -44,3 +44,5 @@     EQ -> expr False i     GT -> "resize" <> tupled (sequenceA [expr False i                                         ,expr False (Literal Nothing (NumLit sz))])+  | otherwise+  = error ("fromIntegerTFTemplateVhdl: bad bInputs: " <> show (bbInputs bbCtx))
src/Clash/Primitives/Sized/ToInteger.hs view
@@ -27,7 +27,41 @@ import System.IO (hPutStrLn, stderr) import Text.Trifecta.Result (Result(Success)) -#if MIN_VERSION_ghc(9,0,0)+#if MIN_VERSION_ghc(9,8,0)+import GHC.Unit.Module.Warnings (emptyWarningCategorySet)+import GHC.Utils.Error+  (DiagOpts(..), mkPlainDiagnostic, mkPlainMsgEnvelope, pprLocMsgEnvelopeDefault)+import GHC.Utils.Outputable+  (blankLine, empty, int, integer, showSDocUnsafe, text, ($$), ($+$), (<+>),+   defaultSDocContext )+import qualified GHC.Utils.Outputable as Outputable+import GHC.Types.Error (DiagnosticReason (WarningWithoutFlag))+import GHC.Types.SrcLoc (isGoodSrcSpan)+#elif MIN_VERSION_ghc(9,6,0)+import GHC.Utils.Error+  (DiagOpts(..), mkPlainDiagnostic, mkPlainMsgEnvelope, pprLocMsgEnvelopeDefault)+import GHC.Utils.Outputable+  (blankLine, empty, int, integer, showSDocUnsafe, text, ($$), ($+$), (<+>),+   defaultSDocContext )+import qualified GHC.Utils.Outputable as Outputable+import GHC.Types.Error (DiagnosticReason (WarningWithoutFlag))+import GHC.Types.SrcLoc (isGoodSrcSpan)+#elif MIN_VERSION_ghc(9,4,0)+import GHC.Utils.Error+  (DiagOpts(..), mkPlainDiagnostic, mkPlainMsgEnvelope, pprLocMsgEnvelope)+import GHC.Utils.Outputable+  (blankLine, empty, int, integer, showSDocUnsafe, text, ($$), ($+$), (<+>),+   defaultSDocContext )+import qualified GHC.Utils.Outputable as Outputable+import GHC.Types.Error (DiagnosticReason (WarningWithoutFlag))+import GHC.Types.SrcLoc (isGoodSrcSpan)+#elif MIN_VERSION_ghc(9,2,0)+import GHC.Utils.Error (mkPlainWarnMsg, pprLocMsgEnvelope)+import GHC.Utils.Outputable+  (blankLine, empty, int, integer, showSDocUnsafe, text, ($$), ($+$), (<+>))+import qualified GHC.Utils.Outputable as Outputable+import GHC.Types.SrcLoc (isGoodSrcSpan)+#elif MIN_VERSION_ghc(9,0,0) import GHC.Driver.Session (unsafeGlobalDynFlags) import GHC.Utils.Error (mkPlainWarnMsg, pprLocErrMsg) import GHC.Utils.Outputable@@ -76,10 +110,30 @@         (_,sp) <- Lens.use curCompNm         let srcInfo1 | isGoodSrcSpan sp = srcInfo                      | otherwise        = empty-+#if MIN_VERSION_ghc(9,8,0)+            opts     = DiagOpts mempty mempty emptyWarningCategorySet emptyWarningCategorySet False False Nothing defaultSDocContext+            diag     = mkPlainDiagnostic WarningWithoutFlag [] (warnMsg i1 iw $+$ blankLine $+$ srcInfo1)+            warnMsg1 = mkPlainMsgEnvelope opts sp diag+            warnMsg2 = pprLocMsgEnvelopeDefault warnMsg1+#elif MIN_VERSION_ghc(9,6,0)+            opts     = DiagOpts mempty mempty False False Nothing defaultSDocContext+            diag     = mkPlainDiagnostic WarningWithoutFlag [] (warnMsg i1 iw $+$ blankLine $+$ srcInfo1)+            warnMsg1 = mkPlainMsgEnvelope opts sp diag+            warnMsg2 = pprLocMsgEnvelopeDefault warnMsg1+#elif MIN_VERSION_ghc(9,4,0)+            opts     = DiagOpts mempty mempty False False Nothing defaultSDocContext+            diag     = mkPlainDiagnostic WarningWithoutFlag [] (warnMsg i1 iw $+$ blankLine $+$ srcInfo1)+            warnMsg1 = mkPlainMsgEnvelope opts sp diag+            warnMsg2 = pprLocMsgEnvelope warnMsg1+#elif MIN_VERSION_ghc(9,2,0)+            warnMsg1 = mkPlainWarnMsg sp (warnMsg i1 iw $+$ blankLine $+$ srcInfo1)+            warnMsg2 = pprLocMsgEnvelope warnMsg1+#else             warnMsg1 = mkPlainWarnMsg unsafeGlobalDynFlags sp (warnMsg i1 iw $+$ blankLine $+$ srcInfo1)+            warnMsg2 = pprLocErrMsg warnMsg1+#endif -        liftIO (hPutStrLn stderr (showSDocUnsafe (pprLocErrMsg warnMsg1)))+        liftIO (hPutStrLn stderr (showSDocUnsafe warnMsg2))     _ -> return ()   return ((meta,) <$> bb)  where
src/Clash/Primitives/Sized/Vector.hs view
@@ -1,5 +1,6 @@ {-|   Copyright   :  (C) 2020-2022 QBayLogic B.V.+                     2022     , Google Inc.   License     :  BSD2 (see the file LICENSE)   Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> @@ -12,22 +13,19 @@  module Clash.Primitives.Sized.Vector where -import           Control.Monad                      (replicateM)-import           Control.Monad.State                (State, zipWithM)+import           Control.Monad                      (replicateM, zipWithM)+import           Control.Monad.State                (State) import qualified Control.Lens                       as Lens import           Data.Either                        (rights)-import qualified Data.IntMap                        as IntMap import           Data.List.Extra                    (iterateNM)-import           Data.Maybe                         (fromMaybe)+import           Data.Maybe                         (fromMaybe, listToMaybe) import           Data.Monoid                        (Ap(getAp)) import           Data.Text.Extra                    (showt)-import           Data.Text.Lazy                     (pack) import           Data.Text.Prettyprint.Doc.Extra   (Doc, string, renderLazy, layoutPretty, LayoutOptions(..),    PageWidth(AvailablePerLine)) import           Text.Trifecta.Result               (Result(Success)) import qualified Data.String.Interpolate            as I-import qualified Data.String.Interpolate.Util       as I import           GHC.Stack                          (HasCallStack)  import           Clash.Backend@@ -42,11 +40,11 @@   (BlackBoxFunction, BlackBoxMeta(..), TemplateKind(TExpr, TDecl),    Element(Component, Typ, TypElem, Text), Decl(Decl), emptyBlackBoxMeta) import           Clash.Netlist.Types-  (Identifier, TemplateFunction, BlackBoxContext, HWType(Vector),-   Declaration(..), Expr(Literal, Identifier,DataCon), Literal(NumLit),-   BlackBox(BBTemplate, BBFunction), TemplateFunction(..), WireOrReg(Wire),-   Modifier(Indexed, Nested, DC), HWType(..), bbInputs, bbResults, emptyBBContext, tcCache,-   bbFunctions)+  (Identifier, TemplateFunction, BlackBoxContext, HWType(Vector), Usage(Cont),+   Declaration(..), Expr(Literal,Identifier,DataCon,BlackBoxE), Literal(NumLit),+   BlackBox(BBTemplate, BBFunction), TemplateFunction(..),+   Modifier(Indexed, Nested, DC), HWType(..), BlackBoxContext(..),+   emptyBBContext, tcCache) import qualified Clash.Netlist.Id                   as Id import           Clash.Netlist.Util                 (typeSize) import qualified Clash.Primitives.DSL               as Prim@@ -63,10 +61,10 @@  where   bb = BBFunction "Clash.Primitives.Sized.Vector.iterateBBF" 0 iterateTF   vecLength tcm =-    case coreView tcm (head (rights args)) of-      (LitTy (NumTy 0)) -> error "Unexpected empty vector in 'iterateBBF'"-      (LitTy (NumTy n)) -> fromInteger (n - 1)-      vl -> error $ "Unexpected vector length: " ++ show vl+    case coreView tcm <$> rights args of+      (LitTy (NumTy 0)):_ -> error "Unexpected empty vector in 'iterateBBF'"+      (LitTy (NumTy n)):_ -> fromInteger (n - 1)+      vl -> error $ "Unexpected vector length: " ++ show (listToMaybe vl)   meta tcm = emptyBlackBoxMeta {       bbKind=TDecl     , bbFunctionPlurality=[(1, vecLength tcm)]@@ -116,16 +114,18 @@ foldBBF :: HasCallStack => BlackBoxFunction foldBBF _isD _primName args _resTy = do   tcm <- Lens.view tcCache-  pure (Right (meta tcm, bb))- where-  bb = BBFunction "Clash.Primitives.Sized.Vector.foldTF" 0 foldTF-  [vecLengthMinusOne, _] = rights args-  vecLength tcm =-    case coreView tcm vecLengthMinusOne of-      (LitTy (NumTy n)) -> n + 1-      vl -> error $ "Unexpected vector length: " ++ show vl-  funcPlural tcm = foldFunctionPlurality (fromInteger (vecLength tcm))-  meta tcm = emptyBlackBoxMeta {bbKind=TDecl, bbFunctionPlurality=[(0, funcPlural tcm)]}+  let+    bb = BBFunction "Clash.Primitives.Sized.Vector.foldTF" 0 foldTF+    vecLengthMinusOne = case rights args of+      (l:_) -> l+      _ -> error ("foldBBF: bad Vec: " <> show args)+    vecLength =+      case coreView tcm vecLengthMinusOne of+        (LitTy (NumTy n)) -> n + 1+        vl -> error $ "Unexpected vector length: " ++ show vl+    funcPlural = foldFunctionPlurality (fromInteger vecLength)+    meta = emptyBlackBoxMeta {bbKind=TDecl, bbFunctionPlurality=[(0, funcPlural)]}+  pure (Right (meta, bb))  -- | Type signature of function we're generating netlist for: --@@ -142,9 +142,9 @@   vecIds <- replicateM n (Id.next baseId)    vecId <- Id.make "vec"-  let vecDecl = sigDecl vecType Wire vecId-      vecAssign = Assignment vecId vec-      elemAssigns = zipWith Assignment vecIds (map (iIndex vecId) [0..])+  let vecDecl = sigDecl vecType vecId+      vecAssign = Assignment vecId Cont vec+      elemAssigns = zipWith3 Assignment vecIds (repeat Cont) (map (iIndex vecId) [0..])       resultId =         case bbResults bbCtx of           [(Identifier t _, _)] -> t@@ -155,12 +155,8 @@   (concat -> fCalls, result) <- mkTree 1 vecIds    let intermediateResultIds = concatMap (\(FCall l r _) -> [l, r]) fCalls-      wr = case IntMap.lookup 0 (bbFunctions bbCtx) of-             Just ((_,rw,_,_,_,_):_) -> rw-             _ -> error "internal error"-      sigDecls = zipWith (sigDecl aTy) (wr:replicate n Wire ++ repeat wr)-                                       (result : intermediateResultIds)-      resultAssign = Assignment resultId (Identifier result Nothing)+      sigDecls = fmap (sigDecl aTy) (result : intermediateResultIds)+      resultAssign = Assignment resultId Cont (Identifier result Nothing)    callDecls <- zipWithM callDecl [0..] fCalls   foldNm <- Id.make "fold"@@ -229,8 +225,8 @@     pure ([], rest)    -- Simple wire without comment-  sigDecl :: HWType -> WireOrReg -> Identifier -> Declaration-  sigDecl typ rw nm = NetDecl' Nothing rw nm (Right typ) Nothing+  sigDecl :: HWType -> Identifier -> Declaration+  sigDecl typ nm = NetDecl Nothing nm typ    -- Index the intermediate vector. This uses a hack in Clash: the 10th   -- constructor of Vec doesn't exist; using it will be interpreted by the@@ -250,16 +246,16 @@     [_nTy,_aTy,_kn,Left v,Left ix] | isLiteral ix && isVar v ->       Right (meta TExpr, BBFunction "Clash.Primitives.Sized.Vector.indexIntVerilogTF" 0 indexIntVerilogTF)     [_nTy,_aTy,_kn,_v,Left ix] | isLiteral ix ->-      case runParse (pack (I.unindent bbTextLitIx)) of+      case runParse bbTextLitIx of         Success t -> Right (meta TDecl, BBTemplate t)         _         -> Left "internal error: parse fail"      _ ->-      case runParse (pack (I.unindent bbText)) of+      case runParse bbText of         Success t -> Right (meta TDecl, BBTemplate t)         _         -> Left "internal error: parse fail" -  bbText = [I.i|+  bbText = [I.__i|     // index begin     ~IF~SIZE[~TYP[1]]~THENwire ~TYPO ~GENSYM[vecArray][0] [0:~LIT[0]-1];     genvar ~GENSYM[i][2];@@ -269,12 +265,14 @@     end     ~ENDGENERATE     assign ~RESULT = ~SYM[0][~ARG[2]];~ELSEassign ~RESULT = ~ERRORO;~FI-    // index end|]+    // index end+    |] -  bbTextLitIx = [I.i|+  bbTextLitIx = [I.__i|     // index lit begin     ~IF~SIZE[~TYP[1]]~THENassign ~RESULT = ~VAR[vec][1][~SIZE[~TYP[1]]-1-~LIT[2]*~SIZE[~TYPO] -: ~SIZE[~TYPO]];~ELSEassign ~RESULT = ~ERRORO;~FI-    // index lit end|]+    // index lit end+    |]   indexIntVerilogTF :: TemplateFunction@@ -287,28 +285,28 @@   :: Backend s   => BlackBoxContext   -> State s Doc-indexIntVerilogTemplate bbCtx = getAp $ case typeSize vTy of+indexIntVerilogTemplate bbCtx+  | [  _kn, (vec, vTy, _), (ix, _, _)] <- bbInputs bbCtx+  , [(_,rTy)] <- bbResults bbCtx+  = getAp $ case typeSize vTy of   0 -> hdlTypeErrValue rTy   _ -> case vec of-    Identifier i mM -> case mM of-      Just m ->-           expr False (Identifier i (Just (Nested m (Indexed (vTy,10,ixI ix)))))-      _ -> expr False (Identifier i (Just (Indexed (vTy,10,ixI ix))))+    Identifier i mM -> do+      let+        ixI :: Expr ->  Int+        ixI ix0 = case ix0 of+          Literal _ (NumLit j) ->+            fromInteger j+          DataCon (Signed _) (DC (Void{},_)) [Literal (Just (Signed _,_)) (NumLit j)] ->+            fromInteger j+          BlackBoxE "GHC.Types.I#" _lib _use _incl _templ Context{bbInputs=[(Literal _ (NumLit j),_,_)]} _paren ->+            fromInteger j+          _ ->+            error ($(curLoc) ++ "Unexpected literal: " ++ show ix)+      case mM of+        Just m ->+            expr False (Identifier i (Just (Nested m (Indexed (vTy,10,ixI ix)))))+        _ -> expr False (Identifier i (Just (Indexed (vTy,10,ixI ix))))     _ -> error ($(curLoc) ++ "Expected Identifier: " ++ show vec)- where-  [  _kn-   , (vec, vTy, _)-   , (ix, _, _)-   ] = bbInputs bbCtx--  [(_,rTy)] = bbResults bbCtx--  ixI :: Expr ->  Int-  ixI ix0 = case ix0 of-    Literal _ (NumLit i) ->-      fromInteger i-    DataCon (Signed _) (DC (Void{},_)) [Literal (Just (Signed _,_)) (NumLit i)] ->-      fromInteger i-    _ ->-      error ($(curLoc) ++ "Unexpected literal: " ++ show ix)-+  | otherwise+  = error ("indexIntVerilogTemplate: bad bbContext: " <> show bbCtx)
src/Clash/Primitives/Types.hs view
@@ -3,6 +3,7 @@                     2016-2017, Myrtle Software Ltd                     2018     , Google Inc.                     2021     , QBayLogic B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -12,7 +13,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-}  module Clash.Primitives.Types@@ -32,21 +32,24 @@   , CompiledPrimMap   ) where -import {-# SOURCE #-} Clash.Netlist.Types (BlackBox)+import {-# SOURCE #-} Clash.Netlist.Types (BlackBox, Usage(..)) import           Clash.Annotations.Primitive  (PrimitiveGuard) import           Clash.Core.Term (WorkInfo (..)) import           Clash.Netlist.BlackBox.Types   (BlackBoxFunction, BlackBoxTemplate, TemplateKind (..), RenderVoid(..)) import           Control.Applicative          ((<|>)) import           Control.DeepSeq              (NFData)+import           Control.Monad                (when) import           Data.Aeson   (FromJSON (..), Value (..), (.:), (.:?), (.!=))+import           Data.Aeson.Types             (Parser) import           Data.Binary                  (Binary) import           Data.Char                    (isUpper, isLower, isAlphaNum) import           Data.Either                  (lefts) import           Data.Hashable                (Hashable) import qualified Data.HashMap.Strict          as H import           Data.List                    (intercalate)+import           Data.Maybe                   (isJust) import qualified Data.Text                    as S import           Data.Text.Lazy               (Text) import           GHC.Generics                 (Generic)@@ -108,10 +111,11 @@       let errs = lefts $ checkFunc func : map checkMod mods in       case errs of         [] -> Right $ BlackBoxFunctionName mods func-        _  -> Left $ "Error while parsing " ++ show bbfn ++ ": " ++ head errs+        e:_ -> Left $ "Error while parsing " ++ show bbfn ++ ": " ++ e   where     checkMod mod'-      | isLower (head mod') =+      | m':_ <- mod'+      , isLower m' =           Left $ "Module name cannot start with lowercase: " ++ mod'       | any (not . isAlphaNum) mod' =           Left $ "Module name must be alphanumerical: " ++ mod'@@ -119,7 +123,8 @@           Right mod'      checkFunc func-      | isUpper (head func) =+      | f:_ <- func+      , isUpper f =           Left $ "Function name must start with lowercase: " ++ func       | otherwise =           Right func@@ -165,10 +170,10 @@     -- ^ A warning to be outputted when the primitive is instantiated.     -- This is intended to be used as a warning for primitives that are not     -- synthesizable, but may also be used for other purposes.-  , outputReg :: Bool-    -- ^ Verilog only: whether the result should be a /reg/(@True@) or /wire/-    -- (@False@); when not specified in the /.primitives/ file, the value will default-    -- to @False@ (i.e. /wire/).+  , outputUsage :: Usage+    -- ^ How the result is assigned in HDL. This is used to determine the+    -- type of declaration used to render the result (wire/reg or+    -- signal/variable). The default usage is continuous assignment.   , libraries :: [a]     -- ^ VHDL only: add /library/ declarations for the given names   , imports   :: [a]@@ -241,10 +246,10 @@       [(conKey,Object conVal)] ->         case conKey of           "BlackBoxHaskell"  -> do-            usedArguments <- conVal .:? "usedArguments"-            ignoredArguments <- conVal .:? "ignoredArguments"+            usedArgs <- conVal .:? "usedArguments"+            ignoredArgs <- conVal .:? "ignoredArguments"             args <--              case (usedArguments, ignoredArguments) of+              case (usedArgs, ignoredArgs) of                 (Nothing, Nothing) -> pure (IgnoredArguments [])                 (Just a, Nothing) -> pure (UsedArguments a)                 (Nothing, Just a) -> pure (IgnoredArguments a)@@ -254,20 +259,28 @@             name' <- conVal .: "name"             wf    <- ((conVal .:? "workInfo" >>= maybe (pure Nothing) parseWorkInfo) .!= WorkVariable)             fName <- conVal .: "templateFunction"-            multiResult <- conVal .:? "multiResult" .!= False+            isMultiResult <- conVal .:? "multiResult" .!= False             templ <- (Just . TInline <$> conVal .: "template")                  <|> (Just . TFile   <$> conVal .: "file")                  <|> (pure Nothing)             fName' <- either fail return (parseBBFN fName)-            return (BlackBoxHaskell name' wf args multiResult fName' templ)-          "BlackBox"  ->+            return (BlackBoxHaskell name' wf args isMultiResult fName' templ)+          "BlackBox"  -> do+            outReg <- conVal .:? "outputReg" :: Parser (Maybe Bool)++            when (isJust outReg) .+              fail $ mconcat+                [ "[9] 'outputReg' is no longer a recognized key.\n"+                , "Use 'outputUsage: Continuous|NonBlocking|Blocking' instead."+                ]+             BlackBox <$> conVal .: "name"                      <*> (conVal .:? "workInfo" >>= maybe (pure Nothing) parseWorkInfo) .!= WorkVariable                      <*> conVal .:? "renderVoid" .!= NoRenderVoid                      <*> conVal .:? "multiResult" .!= False                      <*> (conVal .: "kind" >>= parseTemplateKind)                      <*> conVal .:? "warning"-                     <*> conVal .:? "outputReg" .!= False+                     <*> conVal .:? "outputUsage" .!= Cont                      <*> conVal .:? "libraries" .!= []                      <*> conVal .:? "imports" .!= []                      <*> pure [] -- functionPlurality not supported in json
src/Clash/Primitives/Util.hs view
@@ -3,6 +3,7 @@                     2017     , Myrtle Software Ltd                     2018     , Google Inc.                     2021     , QBayLogic B.V.+                    2022     , Google Inc.   License    :  BSD2 (see the file LICENSE)   Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> @@ -10,7 +11,6 @@ -}  {-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -61,8 +61,8 @@ hashCompiledPrimitive :: CompiledPrimitive -> Int hashCompiledPrimitive (Primitive {name, primSort}) = hash (name, primSort) hashCompiledPrimitive (BlackBoxHaskell {function}) = fst function-hashCompiledPrimitive (BlackBox {name, kind, outputReg, libraries, imports, includes, template}) =-  hash (name, kind, outputReg, libraries, imports, includes', hashBlackbox template)+hashCompiledPrimitive (BlackBox {name, kind, outputUsage, libraries, imports, includes, template}) =+  hash (name, kind, outputUsage, libraries, imports, includes', hashBlackbox template)     where       includes' = map (\(nms, bb) -> (nms, hashBlackbox bb)) includes       hashBlackbox (BBTemplate bbTemplate) = hash bbTemplate@@ -99,7 +99,7 @@   return (name, HasBlackBox [] (Primitive name wf primType)) resolvePrimitive' metaPath BlackBox{template=t, includes=i, resultNames=r, resultInits=ri, ..} = do   let resolveSourceM = traverse (traverse (resolveTemplateSource metaPath))-  bb <- BlackBox name workInfo renderVoid multiResult kind () outputReg libraries imports functionPlurality+  bb <- BlackBox name workInfo renderVoid multiResult kind () outputUsage libraries imports functionPlurality           <$> mapM (traverse resolveSourceM) i           <*> traverse resolveSourceM r           <*> traverse resolveSourceM ri
src/Clash/Primitives/Verification.hs view
@@ -7,6 +7,8 @@  import qualified Control.Lens                    as Lens import           Control.Monad.State             (State)+import           Data.List.Infinite              (Infinite(..), (...))+import           Data.Maybe                      (listToMaybe) import           Data.Monoid                     (Ap(getAp)) import           Data.Text.Prettyprint.Doc.Extra (Doc) import qualified Data.Text                       as Text@@ -20,12 +22,12 @@ import           Clash.Core.TermLiteral          (termToDataError) import           Clash.Util                      (indexNote) import           Clash.Netlist                   (mkExpr)-import           Clash.Netlist.Util              (stripVoid, id2identifier)+import           Clash.Netlist.Util              (stripVoid) import qualified Clash.Netlist.Id                as Id import           Clash.Netlist.Types   (BlackBox(BBFunction), TemplateFunction(..), BlackBoxContext, Identifier,-   NetlistMonad, Declaration(Assignment, NetDecl'),-   HWType(Bool, KnownDomain), WireOrReg(Wire), NetlistId(..),+   NetlistMonad, Declaration(Assignment, NetDecl), Usage(Cont),+   HWType(Bool, KnownDomain), NetlistId(..),    DeclarationType(Concurrent), tcCache, bbInputs, Expr(Identifier)) import           Clash.Netlist.BlackBox.Types   (BlackBoxFunction, BlackBoxMeta(..), TemplateKind(TDecl), RenderVoid(..),@@ -46,15 +48,20 @@  where   -- TODO: Improve error handling; currently errors don't indicate what   -- TODO: blackbox generated them.-  clk = indexNote "clk" (lefts args) 1+  _knownDomainArg+    :< clkArg+    :< _rstArg+    :< propNameArg+    :< renderAsArg+    :< propArg+    :< _ = ((0 :: Int)...)+  (Id.unsafeFromCoreId -> clkId) = varToId (indexNote "clk" (lefts args) clkArg)   clkExpr = Identifier clkId Nothing-  (id2identifier -> clkId) = varToId clk-  (id2identifier -> _clkId) = varToId (indexNote "rst" (lefts args) 2)    litArgs = do-    propName <- termToDataError (indexNote "propName" (lefts args) 3)-    renderAs <- termToDataError (indexNote "renderAs" (lefts args) 4)-    cvProperty <- termToDataError (indexNote "propArg" (lefts args) 5)+    propName <- termToDataError (indexNote "propName" (lefts args) propNameArg)+    renderAs <- termToDataError (indexNote "renderAs" (lefts args) renderAsArg)+    cvProperty <- termToDataError (indexNote "propArg" (lefts args) propArg)     Right (propName, renderAs, cvProperty)    bb = BBFunction "Clash.Primitives.Verification.checkTF" 0@@ -67,7 +74,7 @@     -- ^ Term to bind. Does not bind if it's already a reference to a signal     -> NetlistMonad (Identifier, [Declaration])     -- ^ ([new] reference to signal, [declarations need to get it in scope])-  bindMaybe _ (Var vId) = pure (id2identifier vId, [])+  bindMaybe _ (Var vId) = pure (Id.unsafeFromCoreId vId, [])   bindMaybe Nothing t = bindMaybe (Just "s") t   bindMaybe (Just nm) t = do     tcm <- Lens.view tcCache@@ -75,11 +82,11 @@     (expr0, decls) <- mkExpr False Concurrent (NetlistId newId (inferCoreTypeOf tcm t)) t     pure       ( newId-      , decls ++ [sigDecl Bool newId, Assignment newId expr0] )+      , decls ++ [sigDecl Bool newId, Assignment newId Cont expr0] )    -- Simple wire without comment   sigDecl :: HWType -> Identifier -> Declaration-  sigDecl typ nm = NetDecl' Nothing Wire nm (Right typ) Nothing+  sigDecl typ nm = NetDecl Nothing nm typ  checkTF   :: [Declaration]@@ -112,9 +119,9 @@   hdl = hdlKind (undefined :: s)    edge =-    case head (bbInputs bbCtx) of-      (_, stripVoid -> KnownDomain _nm _period e _rst _init _polarity, _) -> e-      _ -> error $ "Unexpected first argument: " ++ show (head (bbInputs bbCtx))+    case bbInputs bbCtx of+      (_, stripVoid -> KnownDomain _nm _period e _rst _init _polarity, _):_ -> e+      _ -> error $ "Unexpected first argument: " ++ show (listToMaybe (bbInputs bbCtx))    renderedPslProperty = case renderAs of     PSL          -> psl
+ src/Clash/Primitives/Xilinx/ClockGen.hs view
@@ -0,0 +1,195 @@+{-|+  Copyright   :  (C) 2023, QBayLogic B.V.+  License     :  BSD2 (see the file LICENSE)+  Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>++  Blackbox template functions for+  Clash.Xilinx.ClockGen.{clockWizard,clockWizardDifferential}+-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ViewPatterns #-}++module Clash.Primitives.Xilinx.ClockGen+  ( clockWizardTF+  , clockWizardTclTF+  , clockWizardDifferentialTF+  , clockWizardDifferentialTclTF+  ) where++import Control.Monad.State (State)+import Data.List.Infinite (Infinite(..), (...))+import Data.Maybe (fromMaybe)+import Data.String.Interpolate (i)+import qualified Data.Text as T+import Prettyprinter.Interpolate (__di)+import Text.Show.Pretty (ppShow)++import Clash.Signal (periodToHz)++import Clash.Backend (Backend)+import qualified Clash.Netlist.Id as Id+import Clash.Netlist.Types+import Clash.Netlist.Util (stripVoid)+import qualified Clash.Primitives.DSL as DSL+import Data.Text.Extra (showt)+import Data.Text.Prettyprint.Doc.Extra (Doc)++usedArguments :: [Int]+usedArguments = [knownDomIn, clocksCxt, clk, rst]+ where+  knownDomIn+    :< _clocksClass+    :< clocksCxt+    :< _numOutClocks+    :< clk+    :< rst+    :< _ = (0...)++clockWizardTF :: TemplateFunction+clockWizardTF =+  TemplateFunction usedArguments valid (clockWizardTemplate False)+ where+  valid = const True++clockWizardDifferentialTF :: TemplateFunction+clockWizardDifferentialTF =+  TemplateFunction usedArguments valid (clockWizardTemplate True)+ where+  valid = const True++clockWizardTemplate+  :: Backend s+  => Bool+  -> BlackBoxContext+  -> State s Doc+clockWizardTemplate isDifferential bbCtx+  | [ _knownDomIn+    , _clocksClass+    , _clocksCxt+    , _numOutClocks+    , clk+    , rst+    ] <- map fst (DSL.tInputs bbCtx)+  , [DSL.ety -> resultTy] <- DSL.tResults bbCtx+  , Product _ _ (init -> pllOutTys) <- resultTy+  , [compName] <- bbQsysIncName bbCtx+  = do+      clkWizInstName <- Id.makeBasic $ fromMaybe "clk_wiz" $ bbCtxName bbCtx+      DSL.declarationReturn bbCtx blockName $ do++        rstHigh <- DSL.unsafeToActiveHigh "reset" rst+        pllOuts <- DSL.declareN "pllOut" pllOutTys+        locked <- DSL.declare "locked" Bit+        pllLock <- DSL.boolFromBit "pllLock" locked++        let pllOutNames =+              map (\n -> "clk_out" <> showt n) [1 .. length pllOutTys]+            compInps = compClkInps <> [ ("reset", Bit) ]+            compOuts = zip pllOutNames pllOutTys <> [("locked", Bit)]+            inps = clkInps clk <> [ ("reset", rstHigh) ]+            outs = zip pllOutNames pllOuts <> [("locked", locked)]++        DSL.compInBlock compName compInps compOuts+        DSL.instDecl Empty (Id.unsafeMake compName) clkWizInstName [] inps outs++        pure [DSL.constructProduct resultTy (pllOuts <> [pllLock])]+  | otherwise+  = error $ ppShow bbCtx+ where+  blockName | isDifferential = "clockWizardDifferential"+            | otherwise      = "clockWizard"+  compClkInps | isDifferential = [ ("clk_in1_p", Bit)+                                 , ("clk_in1_n", Bit)+                                 ]+              | otherwise      = [ ("clk_in1", Bit) ]+  clkInps clk+    | isDifferential+    , DataCon (Product "Clash.Signal.Internal.DiffClock" _ clkTys) _ clkEs+      <- DSL.eex clk+    , [clkP@(Identifier _ Nothing), clkN@(Identifier _ Nothing)] <- clkEs+    , [clkPTy, clkNTy] <- clkTys+    = [ ("clk_in1_p", DSL.TExpr clkPTy clkP)+      , ("clk_in1_n", DSL.TExpr clkNTy clkN)+      ]+    | not isDifferential+    = [ ("clk_in1", clk) ]+    | otherwise+    = error $ ppShow bbCtx++clockWizardTclTF :: TemplateFunction+clockWizardTclTF =+  TemplateFunction usedArguments valid (clockWizardTclTemplate False)+ where+  valid = const True++clockWizardDifferentialTclTF :: TemplateFunction+clockWizardDifferentialTclTF =+  TemplateFunction usedArguments valid (clockWizardTclTemplate True)+ where+  valid = const True++clockWizardTclTemplate+  :: Backend s+  => Bool+  -> BlackBoxContext+  -> State s Doc+clockWizardTclTemplate isDifferential bbCtx+  |   (_,stripVoid -> kdIn,_)+    : _clocksClass+    : (_,stripVoid -> Product _ _ (init -> kdOuts),_)+    : _ <- bbInputs bbCtx+  , [compName] <- bbQsysIncName bbCtx+  = let+    clkFreq (KnownDomain _ p _ _ _ _) =+      periodToHz (fromInteger p) / 1e6 :: Double+    clkFreq _ =+      error $ "Internal error: not a KnownDomain\n" <> ppShow bbCtx++    clkInFreq = clkFreq kdIn+    clkOutFreqs = map clkFreq kdOuts++    clkOutProps = concat+      [ [ [i|CONFIG.CLKOUT#{n}_USED true \\|]+        , [i|CONFIG.CLKOUT#{n}_REQUESTED_OUT_FREQ #{clkOutFreq} \\|]+        ]+      | (clkOutFreq, n) <- zip clkOutFreqs [(1::Word)..]+      ]++    differentialPinString :: T.Text+    differentialPinString = if isDifferential+      then "Differential_clock_capable_pin"+      else "Single_ended_clock_capable_pin"++    propIndent = T.replicate 18 " "+    props = T.intercalate "\n"  . map (propIndent <>) $+      [ [i|CONFIG.PRIM_SOURCE #{differentialPinString} \\|]+      , [i|CONFIG.PRIM_IN_FREQ #{clkInFreq} \\|]+      ] <> clkOutProps++    bbText = [__di|+      namespace eval $tclIface {+        variable api 1+        variable scriptPurpose createIp+        variable ipName {#{compName}}++        proc createIp {ipName0 args} {+          create_ip \\+            -name clk_wiz \\+            -vendor xilinx.com \\+            -library ip \\+            -version 6.0 \\+            -module_name $ipName0 \\+            {*}$args++          set_property \\+            -dict [list \\+      #{props}+                  ] [get_ips $ipName0]+          return+        }+      }|]+    in pure bbText+  | otherwise+  = error ("clockWizardTclTemplate: bad bbContext: " <> show bbCtx)
src/Clash/Rewrite/Combinators.hs view
@@ -54,7 +54,7 @@  allR trans (TransformContext is c) (Letrec xes e) = do   xes' <- traverse rewriteBind xes-  e'   <- trans (TransformContext is' (LetBody bndrs:c)) e+  e'   <- trans (TransformContext is' (LetBody xes:c)) e   return (Letrec xes' e')  where   bndrs              = map fst xes
src/Clash/Rewrite/Types.hs view
@@ -16,6 +16,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-}  module Clash.Rewrite.Types where@@ -174,6 +175,13 @@     , Monad     , MonadFix     )+#if MIN_VERSION_transformers(0,5,6) && MIN_VERSION_mtl(2,3,0)+  deriving newtype+    ( MonadState (RewriteState extra)+    , MonadWriter Any+    , MonadReader RewriteEnv+    )+#endif  -- | Run the computation in the RewriteMonad runR
src/Clash/Rewrite/Util.hs view
@@ -79,7 +79,10 @@ import           Clash.Core.VarEnv   (InScopeSet, extendInScopeSet, extendInScopeSetList, mkInScopeSet,    uniqAway, uniqAway', mapVarEnv, eltsVarEnv, unitVarSet, emptyVarEnv,-   mkVarEnv, eltsVarSet, elemVarEnv, lookupVarEnv, extendVarEnv, elemVarSet)+   mkVarEnv, eltsVarSet, elemVarEnv, lookupVarEnv, extendVarEnv, elemVarSet,+   differenceVarEnv)+import           Clash.Data.UniqMap (UniqMap)+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Debug import           Clash.Driver.Types   (TransformationInfo(..), DebugOpts(..), BindingMap, Binding(..), IsPrim(..),@@ -554,9 +557,9 @@             -> RewriteMonad extra LetBinding liftBinding (var@Id {varName = idName} ,e) = do   -- Get all local FVs, excluding the 'idName' from the let-binding-  let unitFV :: Var a -> Const (UniqSet TyVar,UniqSet Id) (Var a)-      unitFV v@(Id {})    = Const (emptyUniqSet,unitUniqSet (coerce v))-      unitFV v@(TyVar {}) = Const (unitUniqSet (coerce v),emptyUniqSet)+  let unitFV :: Var a -> Const (UniqMap TyVar,UniqMap Id) (Var a)+      unitFV v@(Id {})    = Const (UniqMap.empty,UniqMap.singletonUnique (coerce v))+      unitFV v@(TyVar {}) = Const (UniqMap.singletonUnique (coerce v),UniqMap.empty)        interesting :: Var a -> Bool       interesting Id {idScope = GlobalId} = False@@ -565,8 +568,8 @@        (boundFTVsSet,boundFVsSet) =         getConst (Lens.foldMapOf (termFreeVars' interesting) unitFV e)-      boundFTVs = eltsUniqSet boundFTVsSet-      boundFVs  = eltsUniqSet boundFVsSet+      boundFTVs = UniqMap.elems boundFTVsSet+      boundFVs  = UniqMap.elems boundFVsSet    -- Make a new global ID   tcm       <- Lens.view tcCache@@ -594,12 +597,12 @@       newBody = mkTyLams (mkLams e' boundFVs) boundFTVs    -- Check if an alpha-equivalent global binder already exists-  aeqExisting <- (eltsUniqMap . filterUniqMap ((`aeqTerm` newBody) . bindingTerm)) <$> Lens.use bindings+  aeqExisting <- (UniqMap.elems . UniqMap.filter ((`aeqTerm` newBody) . bindingTerm)) <$> Lens.use bindings   case aeqExisting of     -- If it doesn't, create a new binder     [] -> do -- Add the created function to the list of global bindings              let r = newBodyId `globalIdOccursIn` newBody-             bindings %= extendUniqMap newBodyNm+             bindings %= UniqMap.insert newBodyNm                                     -- We mark this function as internal so that                                     -- it can be inlined at the very end of                                     -- the normalisation pipeline as part of the@@ -608,7 +611,11 @@                                     -- function at this moment for a reason!                                     -- (termination, CSE and DEC oppertunities,                                     -- ,etc.)+#if MIN_VERSION_ghc(9,2,0)+                                    (Binding newBodyId sp NoUserInlinePrag IsFun newBody r)+#else                                     (Binding newBodyId sp NoUserInline IsFun newBody r)+#endif              -- Return the new binder              return (var, newExpr)     -- If it does, use the existing binder@@ -650,7 +657,7 @@ addGlobalBind vNm ty sp inl body = do   let vId = mkGlobalId ty vNm       r = vId `globalIdOccursIn` body-  (ty,body) `deepseq` bindings %= extendUniqMap vNm (Binding vId sp inl IsFun body r)+  (ty,body) `deepseq` bindings %= UniqMap.insert vNm (Binding vId sp inl IsFun body r)  -- | Create a new name out of the given name, but with another unique. Resulting -- unique is guaranteed to not be in the given InScopeSet.@@ -672,7 +679,7 @@   -> m (Name a) cloneNameWithBindingMap binders nm = do   i <- getUniqueM-  return (uniqAway' (`elemUniqMapDirectly` binders) i (setUnique nm i))+  return (uniqAway' (`UniqMap.elem` binders) i (setUnique nm i))  {-# INLINE isUntranslatable #-} -- | Determine if a term cannot be represented in hardware@@ -724,7 +731,7 @@   -> Term   -> Rewrite extra   -> RewriteMonad extra Term-whnfRW isSubj ctx@(TransformContext is0 _) e rw = do+whnfRW isSubj ctx@(TransformContext is0 hist) e rw = do   tcm <- Lens.view tcCache   bndrs <- Lens.use bindings   eval <- Lens.view evaluator@@ -732,11 +739,18 @@   let (ids1,ids2) = splitSupply ids   uniqSupply Lens..= ids2   gh <- Lens.use globalHeap+  let lh = localBinders mempty hist -  case whnf' eval bndrs tcm gh ids1 is0 isSubj e of+  case whnf' eval bndrs lh tcm gh ids1 is0 isSubj e of     (!gh1,ph,v) -> do       globalHeap Lens..= gh1-      bindPureHeap tcm ph rw ctx v+      bindPureHeap tcm (ph `differenceVarEnv` lh) rw ctx v+ where+  localBinders acc [] = acc+  localBinders !acc (h:hs) = case h of+    LetBody ls -> localBinders (acc <> mkVarEnv ls) hs+    _ -> localBinders acc hs+ {-# SCC whnfRW #-}  -- | Binds variables on the PureHeap over the result of the rewrite@@ -785,9 +799,9 @@   where     heapIds = map fst bndrs     is1 = extendInScopeSetList is0 heapIds-    ctx = TransformContext is1 (LetBody heapIds : hist)+    ctx = TransformContext is1 (LetBody bndrs : hist) -    bndrs = map toLetBinding $ toListUniqMap heap+    bndrs = map toLetBinding $ UniqMap.toList heap      toLetBinding :: (Unique,Term) -> LetBinding     toLetBinding (uniq,term) = (nm, term)
src/Clash/Unique.hs view
@@ -1,103 +1,9 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeSynonymInstances #-}  module Clash.Unique-  ( -- * Unique-    Unique+  ( Unique   , Uniquable (..)-    -- * UniqMap-  , UniqMap-    -- ** Accessors-    -- *** Size information-  , nullUniqMap-    -- *** Indexing-  , lookupUniqMap-  , lookupUniqMap'-    -- ** Construction-  , emptyUniqMap-  , unitUniqMap-    -- ** Modification-  , extendUniqMap-  , extendUniqMapWith-  , extendListUniqMap-  , delUniqMap-  , delListUniqMap-  , unionUniqMap-  , unionUniqMapWith-  , differenceUniqMap-    -- ** Element-wise operations-    -- *** Mapping-  , mapUniqMap-  , mapMaybeUniqMap-    -- ** Working with predicates-    -- *** Filtering-  , filterUniqMap-    -- *** Searching-  , elemUniqMap-  , notElemUniqMap-  , elemUniqMapDirectly-    -- ** Folding-  , foldrWithUnique-  , foldlWithUnique'-    -- ** Conversions-    -- *** Lists-  , eltsUniqMap-  , keysUniqMap-  , listToUniqMap-  , toListUniqMap-    -- *** UniqSet-  , uniqMapToUniqSet-    -- * UniqSet-  , UniqSet-    -- ** Accessors-    -- *** Size information-  , nullUniqSet-    -- *** Indexing-  , lookupUniqSet-    -- ** Construction-  , emptyUniqSet-  , unitUniqSet-    -- ** Modifications-  , extendUniqSet-  , unionUniqSet-  , delUniqSetDirectly-    -- ** Working with predicates-    -- *** Searching-  , elemUniqSet-  , notElemUniqSet-  , elemUniqSetDirectly-    -- *** Misc-  , subsetUniqSet-  , disjointUniqSet-  , differenceUniqSet-    -- ** Conversions-    -- *** Lists-  , mkUniqSet-  , eltsUniqSet-  )-where--import           Control.DeepSeq (NFData)-import           Data.Binary (Binary)-import           Data.IntMap (IntMap)-import qualified Data.IntMap as IntMap--#if !MIN_VERSION_containers(0,6,2)-import qualified Data.IntMap.Extra as IntMap-#endif--import qualified Data.List   as List--#if MIN_VERSION_prettyprinter(1,7,0)-import           Prettyprinter-#else-import           Data.Text.Prettyprint.Doc-#endif--import           GHC.Stack--import           Clash.Pretty+  ) where  type Unique = Int @@ -105,344 +11,6 @@   getUnique :: a -> Unique   setUnique :: a -> Unique -> a -instance Uniquable Int where-  getUnique i = i-  setUnique _i0 i1 = i1---- | Map indexed by a 'Uniquable' key-newtype UniqMap a = UniqMap (IntMap a)-  deriving (Functor, Foldable, Traversable, Semigroup, Monoid, NFData, Binary)--instance ClashPretty a => ClashPretty (UniqMap a) where-  clashPretty (UniqMap env) =-    brackets $ fillSep $ punctuate comma $-      [ fromPretty uq <+> ":->" <+> clashPretty elt-      | (uq,elt) <- IntMap.toList env-      ]--instance ClashPretty a => Show (UniqMap a) where-  show = showDoc . clashPretty---- | The empty map-emptyUniqMap-  :: UniqMap a-emptyUniqMap = UniqMap IntMap.empty---- | Map with a single key-value pair-unitUniqMap-  :: Uniquable a-  => a-  -> b-  -> UniqMap b-unitUniqMap k v = UniqMap (IntMap.singleton (getUnique k) v)---- | Check whether the map is empty-nullUniqMap-  :: UniqMap a-  -> Bool-nullUniqMap (UniqMap m) = IntMap.null m---- | Extend the map with a new key-value pair. If the key already exists in the--- associated value will be overwritten-extendUniqMap-  :: Uniquable a-  => a-  -> b-  -> UniqMap b-  -> UniqMap b-extendUniqMap k x (UniqMap m) = UniqMap (IntMap.insert (getUnique k) x m)---- | Extend the map with a new key-value pair. If the key already exists in the--- associated value will be combined with the new value using the function--- provided-extendUniqMapWith-  :: Uniquable a-  => a-  -> b-  -> (b -> b -> b)-  -> UniqMap b-  -> UniqMap b-extendUniqMapWith k x f (UniqMap m) =-  UniqMap (IntMap.insertWith f (getUnique k) x m)---- | Extend the map with a list of key-value pairs. Positions with existing--- keys will be overwritten with the new values-extendListUniqMap-  :: Uniquable a-  => UniqMap b-  -> [(a, b)]-  -> UniqMap b-extendListUniqMap (UniqMap env) xs =-  UniqMap (List.foldl' (\m (k, v) -> IntMap.insert (getUnique k) v m) env xs)---- | Look up a value in the map-lookupUniqMap-  :: Uniquable a-  => a-  -> UniqMap b-  -> Maybe b-lookupUniqMap k (UniqMap m) = IntMap.lookup (getUnique k) m---- | Like 'lookupUniqMap'', but errors out when the key is not present-lookupUniqMap'-  :: (HasCallStack, Uniquable a)-  => UniqMap b-  -> a-  -> b-lookupUniqMap' (UniqMap m) k =-  IntMap.findWithDefault d k' m- where-  k' = getUnique k-  d  = error ("lookupUniqMap': key " ++ show k' ++ " is not an element of the map")---- | Check whether a key is in the map-elemUniqMap-  :: Uniquable a-  => a-  -> UniqMap b-  -> Bool-elemUniqMap k = elemUniqMapDirectly (getUnique k)---- | Check whether an element exists in the uniqmap based on a given `Unique`-elemUniqMapDirectly-  :: Unique-  -> UniqMap b-  -> Bool-elemUniqMapDirectly k (UniqMap m) = k `IntMap.member` m-{-# INLINE elemUniqMapDirectly #-}---- | Check whether a key is not in the map-notElemUniqMap-  :: Uniquable a-  => a-  -> UniqMap b-  -> Bool-notElemUniqMap k (UniqMap m) = IntMap.notMember (getUnique k) m---- | Derive a map where all the elements adhere to the predicate-filterUniqMap-  :: (b -> Bool)-  -> UniqMap b-  -> UniqMap b-filterUniqMap f (UniqMap m) = UniqMap (IntMap.filter f m)---- | Remove a key-value pair from the map-delUniqMap-  :: Uniquable a-  => UniqMap b-  -> a-  -> UniqMap b-delUniqMap (UniqMap env) v = UniqMap (IntMap.delete (getUnique v) env)---- | Remove a list of key-value pairs from the map-delListUniqMap-  :: Uniquable a-  => UniqMap b-  -> [a]-  -> UniqMap b-delListUniqMap (UniqMap env) vs =-  UniqMap (List.foldl' (\m v -> IntMap.delete (getUnique v) m) env vs)---- | A (left-biased) union of two maps-unionUniqMap-  :: UniqMap a-  -> UniqMap a-  -> UniqMap a-unionUniqMap (UniqMap m1) (UniqMap m2) = UniqMap (IntMap.union m1 m2)---- | A union of two maps, key-value pairs with the same key will be merged using--- the given function-unionUniqMapWith-  :: (a -> a -> a)-  -> UniqMap a-  -> UniqMap a-  -> UniqMap a-unionUniqMapWith f (UniqMap m1) (UniqMap m2) = UniqMap (IntMap.unionWith f m1 m2)---- | Get the difference between two maps-differenceUniqMap-  :: UniqMap a-  -> UniqMap a-  -> UniqMap a-differenceUniqMap (UniqMap m1) (UniqMap m2) = UniqMap (IntMap.difference m1 m2)---- | Convert a list of key-value pairs to a map-listToUniqMap-  :: Uniquable a-  => [(a,b)]-  -> UniqMap b-listToUniqMap xs =-  UniqMap (List.foldl' (\m (k, v) -> IntMap.insert (getUnique k) v m) IntMap.empty xs)---- | Convert a map to a list of key-value pairs-toListUniqMap-  :: UniqMap a-  -> [(Unique,a)]-toListUniqMap (UniqMap m) = IntMap.toList m---- | Extract the elements of a map into a list-eltsUniqMap-  :: UniqMap a-  -> [a]-eltsUniqMap (UniqMap m) = IntMap.elems m---- | Apply a function to every element in the map-mapUniqMap-  :: (a -> b)-  -> UniqMap a-  -> UniqMap b-mapUniqMap f (UniqMap m) = UniqMap (IntMap.map f m)---- | Extract the keys of a map into a list-keysUniqMap-  :: UniqMap a-  -> [Unique]-keysUniqMap (UniqMap m) = IntMap.keys m---- | Apply a function to every element in the map. When the function returns--- 'Nothing', the key-value pair will be removed-mapMaybeUniqMap-  :: (a -> Maybe b)-  -> UniqMap a-  -> UniqMap b-mapMaybeUniqMap f (UniqMap m) = UniqMap (IntMap.mapMaybe f m)---- | Right-fold over a map using both the key and value-foldrWithUnique-  :: (Unique -> a -> b -> b)-  -> b-  -> UniqMap a-  -> b-foldrWithUnique f s (UniqMap m) = IntMap.foldrWithKey f s m---- | Strict left-fold over a map using both the key and the value-foldlWithUnique'-  :: (a -> Unique -> b -> a)-  -> a-  -> UniqMap b-  -> a-foldlWithUnique' f s (UniqMap m) = IntMap.foldlWithKey' f s m---- | Set of things that have a 'Unique'------ Invariant: they keys in the map are the uniques of the values-newtype UniqSet a = UniqSet (IntMap a)-  deriving (Foldable, Semigroup, Monoid, NFData, Binary)--instance ClashPretty a => ClashPretty (UniqSet a) where-  clashPretty (UniqSet env) =-    braces (fillSep (map clashPretty (IntMap.elems env)))---- | The empty set-emptyUniqSet-  :: UniqSet a-emptyUniqSet = UniqSet IntMap.empty---- | Set with a single element-unitUniqSet-  :: Uniquable a-  => a-  -> UniqSet a-unitUniqSet a = UniqSet (IntMap.singleton (getUnique a) a)---- | Add an element to the set-extendUniqSet-  :: Uniquable a-  => UniqSet a-  -> a-  -> UniqSet a-extendUniqSet (UniqSet env) a = UniqSet (IntMap.insert (getUnique a) a env)---- | Union two sets-unionUniqSet-  :: UniqSet a-  -> UniqSet a-  -> UniqSet a-unionUniqSet (UniqSet env1) (UniqSet env2) = UniqSet (IntMap.union env1 env2)---- | Check whether an element exists in the set-elemUniqSet-  :: Uniquable a-  => a-  -> UniqSet a-  -> Bool-elemUniqSet a (UniqSet env) = IntMap.member (getUnique a) env---- | Check whether an element does not exist in the set-notElemUniqSet-  :: Uniquable a-  => a-  -> UniqSet a-  -> Bool-notElemUniqSet a (UniqSet env) = IntMap.notMember (getUnique a) env---- | Check whether an element exists in the set based on the `Unique` contained--- in that element-elemUniqSetDirectly-  :: Unique-  -> UniqSet a-  -> Bool-elemUniqSetDirectly k (UniqSet m) = k `IntMap.member` m---- | Check whether a set is empty-nullUniqSet-  :: UniqSet a-  -> Bool-nullUniqSet (UniqSet env) = IntMap.null env---- | Look up an element in the set, returns it if it exists-lookupUniqSet-  :: Uniquable a-  => a-  -> UniqSet b-  -> Maybe b-lookupUniqSet a (UniqSet env) = IntMap.lookup (getUnique a) env---- | Remove an element based on the `Unique` it contains-delUniqSetDirectly-  :: Unique-  -> UniqSet b-  -> UniqSet b-delUniqSetDirectly k (UniqSet env) = UniqSet (IntMap.delete k env)---- | Get the elements of the set as a list-eltsUniqSet-  :: UniqSet a-  -> [a]-eltsUniqSet (UniqSet env) = IntMap.elems env---- | Create a set out of a list of elements that contain a 'Unique'-mkUniqSet-  :: Uniquable a-  => [a]-  -> UniqSet a-mkUniqSet m = UniqSet (IntMap.fromList (map (\x -> (getUnique x,x)) m))---- | Convert a 'UniqMap' to a 'UniqSet'-uniqMapToUniqSet-  :: UniqMap a-  -> UniqSet a-uniqMapToUniqSet (UniqMap m) = UniqSet m---- | Check whether a A is a subset of B-subsetUniqSet-  :: UniqSet a-  -- ^ Set A-  -> UniqSet a-  -- ^ Set B-  -> Bool-subsetUniqSet (UniqSet e1) (UniqSet e2) = IntMap.null (IntMap.difference e1 e2)---- | Check whether A and B are disjoint-disjointUniqSet-  :: UniqSet a-  -> UniqSet a-  -> Bool-disjointUniqSet (UniqSet e1) (UniqSet e2) = IntMap.disjoint e1 e2---- | Take the difference of two sets-differenceUniqSet-  :: UniqSet a-  -> UniqSet a-  -> UniqSet a-differenceUniqSet (UniqSet e1) (UniqSet e2) = UniqSet (IntMap.difference e1 e2)+instance Uniquable Unique where+  getUnique = id+  setUnique = flip const
src/Clash/Util.hs view
@@ -18,6 +18,9 @@   ( module Clash.Util   , SrcSpan   , noSrcSpan+#if MIN_VERSION_transformers(0,6,0)+  , hoistMaybe+#endif   ) where @@ -25,6 +28,11 @@ import Control.Lens import Control.Monad.State            (MonadState,StateT) import qualified Control.Monad.State  as State+#if MIN_VERSION_transformers(0,6,0)+import Control.Monad.Trans.Maybe      (hoistMaybe)+#else+import Control.Monad.Trans.Maybe      (MaybeT (..))+#endif import Data.Hashable                  (Hashable) import Data.HashMap.Lazy              (HashMap) import qualified Data.HashMap.Lazy    as HashMapL@@ -59,6 +67,8 @@ import SrcLoc                         (SrcSpan, noSrcSpan) #endif +import Clash.Data.UniqMap (UniqMap)+import qualified Clash.Data.UniqMap as UniqMap import Clash.Debug import Clash.Unique @@ -66,6 +76,11 @@ import qualified Paths_clash_lib      (version) #endif +{- $setup+>>> :m -Prelude+>>> import Clash.Prelude+-}+ data ClashException = ClashException SrcSpan String (Maybe String)  instance Show ClashException where@@ -180,11 +195,11 @@   -> m v makeCachedU key l create = do   cache <- use l-  case lookupUniqMap key cache of+  case UniqMap.lookup key cache of     Just value -> return value     Nothing -> do       value <- create-      l %= extendUniqMap key value+      l %= UniqMap.insert key value       return value  -- | Cache the result of a monadic action using a 'OMap'@@ -257,8 +272,10 @@ clogBase _ _ = Nothing  -- | Get the package id of the type of a value--- >>> pkgIdFromTypeable (undefined :: TopEntity)--- "clash-prelude-0.99.3-64904d90747cb49e17166bbc86fec8678918e4ead3847193a395b258e680373c"+--+-- >>> pkgIdFromTypeable (0 :: Unsigned 32)+-- "clash-prelude-...+-- pkgIdFromTypeable :: Typeable a => a -> String pkgIdFromTypeable = tyConPackage . typeRepTyCon . typeOf @@ -322,3 +339,12 @@   , LangExt.Strict   , LangExt.StrictData   ]++thenCompare :: Ordering -> Ordering -> Ordering+thenCompare EQ rel = rel+thenCompare rel _  = rel++#if !MIN_VERSION_transformers(0,6,0)+hoistMaybe :: (Applicative m) => Maybe b -> MaybeT m b+hoistMaybe = MaybeT . pure+#endif
src/Clash/Util/Graph.hs view
@@ -19,8 +19,8 @@  import           Clash.Core.Var (Id) import           Clash.Core.Term (Term)+import qualified Clash.Data.UniqMap as UniqMap import           Clash.Driver.Types (BindingMap, Binding (bindingTerm))-import           Clash.Unique (lookupUniqMap', keysUniqMap) import           Clash.Normalize.Util (callGraph)  data Marker@@ -145,6 +145,6 @@   -- ^ Root of the call graph   -> [Term] callGraphBindings bindingsMap tm =-  map (bindingTerm . (bindingsMap `lookupUniqMap'`)) (keysUniqMap cg)+  map (bindingTerm . (`UniqMap.find` bindingsMap)) (UniqMap.keys cg)   where     cg = callGraph bindingsMap tm
src/Clash/Util/Interpolate.hs view
@@ -1,6 +1,6 @@ {-|-Copyright  :  (C) 2019, QBayLogic B.V.-                  2013, Nikita Volkov+Copyright  :  (C) 2019-2022, QBayLogic B.V.+                  2013     , Nikita Volkov License    :  BSD2 (see the file LICENSE) Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> -}@@ -42,8 +42,8 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TemplateHaskell #-} --- TODO: only export the @i@ quasiquotor when `ghcide` stop type-checking--- exanded quasiquote splices+-- TODO: only export the @i@ quasiquoter when `ghcide` stops type-checking+-- expanded quasiquote splices module Clash.Util.Interpolate (i, format, toString) where  import           Language.Haskell.Meta.Parse (parseExp)@@ -203,6 +203,30 @@   joinLiterals (Literal s0:Literal s1:ss) = joinLiterals (Literal (s0 ++ s1):ss)   joinLiterals (n:ns) = n:joinLiterals ns +{-|+@i@ will reflow the quasi-quoted text to 90 columns wide. If an interpolation+variable is on its own line and expands to a multi-line string, the interpolated+text will be indented the same as the interpolation variable was:++> :set -XQuasiQuotes+> :{+> a = "Multi\nLine\nString"+> b = [i|+>     This line will be reflowed+>     and the interpolated+>     multi-line string here:+>         #{a}+>     will be indented. This+>     text is outdented again.+>   |]+> :}+> putStrLn b+This line will be reflowed and the interpolated multi-line string here:+    Multi+    Line+    String+will be indented. This text is outdented again.+-} i :: QuasiQuoter i = QuasiQuoter {     quoteExp = (varE 'format `appE`) . toExp . parseNodes . decodeNewlines@@ -250,6 +274,7 @@  ------------------------------------------------------------------- -- Everything below this line is unchanged from neat-interpolate --+-- apart from updated module identifier strings                  -- ------------------------------------------------------------------- decodeNewlines :: String -> String decodeNewlines = go@@ -363,9 +388,9 @@     readHex :: String -> Int     readHex xs = case N.readHex xs of       [(n, "")] -> n-      _ -> error "Data.String.Interpolate.Util.readHex: no parse"+      _ -> error $ (show 'unescape) <> " readHex: no parse"      readOct :: String -> Int     readOct xs = case N.readOct xs of       [(n, "")] -> n-      _ -> error "Data.String.Interpolate.Util.readHex: no parse"+      _ -> error $ (show 'unescape) <> " readOct: no parse"
src/Data/Aeson/Extra.hs view
@@ -22,7 +22,8 @@ import qualified Data.Text.Lazy.Encoding as LT import           Data.Text.Encoding.Error (UnicodeException(..)) import           Data.List            (intercalate)-import           Data.List.Extra      (groupOn)+import           Data.List.NonEmpty   (NonEmpty (..))+import qualified Data.List.NonEmpty   as NE import           Data.Tuple.Extra     (second, first) import           Data.Aeson           (FromJSON, Result (..), fromJSON) import           Data.Aeson.Parser    (json)@@ -100,12 +101,13 @@   go2 n inString (_:rest) = go2 n inString rest    toLineMap :: [Int] -> LineMap-  toLineMap virtuals =+  toLineMap [] = IntMap.empty+  toLineMap (v:virtuals) =       IntMap.fromList     $ map (second (\reals -> (minimum reals, maximum reals)))-    $ map (first head . unzip)-    $ groupOn fst-    $ zip virtuals [(0::Int)..]+    $ map (first NE.head . NE.unzip)+    $ NE.groupBy (\(a,_) (b,_) -> a == b)+    $ NE.zip (v :| virtuals) (NE.iterate (+1) (0 :: Int))  genLineErr' :: [Text] -> (Int, Int) -> [Int] -> Text genLineErr' allLines range errorLines =
src/Data/List/Extra.hs view
@@ -25,7 +25,9 @@ import "extra" Data.List.Extra as NeilsExtra import "extra" Control.Monad.Extra (anyM, allM, orM, partitionM) +#if !MIN_VERSION_base(4,18,0) import Control.Applicative (liftA2)+#endif  #if defined(DEBUG) import GHC.Stack (HasCallStack)
src/GHC/BasicTypes/Extra.hs view
@@ -1,7 +1,8 @@ {-|   Copyright   :  (C) 2017, Google Inc.+                     2023, QBayLogic B.V.   License     :  BSD2 (see the file LICENSE)-  Maintainer  :  Christiaan Baaij <christiaan.baaij@gmail.com>+  Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com> -}  {-# LANGUAGE CPP #-}@@ -18,6 +19,51 @@ import Data.Binary import GHC.Generics +#if MIN_VERSION_ghc(9,4,0)+import GHC.Types.SourceText+#endif++#if MIN_VERSION_ghc(9,8,0)+import Data.ByteString+import GHC.Data.FastString+import Unsafe.Coerce+#endif+ deriving instance Generic InlineSpec instance NFData InlineSpec instance Binary InlineSpec++#if MIN_VERSION_ghc(9,8,0)+deriving instance Generic FastString+instance Binary FastString+instance Binary FastZString where+  put = put . fastZStringToByteString+  get = unsafeCoerce (get :: Get ByteString)+#endif++#if MIN_VERSION_ghc(9,4,0)+deriving instance Generic SourceText+#if !MIN_VERSION_ghc(9,8,0)+instance NFData SourceText+#endif+instance Binary SourceText+#endif++-- | Determine whether given 'InlineSpec' is NOINLINE or more strict (OPAQUE)+isNoInline :: InlineSpec -> Bool+isNoInline NoInline{} = True+#if MIN_VERSION_ghc(9,4,0)+isNoInline Opaque{} = True+#endif+isNoInline _ = False++-- | Determine whether given 'InlineSpec' is OPAQUE. If this function is used on+-- a GHC that does not support OPAQUE yet (<9.4), it will return 'True' if given+-- 'InlineSpec' is NOINLINE instead.+isOpaque :: InlineSpec -> Bool+#if MIN_VERSION_ghc(9,4,0)+isOpaque Opaque{} = True+#else+isOpaque NoInline{} = True+#endif+isOpaque _ = False
src/GHC/SrcLoc/Extra.hs view
@@ -30,11 +30,14 @@    srcSpanFile, srcSpanStartLine, srcSpanEndLine, srcSpanStartCol, srcSpanEndCol) import FastString                           (FastString (..), bytesFS, mkFastStringByteList) #endif-+#if MIN_VERSION_ghc(9,4,0)+import qualified GHC.Data.Strict+#endif -#if MIN_VERSION_ghc(9,0,0)-deriving instance Ord SrcSpan-deriving instance Ord UnhelpfulSpanReason+#if MIN_VERSION_ghc(9,4,0)+deriving instance Generic (GHC.Data.Strict.Maybe a)+instance Hashable a => Hashable (GHC.Data.Strict.Maybe a)+instance Binary a => Binary (GHC.Data.Strict.Maybe a) #endif  deriving instance Generic SrcSpan
+ tests/Clash/Tests/Core/TermLiteral.hs view
@@ -0,0 +1,67 @@+{-|+Copyright   :  (C) 2022, Google Inc.+License     :  BSD2 (see the file LICENSE)+Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>++Tests for 'Clash.Core.TermLiteral'.+-}+{-# LANGUAGE TemplateHaskell #-}++{-# OPTIONS_GHC -Wno-orphans #-}++module Clash.Tests.Core.TermLiteral where++import Data.Proxy+import Data.Typeable+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.TH++import Clash.Core.TermLiteral+import Clash.Promoted.Nat++import Clash.Tests.Core.TermLiteral.Types++showTypeable :: Typeable a => Proxy a -> String+showTypeable proxy = showsPrec 0 (typeRep proxy) ""++eqTest :: (TermLiteral a, Typeable a) => Proxy a -> Assertion+eqTest proxy = showType proxy @=? showTypeable proxy++case_int :: Assertion+case_int = eqTest (Proxy @Int)++case_maybe_int :: Assertion+case_maybe_int = eqTest (Proxy @(Maybe Int))++case_maybe_maybe_int :: Assertion+case_maybe_maybe_int = eqTest (Proxy @(Maybe (Maybe Int)))++case_either_int_int :: Assertion+case_either_int_int = eqTest (Proxy @(Either Int Int))++case_either_int_maybe_int :: Assertion+case_either_int_maybe_int = eqTest (Proxy @(Either Int (Maybe Int)))++case_int_int :: Assertion+case_int_int = eqTest (Proxy @(Int, Int))++case_maybe_int_maybe_int :: Assertion+case_maybe_int_maybe_int = eqTest (Proxy @(Maybe Int, Maybe Int))++case_maybe_int_int :: Assertion+case_maybe_int_int = eqTest (Proxy @(Maybe (Int, Int)))++case_snat :: Assertion+case_snat = "SNat _" @=? showType (Proxy @(SNat 5))++case_maybe_snat :: Assertion+case_maybe_snat = "Maybe (SNat _)" @=? showType (Proxy @(Maybe (SNat 5)))++deriveTermLiteral ''NatTypeArg++case_natTypeArg :: Assertion+case_natTypeArg = "NatTypeArg _" @=? showType (Proxy @(NatTypeArg 10))++tests :: TestTree+tests = testGroup "Clash.Tests.Core.TermLiteral" [$(testGroupGenerator)]
+ tests/Clash/Tests/Core/TermLiteral/Types.hs view
@@ -0,0 +1,5 @@+module Clash.Tests.Core.TermLiteral.Types where++import Clash.Promoted.Nat++data NatTypeArg n = NatTypeArg (SNat n)
tests/Clash/Tests/Driver/Manifest.hs view
@@ -7,6 +7,7 @@ import Data.ByteString (ByteString) import qualified Data.ByteString.Base16 as Base16 import Data.Coerce (coerce)+import Data.Either (fromRight) import Data.Text (Text) import qualified Data.HashMap.Strict as HashMap import qualified Data.Text as Text@@ -89,7 +90,8 @@         manifest@Manifest{fileNames} <- genManifest         let           encoded = Aeson.encodePretty manifest-          Right (FilesManifest fileNamesDecoded) = Aeson.eitherDecode encoded+          FilesManifest fileNamesDecoded =+            fromRight (error "Failed to decode manifest") (Aeson.eitherDecode encoded)          pure (fileNamesDecoded Q.=== fileNames)     ]
tests/Clash/Tests/Netlist/Id.hs view
@@ -170,15 +170,15 @@     , testGroup "pretty names"       [ testCase "(# #) => Unit" $ "Unit" @=? roundTrip' "(# #)"       , testCase "() => Unit" $ "Unit" @=? roundTrip' "()"-      , testCase "(,,) => Tup3" $ "Tup3" @=? roundTrip' "(,,)"-      , testCase "(#,,,,#) => Tup5" $ "Tup5" @=? roundTrip' "(,,,,)"+      , testCase "(,,) => Tuple3" $ "Tuple3" @=? roundTrip' "(,,)"+      , testCase "(#,,,,#) => Tuple5" $ "Tuple5" @=? roundTrip' "(,,,,)"       ]      , testGroup "pretty names (force basic)"       [ testCase "(# #) => Unit" $ "Unit" @=? roundTrip False VHDL "(# #)"       , testCase "() => Unit" $ "Unit" @=? roundTrip False VHDL "()"-      , testCase "(,,) => Tup3" $ "Tup3" @=? roundTrip False VHDL "(,,)"-      , testCase "(#,,,,#) => Tup5" $ "Tup5" @=? roundTrip False VHDL "(,,,,)"+      , testCase "(,,) => Tuple3" $ "Tuple3" @=? roundTrip False VHDL "(,,)"+      , testCase "(#,,,,#) => Tuple5" $ "Tuple5" @=? roundTrip False VHDL "(,,,,)"       ]      , testGroup "disallow escaped identifiers"
tests/Clash/Tests/Normalize/Transformations.hs view
@@ -3,35 +3,26 @@ License    :  BSD2 (see the file LICENSE) Maintainer :  QBayLogic B.V. <devops@qbaylogic.com> -}-{-# OPTIONS_GHC -fno-warn-unused-imports #-} {-# LANGUAGE QuasiQuotes #-}  module Clash.Tests.Normalize.Transformations where +import Data.Maybe (fromMaybe)+ import Clash.Normalize.Transformations (inlineBndrsCleanup) import Clash.Core.VarEnv-  (mkInScopeSet, mkVarSet, mkVarEnv, emptyVarEnv, extendInScopeSetList)+  (mkInScopeSet, mkVarSet, mkVarEnv, emptyVarEnv) import Clash.Core.FreeVars (countFreeOccurances) import Clash.Core.Term-import Clash.Unique (UniqSet, extendUniqSet, unitUniqSet)  import Test.Tasty import Test.Tasty.HUnit  import Test.Clash.Rewrite (parseToTermQQ, parseToTerm) -import Debug.Trace-import Clash.Core.Pretty (showPpr)- t1337a :: Term-t1337a = Letrec keep1 result- where-  (keep0:inlines)= map (\(v,e) -> (v,((v,e),countFreeOccurances e))) binds-  is = mkInScopeSet (mkVarSet (map fst binds))--  keep1 = inlineBndrsCleanup is (mkVarEnv inlines) emptyVarEnv [snd keep0]--  Letrec binds result =+t1337a = fromMaybe (error "failed to build term") $ do+  Letrec binds result <- pure $     [parseToTermQQ|       let         -- Types don't mean anything for this example@@ -46,6 +37,13 @@         result_1     |] +  (keep0:inlines) <- pure (map (\(v,e) -> (v,((v,e),countFreeOccurances e))) binds)+  let is = mkInScopeSet (mkVarSet (map fst binds))++  let keep1 = inlineBndrsCleanup is (mkVarEnv inlines) emptyVarEnv [snd keep0]++  return (Letrec keep1 result)+ t1337a_result :: Term t1337a_result = [parseToTermQQ|   let@@ -57,14 +55,9 @@ |]  t1337b :: Term-t1337b = Letrec keep1 result- where-  (keep0:inlines)= map (\(v,e) -> (v,((v,e),countFreeOccurances e))) binds-  is = mkInScopeSet (mkVarSet (map fst binds))--  keep1 = inlineBndrsCleanup is (mkVarEnv inlines) emptyVarEnv [snd keep0]+t1337b = fromMaybe (error "failed to build term") $ do -  Letrec binds result =+  Letrec binds result <- pure $     [parseToTermQQ|       let         -- Types don't mean anything for this example@@ -80,6 +73,13 @@         result_1     |] +  (keep0:inlines) <- pure (map (\(v,e) -> (v,((v,e),countFreeOccurances e))) binds)+  let is = mkInScopeSet (mkVarSet (map fst binds))++  let keep1 = inlineBndrsCleanup is (mkVarEnv inlines) emptyVarEnv [snd keep0]++  return (Letrec keep1 result)+ t1337b_result :: Term t1337b_result = [parseToTermQQ|   let@@ -91,15 +91,8 @@ |]  t1337c :: Term-t1337c = Letrec keep1 result- where-  (keep0:inlines)= map (\(v,e) -> (v,((v,e),countFreeOccurances e))) binds-  Var fv = parseToTerm "freevar_5 :: Int"-  is = mkInScopeSet (mkVarSet (fv : map fst binds))--  keep1 = inlineBndrsCleanup is (mkVarEnv inlines) emptyVarEnv [snd keep0]--  Letrec binds result =+t1337c = fromMaybe (error "failed to build term") $ do+  Letrec binds result <- pure $     [parseToTermQQ|       let         result_1, a_2, b_3, c_4 :: Int@@ -112,6 +105,14 @@       in         result_1     |]++  (keep0:inlines) <- pure (map (\(v,e) -> (v,((v,e),countFreeOccurances e))) binds)+  Var fv <- pure (parseToTerm "freevar_5 :: Int")+  let is = mkInScopeSet (mkVarSet (fv : map fst binds))++  let keep1 = inlineBndrsCleanup is (mkVarEnv inlines) emptyVarEnv [snd keep0]++  return (Letrec keep1 result)  t1337c_result :: Term t1337c_result = [parseToTermQQ|
tests/Test/Clash/Rewrite.hs view
@@ -11,7 +11,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TemplateHaskellQuotes #-}  module Test.Clash.Rewrite where @@ -26,7 +26,6 @@ import Clash.Rewrite.Types import Clash.Rewrite.Util (runRewrite) import Clash.Normalize.Types-import Clash.Unique (emptyUniqMap) import qualified Clash.Util.Interpolate as I  import Control.Applicative ((<|>))@@ -62,10 +61,11 @@   def = RewriteEnv     { _clashEnv = ClashEnv         { envOpts = defClashOpts { opt_debug = debugSilent }-        , envTyConMap = emptyUniqMap+        , envTyConMap = mempty         , envTupleTyCons = IntMap.empty         , envPrimitives = HashMap.empty         , envCustomReprs = buildCustomReprs []+        , envDomains = HashMap.empty         }     , _typeTranslator=error "_typeTranslator: NYI"     , _peEvaluator=error "_peEvaluator: NYI"
+ tests/doctests.hs view
@@ -0,0 +1,7 @@+module Main where++import System.Environment (getArgs)+import Test.DocTest (mainFromCabal)++main :: IO ()+main = mainFromCabal "clash-lib" =<< getArgs
tests/unittests.hs view
@@ -5,10 +5,11 @@  import qualified Clash.Tests.Core.FreeVars import qualified Clash.Tests.Core.Subst+import qualified Clash.Tests.Core.TermLiteral import qualified Clash.Tests.Driver.Manifest import qualified Clash.Tests.Netlist.Id-import qualified Clash.Tests.Util.Interpolate import qualified Clash.Tests.Normalize.Transformations+import qualified Clash.Tests.Util.Interpolate  -- AFAIK there's no good way to override the default, so we just detect the -- default value and change it.@@ -20,10 +21,11 @@ tests = testGroup "Unittests"   [ Clash.Tests.Core.FreeVars.tests   , Clash.Tests.Core.Subst.tests+  , Clash.Tests.Core.TermLiteral.tests   , Clash.Tests.Driver.Manifest.tests-  , Clash.Tests.Util.Interpolate.tests   , Clash.Tests.Netlist.Id.tests   , Clash.Tests.Normalize.Transformations.tests+  , Clash.Tests.Util.Interpolate.tests   ]  main :: IO ()
+ tools/static-files.hs view
@@ -0,0 +1,71 @@+{-|+Copyright   :  (C) 2022     , Google Inc.+License     :  BSD2 (see the file LICENSE)+Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>++Produce static files that are useful when working with Clash designs.+-}++{-# LANGUAGE QuasiQuotes #-}++module Main where++import Control.Monad (when)+import Control.Monad.Extra (whenM, unlessM)+import Prelude+import System.Console.Docopt+  (Docopt, docopt, isPresent, getArg, longOption, parseArgsOrExit)+import System.Directory (copyFile, doesDirectoryExist, doesFileExist)+import System.Environment (getArgs)+import System.Exit (die)+import System.FilePath (takeDirectory)++import Clash.DataFiles++patterns :: Docopt+patterns = [docopt|+Obtain static files useful when working with Clash designs++Currently, only the Tcl connector is available.++Usage:+  static-files [--force] [--verbose] --tcl-connector=<outfile>++Options:+  -f, --force                  Overwrite existing files+  -v, --verbose                Explain what is being done+  --tcl-connector=<outfile>    Write a Tcl script to a file that can parse Clash+                               manifest JSON files and emit the correct commands+                               for loading the design into Vivado+|]++-- Checks whether it looks like we can write a file in the location @path@,+-- accounting for the @--force@ command line argument. Exit with a descriptive+-- error message if something's amiss.+createOkayOrDie ::+  FilePath ->+  Bool ->+  IO ()+createOkayOrDie path force = do+  let pathDir = takeDirectory path+  unlessM (doesDirectoryExist pathDir) $+    die $ "Directory not found: " ++ pathDir+  whenM (doesDirectoryExist path) $+    die $ path ++ " is a directory. Please specify a file name."+  exists <- doesFileExist path+  when (exists && not force) $+    die $ path ++ " already exists and --force not specified. " +++                  "Refusing to overwrite."++main :: IO ()+main = do+  args <- parseArgsOrExit patterns =<< getArgs+  -- Since we got here, we know we got invoked with the sole mandatory option+  -- @--tcl-connector@ and its mandatory argument+  let force = args `isPresent` (longOption "force")+      verbose = args `isPresent` (longOption "verbose")+      Just outFile = args `getArg` (longOption "tcl-connector")+  createOkayOrDie outFile force+  inFile <- tclConnector+  copyFile inFile outFile+  when verbose $ putStrLn $ "Tcl Connector written to " ++ outFile