-- |
-- Module      : Verismith.Verilog.Internal
-- Description : Defaults and common functions.
-- Copyright   : (c) 2018-2019, Yann Herklotz
-- License     : GPL-3
-- Maintainer  : yann [at] yannherklotz [dot] com
-- Stability   : experimental
-- Portability : POSIX
--
-- Defaults and common functions.
module Verismith.Verilog.Internal
  ( regDecl,
    wireDecl,
    emptyMod,
    setModName,
    addModPort,
    addModDecl,
    testBench,
    addTestBench,
    defaultPort,
    portToExpr,
    modName,
    yPort,
    wire,
    reg,
  )
where

import Control.Lens
import Data.Text (Text)
import Verismith.Verilog.AST

regDecl :: Identifier -> (ModItem ann)
regDecl :: forall ann. Identifier -> ModItem ann
regDecl Identifier
i = Maybe PortDir -> Port -> Maybe ConstExpr -> ModItem ann
forall a. Maybe PortDir -> Port -> Maybe ConstExpr -> ModItem a
Decl Maybe PortDir
forall a. Maybe a
Nothing (PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Reg Bool
False (ConstExpr -> ConstExpr -> Range
Range ConstExpr
1 ConstExpr
0) Identifier
i) Maybe ConstExpr
forall a. Maybe a
Nothing

wireDecl :: Identifier -> (ModItem ann)
wireDecl :: forall ann. Identifier -> ModItem ann
wireDecl Identifier
i = Maybe PortDir -> Port -> Maybe ConstExpr -> ModItem ann
forall a. Maybe PortDir -> Port -> Maybe ConstExpr -> ModItem a
Decl Maybe PortDir
forall a. Maybe a
Nothing (PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Wire Bool
False (ConstExpr -> ConstExpr -> Range
Range ConstExpr
1 ConstExpr
0) Identifier
i) Maybe ConstExpr
forall a. Maybe a
Nothing

-- | Create an empty module.
emptyMod :: (ModDecl ann)
emptyMod :: forall ann. ModDecl ann
emptyMod = Identifier
-> [Port] -> [Port] -> [ModItem ann] -> [Parameter] -> ModDecl ann
forall a.
Identifier
-> [Port] -> [Port] -> [ModItem a] -> [Parameter] -> ModDecl a
ModDecl Identifier
"" [] [] [] []

-- | Set a module name for a module declaration.
setModName :: Text -> (ModDecl ann) -> (ModDecl ann)
setModName :: forall ann. Text -> ModDecl ann -> ModDecl ann
setModName Text
str = (Identifier -> Identity Identifier)
-> ModDecl ann -> Identity (ModDecl ann)
forall a (f :: * -> *).
Applicative f =>
(Identifier -> f Identifier) -> ModDecl a -> f (ModDecl a)
modId ((Identifier -> Identity Identifier)
 -> ModDecl ann -> Identity (ModDecl ann))
-> Identifier -> ModDecl ann -> ModDecl ann
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Text -> Identifier
Identifier Text
str

-- | Add a input port to the module declaration.
addModPort :: Port -> (ModDecl ann) -> (ModDecl ann)
addModPort :: forall ann. Port -> ModDecl ann -> ModDecl ann
addModPort Port
port = ([Port] -> Identity [Port])
-> ModDecl ann -> Identity (ModDecl ann)
forall a (f :: * -> *).
Applicative f =>
([Port] -> f [Port]) -> ModDecl a -> f (ModDecl a)
modInPorts (([Port] -> Identity [Port])
 -> ModDecl ann -> Identity (ModDecl ann))
-> ([Port] -> [Port]) -> ModDecl ann -> ModDecl ann
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (:) Port
port

addModDecl :: (ModDecl ann) -> (Verilog ann) -> (Verilog ann)
addModDecl :: forall ann. ModDecl ann -> Verilog ann -> Verilog ann
addModDecl ModDecl ann
desc = ([ModDecl ann] -> Identity [ModDecl ann])
-> Verilog ann -> Identity (Verilog ann)
(Unwrapped (Verilog ann) -> Identity (Unwrapped (Verilog ann)))
-> Verilog ann -> Identity (Verilog ann)
forall s t. Rewrapping s t => Iso s t (Unwrapped s) (Unwrapped t)
Iso
  (Verilog ann)
  (Verilog ann)
  (Unwrapped (Verilog ann))
  (Unwrapped (Verilog ann))
_Wrapped (([ModDecl ann] -> Identity [ModDecl ann])
 -> Verilog ann -> Identity (Verilog ann))
-> ([ModDecl ann] -> [ModDecl ann]) -> Verilog ann -> Verilog ann
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (:) ModDecl ann
desc

testBench :: (ModDecl ann)
testBench :: forall ann. ModDecl ann
testBench =
  Identifier
-> [Port] -> [Port] -> [ModItem ann] -> [Parameter] -> ModDecl ann
forall a.
Identifier
-> [Port] -> [Port] -> [ModItem a] -> [Parameter] -> ModDecl a
ModDecl
    Identifier
"main"
    []
    []
    [ Identifier -> ModItem ann
forall ann. Identifier -> ModItem ann
regDecl Identifier
"a",
      Identifier -> ModItem ann
forall ann. Identifier -> ModItem ann
regDecl Identifier
"b",
      Identifier -> ModItem ann
forall ann. Identifier -> ModItem ann
wireDecl Identifier
"c",
      Identifier -> [ModConn] -> Identifier -> [ModConn] -> ModItem ann
forall a.
Identifier -> [ModConn] -> Identifier -> [ModConn] -> ModItem a
ModInst
        Identifier
"and"
        []
        Identifier
"and_gate"
        [Expr -> ModConn
ModConn (Expr -> ModConn) -> Expr -> ModConn
forall a b. (a -> b) -> a -> b
$ Identifier -> Expr
Id Identifier
"c", Expr -> ModConn
ModConn (Expr -> ModConn) -> Expr -> ModConn
forall a b. (a -> b) -> a -> b
$ Identifier -> Expr
Id Identifier
"a", Expr -> ModConn
ModConn (Expr -> ModConn) -> Expr -> ModConn
forall a b. (a -> b) -> a -> b
$ Identifier -> Expr
Id Identifier
"b"],
      Statement ann -> ModItem ann
forall a. Statement a -> ModItem a
Initial (Statement ann -> ModItem ann) -> Statement ann -> ModItem ann
forall a b. (a -> b) -> a -> b
$
        [Statement ann] -> Statement ann
forall a. [Statement a] -> Statement a
SeqBlock
          [ Assign -> Statement ann
forall a. Assign -> Statement a
BlockAssign (Assign -> Statement ann)
-> (Expr -> Assign) -> Expr -> Statement ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LVal -> Maybe Delay -> Expr -> Assign
Assign (Identifier -> LVal
RegId Identifier
"a") Maybe Delay
forall a. Maybe a
Nothing (Expr -> Statement ann) -> Expr -> Statement ann
forall a b. (a -> b) -> a -> b
$ BitVec -> Expr
Number BitVec
1,
            Assign -> Statement ann
forall a. Assign -> Statement a
BlockAssign (Assign -> Statement ann)
-> (Expr -> Assign) -> Expr -> Statement ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LVal -> Maybe Delay -> Expr -> Assign
Assign (Identifier -> LVal
RegId Identifier
"b") Maybe Delay
forall a. Maybe a
Nothing (Expr -> Statement ann) -> Expr -> Statement ann
forall a b. (a -> b) -> a -> b
$ BitVec -> Expr
Number BitVec
1
          ]
    ]
    []

addTestBench :: (Verilog ann) -> (Verilog ann)
addTestBench :: forall ann. Verilog ann -> Verilog ann
addTestBench = ModDecl ann -> Verilog ann -> Verilog ann
forall ann. ModDecl ann -> Verilog ann -> Verilog ann
addModDecl ModDecl ann
forall ann. ModDecl ann
testBench

defaultPort :: Identifier -> Port
defaultPort :: Identifier -> Port
defaultPort = PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Wire Bool
False (ConstExpr -> ConstExpr -> Range
Range ConstExpr
1 ConstExpr
0)

portToExpr :: Port -> Expr
portToExpr :: Port -> Expr
portToExpr (Port PortType
_ Bool
_ Range
_ Identifier
i) = Identifier -> Expr
Id Identifier
i

modName :: (ModDecl ann) -> Text
modName :: forall ann. ModDecl ann -> Text
modName = Identifier -> Text
getIdentifier (Identifier -> Text)
-> (ModDecl ann -> Identifier) -> ModDecl ann -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting Identifier (ModDecl ann) Identifier
-> ModDecl ann -> Identifier
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Identifier (ModDecl ann) Identifier
forall a (f :: * -> *).
Applicative f =>
(Identifier -> f Identifier) -> ModDecl a -> f (ModDecl a)
modId

yPort :: Identifier -> Port
yPort :: Identifier -> Port
yPort = PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Wire Bool
False (ConstExpr -> ConstExpr -> Range
Range ConstExpr
90 ConstExpr
0)

wire :: Range -> Identifier -> Port
wire :: Range -> Identifier -> Port
wire = PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Wire Bool
False

reg :: Range -> Identifier -> Port
reg :: Range -> Identifier -> Port
reg = PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Reg Bool
False