sv2v-0.0.11: src/Convert/TFBlock.hs
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for tasks and functions to contain only one top-level statement,
- as required in Verilog-2005. This conversion also hoists data declarations to
- the task or function level for greater portability.
-}
module Convert.TFBlock (convert) where
import Data.List (intersect)
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: [AST] -> [AST]
convert = map $ traverseDescriptions $ traverseModuleItems convertModuleItem
convertModuleItem :: ModuleItem -> ModuleItem
convertModuleItem (MIPackageItem packageItem) =
MIPackageItem $ convertPackageItem packageItem
convertModuleItem other = other
convertPackageItem :: PackageItem -> PackageItem
convertPackageItem (Function ml t f decls stmts) =
Function ml t f decls' stmts'
where (decls', stmts') = convertTFBlock decls stmts
convertPackageItem (Task ml f decls stmts) =
Task ml f decls' stmts'
where (decls', stmts') = convertTFBlock decls stmts
convertPackageItem other = other
convertTFBlock :: [Decl] -> [Stmt] -> ([Decl], [Stmt])
convertTFBlock decls [CommentStmt c, stmt] =
convertTFBlock (decls ++ [CommentDecl c]) [stmt]
convertTFBlock decls stmts =
(decls', [stmtsToStmt stmts'])
where (decls', stmts') = flattenOuterBlocks $ Block Seq "" decls stmts
stmtsToStmt :: [Stmt] -> Stmt
stmtsToStmt [stmt] = stmt
stmtsToStmt stmts = Block Seq "" [] stmts
flattenOuterBlocks :: Stmt -> ([Decl], [Stmt])
flattenOuterBlocks (Block Seq "" declsA [stmt]) =
if canCombine declsA declsB
then (declsA ++ declsB, stmtsB)
else (declsA, [stmt])
where (declsB, stmtsB) = flattenOuterBlocks stmt
flattenOuterBlocks (Block Seq name decls stmts)
| null name = (decls, stmts)
| otherwise = ([], [Block Seq name decls stmts])
flattenOuterBlocks stmt = ([], [stmt])
canCombine :: [Decl] -> [Decl] -> Bool
canCombine [] _ = True
canCombine _ [] = True
canCombine declsA declsB =
null $ intersect (declNames declsA) (declNames declsB)
declNames :: [Decl] -> [Identifier]
declNames = filter (not . null) . map declName
declName :: Decl -> Identifier
declName (Variable _ _ x _ _) = x
declName (Net _ _ _ _ x _ _) = x
declName (Param _ _ x _) = x
declName (ParamType _ x _) = x
declName CommentDecl{} = ""