content: {-|
    Copyright   :  (C) 2019-2023, Myrtle Software Ltd
    License     :  BSD2 (see the file LICENSE)
    Maintainer  :  QBayLogic B.V. <devops@qbaylogic.com>
  
  Control naming and deduplication in the generated HDL code. Explicitly nameable
  things include:
  
  * Component (VHDL) / module ((System)Verilog) instances
  
  * Registers
  
  * Terms
  
  Refer to "Clash.Annotations.TopEntity" for controlling naming of entities
  (VHDL) / modules ((System)Verilog) and their ports.
  -}
  
  {-# LANGUAGE CPP #-}
  {-# LANGUAGE DeriveAnyClass #-}
  {-# LANGUAGE QuasiQuotes #-}
  {-# LANGUAGE TemplateHaskellQuotes #-}
  
  module Clash.Magic
    (
    -- ** Functions to control names of identifiers in HDL
      prefixName
    , suffixName
    , suffixNameP
    , suffixNameFromNat
    , suffixNameFromNatP
    , setName
    , nameHint
  
    -- ** Functions to control Clash's (de)duplication mechanisms
    , deDup
    , noDeDup
  
    -- ** Utilities to differentiate between simulation and generating HDL
    , clashSimulation
    , SimOnly (..)
  
    -- * Static assertions
    , clashCompileError
    ) where
  
  import Clash.Annotations.Primitive (Primitive(..), hasBlackBox)
  import Clash.NamedTypes            ((:::))
  import Clash.Promoted.Symbol       (SSymbol)
  import Clash.XException            (NFDataX)
  import Data.String.Interpolate     (__i)
  import GHC.Generics                (Generic)
  import GHC.Magic                   (noinline)
  import GHC.Stack                   (HasCallStack, withFrozenCallStack)
  import GHC.TypeLits                (Nat,Symbol)
  
  -- | Prefix instance and register names with the given 'Symbol'
  prefixName
    :: forall (name :: Symbol) a . a -> name ::: a
  prefixName = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE prefixName #-}
  
  -- | Suffix instance and register names with the given 'Symbol'
  suffixName
    :: forall (name :: Symbol) a . a -> name ::: a
  suffixName = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE suffixName #-}
  
  -- | Suffix instance and register names with the given 'Nat'
  suffixNameFromNat
    :: forall (name :: Nat) a . a -> name ::: a
  suffixNameFromNat = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE suffixNameFromNat #-}
  
  -- | Suffix instance and register names with the given 'Symbol', but add it
  -- in front of other suffixes.
  --
  -- When you write
  --
  -- @
  -- suffixName \@\"A\" (suffixName \@\"B\" f))
  -- @
  --
  -- you get register and instance names inside /f/ with the suffix: "_B_A"
  --
  -- However, if you want them in the other order you can write:
  --
  -- @
  -- suffixNameP \@\"A\" (suffixName \@\"B\" f))
  -- @
  --
  -- so that names inside /f/ will have the suffix "_A_B"
  suffixNameP
    :: forall (name :: Symbol) a . a -> name ::: a
  suffixNameP = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE suffixNameP #-}
  
  -- | Suffix instance and register names with the given 'Nat', but add it in
  -- front of other suffixes.
  --
  -- When you write
  --
  -- @
  -- suffixNameNat \@1 (suffixName \@\"B\" f))
  -- @
  --
  -- you get register and instance names inside /f/ with the suffix: "_B_1"
  --
  -- However, if you want them in the other order you can write:
  --
  -- @
  -- suffixNameNatP \@1 (suffixName \@\"B\" f))
  -- @
  --
  -- so that names inside /f/ will have the suffix "_1_B"
  suffixNameFromNatP
    :: forall (name :: Nat) a . a -> name ::: a
  suffixNameFromNatP = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE suffixNameFromNatP #-}
  
  -- | Name the instance or register with the given 'Symbol', instead of using
  -- an auto-generated name. Pre- and suffixes annotated with 'prefixName' and
  -- 'suffixName' will be added to both instances and registers named with
  -- 'setName' and instances and registers that are auto-named.
  setName
    :: forall (name :: Symbol) a . a -> name ::: a
  setName = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE setName #-}
  
  -- | Name a given term, such as one of type 'Clash.Signal.Signal', using the
  -- given 'SSymbol'. Results in a declaration with the name used as the
  -- identifier in the generated HDL code.
  --
  -- Example usage:
  --
  -- @
  -- nameHint (SSymbol @"identifier") term
  -- @
  --
  -- __NB__: The given name should be considered a hint as it may be expanded,
  -- e.g. if it collides with existing identifiers.
  nameHint
    :: SSymbol sym
    -- ^ A hint for a name
    -> a -> a
  nameHint = seq
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE nameHint #-}
  {-# ANN nameHint hasBlackBox #-}
  
  -- | Force deduplication, i.e. share a function or operator between multiple
  -- branches.
  --
  -- By default Clash converts
  --
  -- @
  -- case x of
  --   A -> 3 * y
  --   B -> x * x
  -- @
  --
  -- to
  --
  -- @
  -- let f_arg0 = case x of {A -> 3; _ -> x}
  --     f_arg1 = case x of {A -> y; _ -> x}
  --     f_out  = f_arg0 * f_arg1
  -- in  case x of
  --       A -> f_out
  --       B -> f_out
  -- @
  --
  -- However, it won't do this for:
  --
  -- @
  -- case x of
  --   A -> 3 + y
  --   B -> x + x
  -- @
  --
  -- Because according to the internal heuristics the multiplexer introduced for
  -- the deduplication are more expensive than the addition. This might not be
  -- the case for your particular platform.
  --
  -- In these cases you can force Clash to deduplicate by:
  --
  -- @
  -- case x of
  --   A -> 'deDup' (3 + y)
  --   B -> 'deDup' (x + x)
  -- @
  deDup
    :: forall a . a -> a
  deDup = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE deDup #-}
  
  -- | Do not deduplicate, i.e. /keep/, an applied function inside a
  -- case-alternative; do not try to share the function between multiple
  -- branches.
  --
  -- By default Clash converts
  --
  -- @
  -- case x of
  --   A -> f 3 y
  --   B -> f x x
  --   C -> h x
  -- @
  --
  -- to
  --
  -- @
  -- let f_arg0 = case x of {A -> 3; _ -> x}
  --     f_arg1 = case x of {A -> y; _ -> x}
  --     f_out  = f f_arg0 f_arg1
  -- in  case x of
  --       A -> f_out
  --       B -> f_out
  --       C -> h x
  -- @
  --
  -- i.e. it deduplicates functions (and operators such as multiplication) between
  -- case-alternatives to save on area. This comes at the cost of multiplexing the
  -- arguments for the deduplicated function.
  --
  -- There are two reasons you would want to stop Clash from doing this:
  --
  -- 1. The deduplicated function is in the critical path, and the addition of the
  --    multiplexers further increased the propagation delay.
  --
  -- 2. Clash's heuristics were off, and the addition of the multiplexers actually
  --    made the final circuit larger instead of smaller.
  --
  -- In these cases you want to tell Clash not to deduplicate:
  --
  -- @
  -- case x of
  --   A -> 'noDeDup' f 3 y
  --   B -> f x x
  --   C -> h x
  -- @
  --
  -- Where the application of /f/ in the /A/-alternative is now explicitly not
  -- deduplicated, and given that the /f/ in the B-alternative is the only
  -- remaining application of /f/ in the case-expression it is also not
  -- deduplicated.
  --
  -- Note that if the /C/-alternative also had an application of /f/, then the
  -- applications of /f/ in the /B/- and /C/-alternatives would have been
  -- deduplicated; i.e. the final circuit would have had two application of /f/.
  noDeDup
    :: forall a . a -> a
  noDeDup = id
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE noDeDup #-}
  
  -- | 'True' in Haskell/Clash simulation. Replaced by 'False' when generating HDL.
  clashSimulation :: Bool
  clashSimulation = noinline True
  -- The 'noinline' is here to prevent SpecConstr from poking through the OPAQUE, see #2736
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE clashSimulation #-}
  
  -- | 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.
  data SimOnly a = SimOnly a
    deriving (Generic, Eq, Ord, Foldable, Traversable, NFDataX)
  {-# ANN SimOnly hasBlackBox #-}
  
  instance Functor SimOnly where
    fmap f (SimOnly a) = SimOnly (f a)
  
  instance Applicative SimOnly where
    pure = SimOnly
    (SimOnly f) <*> (SimOnly a) = SimOnly (f a)
  
  instance Monad SimOnly where
    (SimOnly a) >>= f = f a
  
  instance Semigroup a => Semigroup (SimOnly a) where
    (SimOnly a) <> (SimOnly b) = SimOnly (a <> b)
  
  instance Monoid a => Monoid (SimOnly a) where
    mempty = SimOnly mempty
  
  -- | Same as 'error' but will make HDL generation fail if included in the
  -- final circuit.
  --
  -- This is useful for the error case of static assertions.
  --
  -- Note that the error message needs to be a literal, and during HDL generation
  -- the error message does not include a stack trace, so it had better be
  -- descriptive.
  clashCompileError :: forall a . HasCallStack => String -> a
  clashCompileError msg = withFrozenCallStack $ error msg
  -- See: https://github.com/clash-lang/clash-compiler/pull/2511
  {-# CLASH_OPAQUE clashCompileError #-}
  {-# ANN clashCompileError (
    let primName = 'clashCompileError
    in InlineYamlPrimitive [minBound..] [__i|
      BlackBoxHaskell:
        name: #{primName}
        templateFunction: Clash.Primitives.Magic.clashCompileErrorBBF
      |]) #-}
  