-- |
-- Module      : Verilog.Circuit.Gen
-- Description : Generate verilog from circuit.
-- Copyright   : (c) 2019, Yann Herklotz Grave
-- License     : GPL-3
-- Maintainer  : yann [at] yannherklotz [dot] com
-- Stability   : experimental
-- Portability : POSIX
--
-- Generate verilog from circuit.
module Verismith.Circuit.Gen
  ( generateAST,
  )
where

import Data.Graph.Inductive (LNode, Node)
import qualified Data.Graph.Inductive as G
import Data.Maybe (catMaybes)
import Verismith.Circuit.Base
import Verismith.Circuit.Internal
import Verismith.Verilog.AST
import Verismith.Verilog.Mutate

-- | Converts a 'CNode' to an 'Identifier'.
frNode :: Node -> Identifier
frNode :: Node -> Identifier
frNode = Text -> Identifier
Identifier (Text -> Identifier) -> (Node -> Text) -> Node -> Identifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Node -> Text
fromNode

-- | Converts a 'Gate' to a 'BinaryOperator', which should be a bijective
-- mapping.
fromGate :: Gate -> BinaryOperator
fromGate :: Gate -> BinaryOperator
fromGate Gate
And = BinaryOperator
BinAnd
fromGate Gate
Or = BinaryOperator
BinOr
fromGate Gate
Xor = BinaryOperator
BinXor

inputsC :: Circuit -> [Node]
inputsC :: Circuit -> [Node]
inputsC Circuit
c = Gr Gate () -> [Node]
forall (gr :: * -> * -> *) n e. Graph gr => gr n e -> [Node]
inputs (Circuit -> Gr Gate ()
getCircuit Circuit
c)

genPortsAST :: (Circuit -> [Node]) -> Circuit -> [Port]
genPortsAST :: (Circuit -> [Node]) -> Circuit -> [Port]
genPortsAST Circuit -> [Node]
f Circuit
c = Identifier -> Port
port (Identifier -> Port) -> (Node -> Identifier) -> Node -> Port
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Node -> Identifier
frNode (Node -> Port) -> [Node] -> [Port]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Circuit -> [Node]
f Circuit
c where port :: Identifier -> Port
port = PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Wire Bool
False Range
4

-- | Generates the nested expression AST, so that it can then generate the
-- assignment expressions.
genAssignExpr :: Gate -> [Node] -> Maybe Expr
genAssignExpr :: Gate -> [Node] -> Maybe Expr
genAssignExpr Gate
_ [] = Maybe Expr
forall a. Maybe a
Nothing
genAssignExpr Gate
_ [Node
n] = Expr -> Maybe Expr
forall a. a -> Maybe a
Just (Expr -> Maybe Expr)
-> (Identifier -> Expr) -> Identifier -> Maybe Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Expr
Id (Identifier -> Maybe Expr) -> Identifier -> Maybe Expr
forall a b. (a -> b) -> a -> b
$ Node -> Identifier
frNode Node
n
genAssignExpr Gate
g (Node
n : [Node]
ns) = Expr -> BinaryOperator -> Expr -> Expr
BinOp Expr
wire BinaryOperator
oper (Expr -> Expr) -> Maybe Expr -> Maybe Expr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gate -> [Node] -> Maybe Expr
genAssignExpr Gate
g [Node]
ns
  where
    wire :: Expr
wire = Identifier -> Expr
Id (Identifier -> Expr) -> Identifier -> Expr
forall a b. (a -> b) -> a -> b
$ Node -> Identifier
frNode Node
n
    oper :: BinaryOperator
oper = Gate -> BinaryOperator
fromGate Gate
g

-- | Generate the continuous assignment AST for a particular node. If it does
-- not have any nodes that link to it then return 'Nothing', as that means that
-- the assignment will just be empty.
genContAssignAST :: Circuit -> LNode Gate -> Maybe (ModItem ann)
genContAssignAST :: forall ann. Circuit -> LNode Gate -> Maybe (ModItem ann)
genContAssignAST Circuit
c (Node
n, Gate
g) = ContAssign -> ModItem ann
forall a. ContAssign -> ModItem a
ModCA (ContAssign -> ModItem ann)
-> (Expr -> ContAssign) -> Expr -> ModItem ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identifier -> Expr -> ContAssign
ContAssign Identifier
name (Expr -> ModItem ann) -> Maybe Expr -> Maybe (ModItem ann)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gate -> [Node] -> Maybe Expr
genAssignExpr Gate
g [Node]
nodes
  where
    gr :: Gr Gate ()
gr = Circuit -> Gr Gate ()
getCircuit Circuit
c
    nodes :: [Node]
nodes = Gr Gate () -> Node -> [Node]
forall (gr :: * -> * -> *) a b.
Graph gr =>
gr a b -> Node -> [Node]
G.pre Gr Gate ()
gr Node
n
    name :: Identifier
name = Node -> Identifier
frNode Node
n

genAssignAST :: Circuit -> [ModItem ann]
genAssignAST :: forall ann. Circuit -> [ModItem ann]
genAssignAST Circuit
c = [Maybe (ModItem ann)] -> [ModItem ann]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe (ModItem ann)] -> [ModItem ann])
-> [Maybe (ModItem ann)] -> [ModItem ann]
forall a b. (a -> b) -> a -> b
$ Circuit -> LNode Gate -> Maybe (ModItem ann)
forall ann. Circuit -> LNode Gate -> Maybe (ModItem ann)
genContAssignAST Circuit
c (LNode Gate -> Maybe (ModItem ann))
-> [LNode Gate] -> [Maybe (ModItem ann)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [LNode Gate]
nodes
  where
    gr :: Gr Gate ()
gr = Circuit -> Gr Gate ()
getCircuit Circuit
c
    nodes :: [LNode Gate]
nodes = Gr Gate () -> [LNode Gate]
forall a b. Gr a b -> [LNode a]
forall (gr :: * -> * -> *) a b. Graph gr => gr a b -> [LNode a]
G.labNodes Gr Gate ()
gr

genModuleDeclAST :: Circuit -> (ModDecl ann)
genModuleDeclAST :: forall ann. Circuit -> ModDecl ann
genModuleDeclAST Circuit
c = Identifier
-> [Port] -> [Port] -> [ModItem ann] -> [Parameter] -> ModDecl ann
forall a.
Identifier
-> [Port] -> [Port] -> [ModItem a] -> [Parameter] -> ModDecl a
ModDecl Identifier
i [Port]
forall {a}. [a]
output [Port]
ports (Port -> [ModItem ann] -> [ModItem ann]
forall ann. Port -> [ModItem ann] -> [ModItem ann]
combineAssigns Port
yPort [ModItem ann]
forall {ann}. [ModItem ann]
a) []
  where
    i :: Identifier
i = Text -> Identifier
Identifier Text
"gen_module"
    ports :: [Port]
ports = (Circuit -> [Node]) -> Circuit -> [Port]
genPortsAST Circuit -> [Node]
inputsC Circuit
c
    output :: [a]
output = []
    a :: [ModItem ann]
a = Circuit -> [ModItem ann]
forall ann. Circuit -> [ModItem ann]
genAssignAST Circuit
c
    yPort :: Port
yPort = PortType -> Bool -> Range -> Identifier -> Port
Port PortType
Wire Bool
False Range
90 Identifier
"y"

generateAST :: Circuit -> (Verilog ann)
generateAST :: forall ann. Circuit -> Verilog ann
generateAST Circuit
c = [ModDecl ann] -> Verilog ann
forall a. [ModDecl a] -> Verilog a
Verilog [Circuit -> ModDecl ann
forall ann. Circuit -> ModDecl ann
genModuleDeclAST Circuit
c]