NamedBlock.hs 1.79 KB
Newer Older
1 2 3 4
{- sv2v
 - Author: Zachary Snow <zach@zachjs.com>
 -
 - Conversion for unnamed blocks with contain data declarations
5 6
 -
 - SystemVerilog allows data declarations to appear in all blocks, but Verilog
7
 - allows them to appear only in blocks that are named. This conversion gives
8
 - such blocks a unique name to placate strict Verilog frontends.
9 10 11 12 13 14 15 16 17 18 19 20
 -}

module Convert.NamedBlock (convert) where

import Control.Monad.State
import qualified Data.Set as Set

import Convert.Traverse
import Language.SystemVerilog.AST

type Idents = Set.Set Identifier

21 22
convert :: [AST] -> [AST]
convert asts =
23 24
    -- we collect all the existing blocks in the first pass to make sure we
    -- don't generate conflicting names on repeated passes of this conversion
25 26
    evalState (runner collectStmtM asts >>= runner traverseStmtM) Set.empty
    where runner = mapM . traverseDescriptionsM . traverseModuleItemsM . traverseStmtsM
27 28

collectStmtM :: Stmt -> State Idents Stmt
29
collectStmtM (Block kw x decls stmts) = do
30
    modify $ Set.insert x
31
    return $ Block kw x decls stmts
32 33 34
collectStmtM other = return other

traverseStmtM :: Stmt -> State Idents Stmt
35 36 37
traverseStmtM (Block kw "" [] stmts) =
    return $ Block kw "" [] stmts
traverseStmtM (Block kw "" decls stmts) = do
38 39 40
    names <- get
    let x = uniqueBlockName names
    modify $ Set.insert x
41
    return $ Block kw x decls stmts
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
traverseStmtM other = return other

uniqueBlockName :: Idents -> Identifier
uniqueBlockName names =
    step ("sv2v_autoblock_" ++ (show $ Set.size names)) 0
    where
        step :: Identifier -> Int -> Identifier
        step base n =
            if Set.member name names
                then step base (n + 1)
                else name
            where
                name = if n == 0
                    then base
                    else base ++ "_" ++ show n