{-|
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 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 Data.String.Interpolate (__i)
import GHC.Magic (noinline)
import GHC.Stack (HasCallStack, withFrozenCallStack)
import Clash.NamedTypes ((:::))
import GHC.TypeLits (Nat,Symbol)
import Clash.Promoted.Symbol (SSymbol)
import Clash.Annotations.Primitive (Primitive(..), hasBlackBox)
-- | 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 (Eq, Ord, Foldable, Traversable)
{-# 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
|]) #-}