ParamNoDefault.hs 3.56 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
{- sv2v
 - Author: Zachary Snow <zach@zachjs.com>
 -
 - Conversion for parameters without default values
 -
 - This conversion ensures that any parameters which don't have a default value
 - are always given an explicit value wherever that module or interface is used.
 -
 - Parameters are given a fake default value if they do not have one so that the
 - given source for that module can be consumed by downstream tools. This is not
 - done for type parameters, as those modules are rewritten by a separate
 - conversion. Localparams without defaults are expressly caught and forbidden.
 -}

module Convert.ParamNoDefault (convert) where

import Control.Monad.Writer.Strict
import Data.List (intercalate)
import qualified Data.Map.Strict as Map

import Convert.Traverse
import Language.SystemVerilog.AST

type Parts = Map.Map Identifier [(Identifier, Bool)]

convert :: [AST] -> [AST]
convert files =
    map convertFile files'
    where
        (files', parts) = runWriter $
            mapM (traverseDescriptionsM traverseDescriptionM) files
        convertFile = traverseDescriptions $ traverseModuleItems $
            traverseModuleItem parts

traverseDescriptionM :: Description -> Writer Parts Description
traverseDescriptionM (Part attrs extern kw lifetime name ports items) = do
    let (items', params) = runWriter $ mapM traverseModuleItemM items
    tell $ Map.singleton name params
    return $ Part attrs extern kw lifetime name ports items'
traverseDescriptionM other = return other

traverseModuleItemM :: ModuleItem -> Writer [(Identifier, Bool)] ModuleItem
traverseModuleItemM (MIAttr attr item) =
    traverseModuleItemM item >>= return . MIAttr attr
traverseModuleItemM (MIPackageItem (Decl decl)) =
    traverseDeclM decl >>= return . MIPackageItem . Decl
traverseModuleItemM other = return other

-- writes down the parameters for a part
traverseDeclM :: Decl -> Writer [(Identifier, Bool)] Decl
traverseDeclM (Param Localparam _ x Nil) =
    error $ "localparam " ++ show x ++ " has no default value"
traverseDeclM (Param Parameter t x e) = do
    tell [(x, e == Nil)]
    return $ if e == Nil
        then Param Parameter t x $ RawNum 0
        else Param Parameter t x e
58
traverseDeclM (ParamType Localparam x UnknownType) =
59
    error $ "localparam type " ++ show x ++ " has no default value"
60
traverseDeclM (ParamType Parameter x t) = do
61
    -- parameter types are rewritten separately, so no fake default here
62 63
    tell [(x, t == UnknownType)]
    return $ ParamType Parameter x t
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
traverseDeclM other = return other

-- check for instances missing values for parameters without defaults
traverseModuleItem :: Parts -> ModuleItem -> ModuleItem
traverseModuleItem parts (orig @ (Instance part params name _ _)) =
    if maybePartInfo == Nothing || null missingParams
        then orig
        else error $ "instance " ++ show name ++ " of " ++ show part
                ++ " is missing values for parameters without defaults: "
                ++ (intercalate " " $ map show missingParams)
    where
        maybePartInfo = Map.lookup part parts
        Just partInfo = maybePartInfo
        paramsResolved = resolveBindings (map fst partInfo) params
        paramsWithNoDefault = map fst $ filter snd partInfo
        missingParams = filter (needsDefault paramsResolved) paramsWithNoDefault
traverseModuleItem _ other = other

-- whether a given parameter is unspecified in the given parameter bindings
needsDefault :: [(Identifier, TypeOrExpr)] -> Identifier -> Bool
needsDefault instanceParams param =
    case lookup param instanceParams of
        Nothing -> True
        Just (Right Nil) -> True
        Just _ -> False