mirror of https://github.com/zachjs/sv2v.git
88 lines
3.5 KiB
Haskell
88 lines
3.5 KiB
Haskell
{- 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
|
|
traverseDeclM (ParamType Localparam x UnknownType) =
|
|
error $ "localparam type " ++ show x ++ " has no default value"
|
|
traverseDeclM (ParamType Parameter x t) = do
|
|
-- parameter types are rewritten separately, so no fake default here
|
|
tell [(x, t == UnknownType)]
|
|
return $ ParamType Parameter x t
|
|
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
|
|
paramsWithNoDefault = map fst $ filter snd partInfo
|
|
missingParams = filter (needsDefault params) 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
|