aboutsummaryrefslogtreecommitdiffstats
path: root/src/Test/VeriFuzz/Verilog/CodeGen.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Test/VeriFuzz/Verilog/CodeGen.hs')
-rw-r--r--src/Test/VeriFuzz/Verilog/CodeGen.hs263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/Test/VeriFuzz/Verilog/CodeGen.hs b/src/Test/VeriFuzz/Verilog/CodeGen.hs
new file mode 100644
index 0000000..0247648
--- /dev/null
+++ b/src/Test/VeriFuzz/Verilog/CodeGen.hs
@@ -0,0 +1,263 @@
+{-|
+Module : Test.VeriFuzz.Verilog.CodeGen
+Description : Code generation for Verilog AST.
+Copyright : (c) Yann Herklotz Grave 2018
+License : GPL-3
+Maintainer : ymherklotz@gmail.com
+Stability : experimental
+Portability : POSIX
+
+This module generates the code from the Verilog AST defined in
+"Test.VeriFuzz.Verilog.AST".
+-}
+
+module Test.VeriFuzz.Verilog.CodeGen where
+
+import Control.Lens
+import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import Test.VeriFuzz.Internal.Shared
+import Test.VeriFuzz.Verilog.AST
+
+showT :: (Show a) => a -> Text
+showT = T.pack . show
+
+defMap :: Maybe Statement -> Text
+defMap stat = fromMaybe ";\n" $ genStatement <$> stat
+
+-- | Convert the 'VerilogSrc' type to 'Text' so that it can be rendered.
+genVerilogSrc :: VerilogSrc -> Text
+genVerilogSrc source =
+ fromList $ genDescription <$> source ^. getVerilogSrc
+
+-- | Generate the 'Description' to 'Text'.
+genDescription :: Description -> Text
+genDescription desc =
+ genModuleDecl $ desc ^. getDescription
+
+-- | Generate the 'ModDecl' for a module and convert it to 'Text'.
+genModuleDecl :: ModDecl -> Text
+genModuleDecl mod =
+ "module " <> mod ^. moduleId . getIdentifier
+ <> ports <> ";\n"
+ <> modItems
+ <> "endmodule\n"
+ where
+ ports
+ | null $ mod ^. modPorts = ""
+ | otherwise = "(\n" <> (sep ",\n" $ genPort <$> mod ^. modPorts) <> "\n)"
+ modItems = fromList $ genModuleItem <$> mod ^. moduleItems
+
+-- | Generate the 'Port' description.
+genPort :: Port -> Text
+genPort port =
+ dir <> t <> name
+ where
+ dir = fromMaybe "" $ (<>" ") . genPortDir <$> port ^. portDir
+ t = fromMaybe "wire " $ (<>" ") . genPortType <$> port ^. portType
+ name = port ^. portName . getIdentifier
+
+-- | Convert the 'PortDir' type to 'Text'.
+genPortDir :: PortDir -> Text
+genPortDir Input = "input"
+genPortDir Output = "output"
+genPortDir InOut = "inout"
+
+-- | Generate a 'ModItem'.
+genModuleItem :: ModItem -> Text
+genModuleItem (ModCA ca) = genContAssign ca
+genModuleItem (ModInst (Identifier id) (Identifier name) conn) =
+ id <> " " <> name <> "(" <> sep ", " (genExpr . _modConn <$> conn) <> ")" <> ";\n"
+genModuleItem (Initial stat) = "initial " <> genStatement stat
+genModuleItem (Always stat) = "always " <> genStatement stat
+genModuleItem (Decl port) = genPort port <> ";\n"
+
+-- | Generate continuous assignment
+genContAssign :: ContAssign -> Text
+genContAssign (ContAssign val e) =
+ " assign " <> name <> " = " <> expr <> ";\n"
+ where
+ name = val ^. getIdentifier
+ expr = genExpr $ e
+
+-- | Generate 'Expression' to 'Text'.
+genExpr :: Expression -> Text
+genExpr (OpExpr exprRhs bin exprLhs) =
+ "(" <> genExpr exprRhs <> genBinaryOperator bin <> genExpr exprLhs <> ")"
+genExpr (PrimExpr prim) = genPrimary prim
+genExpr (UnPrimExpr u e) =
+ "(" <> genUnaryOperator u <> genPrimary e <> ")"
+genExpr (CondExpr l t f) =
+ "(" <> genExpr l <> " ? " <> genExpr t <> " : " <> genExpr f <> ")"
+genExpr (ExprStr t) = "\"" <> t <> "\""
+
+-- | Generate a 'PrimaryExpression' to 'Text'.
+genPrimary :: Primary -> Text
+genPrimary (PrimNum num) =
+ "(" <> neg <> sh (num ^. numSize) <> "'d" <> (sh . abs) n <> ")"
+ where
+ sh = T.pack . show
+ abs x = if x <= 0 then -x else x
+ n = num ^. numVal
+ neg = if n <= 0 then "-" else ""
+genPrimary (PrimId ident) = ident ^. getIdentifier
+
+-- | Convert 'BinaryOperator' to 'Text'.
+genBinaryOperator :: BinaryOperator -> Text
+genBinaryOperator BinPlus = " + "
+genBinaryOperator BinMinus = " - "
+genBinaryOperator BinTimes = " * "
+genBinaryOperator BinDiv = " / "
+genBinaryOperator BinMod = " % "
+genBinaryOperator BinEq = " == "
+genBinaryOperator BinNEq = " != "
+genBinaryOperator BinCEq = " === "
+genBinaryOperator BinCNEq = " !== "
+genBinaryOperator BinLAnd = " && "
+genBinaryOperator BinLOr = " || "
+genBinaryOperator BinLT = " < "
+genBinaryOperator BinLEq = " <= "
+genBinaryOperator BinGT = " > "
+genBinaryOperator BinGEq = " >= "
+genBinaryOperator BinAnd = " & "
+genBinaryOperator BinOr = " | "
+genBinaryOperator BinXor = " ^ "
+genBinaryOperator BinXNor = " ^~ "
+genBinaryOperator BinXNorInv = " ~^ "
+genBinaryOperator BinPower = " ** "
+genBinaryOperator BinLSL = " << "
+genBinaryOperator BinLSR = " >> "
+genBinaryOperator BinASL = " <<< "
+genBinaryOperator BinASR = " >>> "
+
+genUnaryOperator :: UnaryOperator -> Text
+genUnaryOperator UnPlus = "+"
+genUnaryOperator UnMinus = "-"
+genUnaryOperator UnNot = "!"
+genUnaryOperator UnAnd = "&"
+genUnaryOperator UnNand = "~&"
+genUnaryOperator UnOr = "|"
+genUnaryOperator UnNor = "~|"
+genUnaryOperator UnXor = "^"
+genUnaryOperator UnNxor = "~^"
+genUnaryOperator UnNxorInv = "^~"
+
+genNet :: Net -> Text
+genNet Wire = "wire"
+genNet Tri = "tri"
+genNet Tri1 = "tri1"
+genNet Supply0 = "supply0"
+genNet Wand = "wand"
+genNet TriAnd = "triand"
+genNet Tri0 = "tri0"
+genNet Supply1 = "supply1"
+genNet Wor = "wor"
+genNet Trior = "trior"
+
+genEvent :: Event -> Text
+genEvent (EId id) = "@(" <> id ^. getIdentifier <> ")"
+genEvent (EExpr expr) = "@(" <> genExpr expr <> ")"
+genEvent EAll = "@*"
+
+genDelay :: Delay -> Text
+genDelay (Delay i) = "#" <> showT i
+
+genRegLVal :: RegLVal -> Text
+genRegLVal (RegId id) = id ^. getIdentifier
+genRegLVal (RegExpr id expr) =
+ id ^. getIdentifier <> " [" <> genExpr expr <> "]"
+genRegLVal (RegSize id msb lsb) =
+ id ^. getIdentifier <> " [" <> genConstExpr msb <> ":" <> genConstExpr lsb <> "]"
+
+genConstExpr :: ConstExpr -> Text
+genConstExpr (ConstExpr num) = showT num
+
+genPortType :: PortType -> Text
+genPortType (PortNet net) = genNet net
+genPortType (Reg signed)
+ | signed = " reg signed "
+ | otherwise = " reg "
+
+genAssign :: Text -> Assign -> Text
+genAssign op (Assign r d e) =
+ genRegLVal r <> op <> fromMaybe "" (genDelay <$> d) <> genExpr e
+
+genStatement :: Statement -> Text
+genStatement (TimeCtrl d stat) = genDelay d <> " " <> defMap stat
+genStatement (EventCtrl e stat) = genEvent e <> " " <> defMap stat
+genStatement (SeqBlock s) =
+ "begin\n" <> fromList (genStatement <$> s) <> "end\n"
+genStatement (BlockAssign a) = genAssign " = " a <> ";\n"
+genStatement (NonBlockAssign a) = genAssign " <= " a <> ";\n"
+genStatement (StatCA a) = genContAssign a
+genStatement (TaskEnable task) = genTask task <> ";\n"
+genStatement (SysTaskEnable task) = "$" <> genTask task <> ";\n"
+
+genTask :: Task -> Text
+genTask (Task name expr)
+ | null expr = id
+ | otherwise = id <> "(" <> sep ", " (genExpr <$> expr) <> ")"
+ where
+ id = name ^. getIdentifier
+
+-- | Render the 'Text' to 'IO'. This is equivalent to 'putStrLn'.
+render :: Text -> IO ()
+render = T.putStrLn
+
+-- Instances
+
+instance Source Task where
+ genSource = genTask
+
+instance Source Statement where
+ genSource = genStatement
+
+instance Source PortType where
+ genSource = genPortType
+
+instance Source ConstExpr where
+ genSource = genConstExpr
+
+instance Source RegLVal where
+ genSource = genRegLVal
+
+instance Source Delay where
+ genSource = genDelay
+
+instance Source Event where
+ genSource = genEvent
+
+instance Source Net where
+ genSource = genNet
+
+instance Source UnaryOperator where
+ genSource = genUnaryOperator
+
+instance Source Primary where
+ genSource = genPrimary
+
+instance Source Expression where
+ genSource = genExpr
+
+instance Source ContAssign where
+ genSource = genContAssign
+
+instance Source ModItem where
+ genSource = genModuleItem
+
+instance Source PortDir where
+ genSource = genPortDir
+
+instance Source Port where
+ genSource = genPort
+
+instance Source ModDecl where
+ genSource = genModuleDecl
+
+instance Source Description where
+ genSource = genDescription
+
+instance Source VerilogSrc where
+ genSource = genVerilogSrc