content: {-|
    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>
  -}
  
  {-# LANGUAGE CPP               #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Clash.Backend where
  
  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
  import Control.Monad.State                  (State)
  import Data.Text.Prettyprint.Doc.Extra      (Doc)
  
  #if MIN_VERSION_ghc(9,0,0)
  import GHC.Types.SrcLoc (SrcSpan)
  #else
  import SrcLoc (SrcSpan)
  #endif
  
  import Clash.Driver.Types (ClashOpts)
  import {-# SOURCE #-} Clash.Netlist.Types
    (Component, Declaration, Expr, HWType, Identifier, IdentifierSet, HasIdentifierSet, UsageMap)
  import Clash.Netlist.BlackBox.Types
  
  import Clash.Signal.Internal                (VDomainConfiguration)
  import Clash.Annotations.Primitive          (HDL)
  
  #ifdef CABAL
  import qualified Paths_clash_lib
  import qualified Data.Version
  #else
  import qualified System.FilePath
  #endif
  
  primsRoot :: IO FilePath
  #ifdef CABAL
  primsRoot = Paths_clash_lib.getDataFileName "prims"
  #else
  primsRoot = return ("clash-lib" System.FilePath.</> "prims")
  #endif
  
  clashVer :: String
  #ifdef CABAL
  clashVer = Data.Version.showVersion Paths_clash_lib.version
  #else
  clashVer = "development"
  #endif
  
  type ModName = Text
  
  -- | Is a type used for internal or external use
  data Usage
    = Internal
    -- ^ Internal use
    | External Text
    -- ^ External use, field indicates the library name
  
  -- | Is '-fclash-aggresive-x-optimization-blackbox' set?
  newtype AggressiveXOptBB = AggressiveXOptBB Bool
  
  -- | Is '-fclash-render-enums' set?
  newtype RenderEnums = RenderEnums Bool
  
  -- | Kind of a HDL type. Used to determine whether types need conversions in
  -- order to cross top entity boundaries.
  data HWKind
    = PrimitiveType
    -- ^ A type defined in an HDL spec. Usually types such as: bool, bit, ..
    | SynonymType
    -- ^ A user defined type that's simply a synonym for another type, very much
    -- like a type synonym in Haskell. As long as two synonym types refer to the
    -- same type, they can be used interchangeably. E.g., a subtype in VHDL.
    | UserType
    -- ^ User defined type that's not interchangeable with any others, even if
    -- the underlying structures are the same. Similar to an ADT in Haskell.
  
  type DomainMap = HashMap Text VDomainConfiguration
  
  emptyDomainMap :: DomainMap
  emptyDomainMap = empty
  
  class HasUsageMap s where
    usageMap :: Lens' s UsageMap
  
  class (HasUsageMap state, HasIdentifierSet state) => Backend state where
    -- | Initial state for state monad
    initBackend :: ClashOpts -> state
  
    -- | What HDL is the backend generating
    hdlKind :: state -> HDL
  
    -- | Location for the primitive definitions
    primDirs :: state -> IO [FilePath]
  
    -- | Name of backend, used for directory to put output files in. Should be
    --   constant function / ignore argument.
    name :: state -> String
  
    -- | File extension for target langauge
    extension :: state -> String
  
    -- | Get the set of types out of state
    extractTypes     :: state -> HashSet HWType
  
    -- | Generate HDL for a Netlist component
    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
    hdlType          :: Usage -> HWType -> Ap (State state) Doc
    -- | Query what kind of type a given HDL type is
    hdlHWTypeKind :: HWType -> State state HWKind
    -- | Convert a Netlist HWType to an HDL error value for that type
    hdlTypeErrValue  :: HWType       -> Ap (State state) Doc
    -- | Convert a Netlist HWType to the root of a target HDL type
    hdlTypeMark      :: HWType       -> Ap (State state) Doc
    -- | Create a record selector
    hdlRecSel        :: HWType -> Int -> Ap (State state) Doc
    -- | Create a signal declaration from an identifier (Text) and Netlist HWType
    hdlSig           :: LT.Text -> HWType -> Ap (State state) Doc
    -- | Create a generative block statement marker
    genStmt          :: Bool -> State state Doc
    -- | Turn a Netlist Declaration to a HDL concurrent block
    inst             :: Declaration  -> Ap (State state) (Maybe Doc)
    -- | Turn a Netlist expression into a HDL expression
    expr             :: Bool -- ^ Enclose in parentheses?
                     -> Expr -- ^ Expr to convert
                     -> Ap (State state) Doc
    -- | Bit-width of Int,Word,Integer
    iwWidth          :: State state Int
    -- | Convert to a bit-vector
    toBV             :: HWType -> LT.Text -> Ap (State state) Doc
    -- | Convert from a bit-vector
    fromBV           :: HWType -> LT.Text -> Ap (State state) Doc
    -- | Synthesis tool we're generating HDL for
    hdlSyn           :: State state HdlSyn
    -- | setModName
    setModName       :: ModName -> state -> state
    -- | Set the name of the current top entity
    setTopName       :: Identifier -> state -> state
    -- | Get the name of the current top entity
    getTopName       :: State state Identifier
    -- | setSrcSpan
    setSrcSpan       :: SrcSpan -> State state ()
    -- | getSrcSpan
    getSrcSpan       :: State state SrcSpan
    -- | Block of declarations
    blockDecl        :: Identifier -> [Declaration] -> Ap (State state) Doc
    addIncludes      :: [(String, Doc)] -> State state ()
    addLibraries     :: [LT.Text] -> State state ()
    addImports       :: [LT.Text] -> State state ()
    addAndSetData    :: FilePath -> State state String
    getDataFiles     :: State state [(String,FilePath)]
    addMemoryDataFile  :: (String,String) -> State state ()
    getMemoryDataFiles :: State state [(String,String)]
    ifThenElseExpr :: state -> Bool
    -- | Whether -fclash-aggressive-x-optimization-blackboxes was set
    aggressiveXOptBB :: State state AggressiveXOptBB
    -- | Whether -fclash-no-render-enums was set
    renderEnums :: State state RenderEnums
    -- | All the domain configurations of design
    domainConfigurations :: State state DomainMap
    -- | Set the domain configurations
    setDomainConfigurations :: DomainMap -> state -> state
  