mirror of https://github.com/zachjs/sv2v.git
interface and instance array support
- support for interface instance arrays - support for interface-using module instance arrays - support for modport array bindings - fix modport bindings shadowed in nested instances
This commit is contained in:
parent
8eac9b0149
commit
2b377cef04
|
|
@ -1,3 +1,4 @@
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
{- sv2v
|
{- sv2v
|
||||||
- Author: Zachary Snow <zach@zachjs.com>
|
- Author: Zachary Snow <zach@zachjs.com>
|
||||||
-
|
-
|
||||||
|
|
@ -11,6 +12,7 @@ import Data.Maybe (mapMaybe)
|
||||||
import Control.Monad.Writer.Strict
|
import Control.Monad.Writer.Strict
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
import Convert.ExprUtils (endianCondExpr)
|
||||||
import Convert.Scoper
|
import Convert.Scoper
|
||||||
import Convert.Traverse
|
import Convert.Traverse
|
||||||
import Language.SystemVerilog.AST
|
import Language.SystemVerilog.AST
|
||||||
|
|
@ -23,18 +25,34 @@ data PartInfo = PartInfo
|
||||||
type PartInfos = Map.Map Identifier PartInfo
|
type PartInfos = Map.Map Identifier PartInfo
|
||||||
|
|
||||||
type ModportInstances = [(Identifier, (Identifier, Identifier))]
|
type ModportInstances = [(Identifier, (Identifier, Identifier))]
|
||||||
type ModportBinding = (Identifier, (Expr, Expr))
|
type ModportBinding = (Identifier, (Substitutions, Expr))
|
||||||
|
type Substitutions = [(Expr, Expr)]
|
||||||
|
|
||||||
convert :: [AST] -> [AST]
|
convert :: [AST] -> [AST]
|
||||||
convert =
|
convert files =
|
||||||
traverseFiles (collectDescriptionsM collectPart)
|
if needsFlattening
|
||||||
(map . convertDescription)
|
then files
|
||||||
|
else traverseFiles
|
||||||
|
(collectDescriptionsM collectPart)
|
||||||
|
(map . convertDescription)
|
||||||
|
files
|
||||||
where
|
where
|
||||||
-- we can only collect/map non-extern interfaces and modules
|
-- we can only collect/map non-extern interfaces and modules
|
||||||
collectPart :: Description -> Writer PartInfos ()
|
collectPart :: Description -> Writer PartInfos ()
|
||||||
collectPart (Part _ False kw _ name ports items) =
|
collectPart (Part _ False kw _ name ports items) =
|
||||||
tell $ Map.singleton name $ PartInfo kw ports items
|
tell $ Map.singleton name $ PartInfo kw ports items
|
||||||
collectPart _ = return ()
|
collectPart _ = return ()
|
||||||
|
-- multidimensional instances need to be flattened before this
|
||||||
|
-- conversion can proceed
|
||||||
|
needsFlattening =
|
||||||
|
getAny $ execWriter $ mapM (collectDescriptionsM checkPart) files
|
||||||
|
checkPart :: Description -> Writer Any ()
|
||||||
|
checkPart (Part _ _ _ _ _ _ items) =
|
||||||
|
mapM (collectNestedModuleItemsM checkItem) items >> return ()
|
||||||
|
checkPart _ = return ()
|
||||||
|
checkItem :: ModuleItem -> Writer Any ()
|
||||||
|
checkItem (Instance _ _ _ rs _) = when (length rs > 1) $ tell $ Any True
|
||||||
|
checkItem _ = return ()
|
||||||
|
|
||||||
convertDescription :: PartInfos -> Description -> Description
|
convertDescription :: PartInfos -> Description -> Description
|
||||||
convertDescription _ (Part _ _ Interface _ name _ _) =
|
convertDescription _ (Part _ _ Interface _ name _ _) =
|
||||||
|
|
@ -54,26 +72,25 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
||||||
traverseModuleItemM :: ModuleItem -> Scoper [ModportDecl] ModuleItem
|
traverseModuleItemM :: ModuleItem -> Scoper [ModportDecl] ModuleItem
|
||||||
traverseModuleItemM (Modport modportName modportDecls) =
|
traverseModuleItemM (Modport modportName modportDecls) =
|
||||||
insertElem modportName modportDecls >> return (Generate [])
|
insertElem modportName modportDecls >> return (Generate [])
|
||||||
traverseModuleItemM (instanceItem @ (Instance _ _ _ [] _)) =
|
traverseModuleItemM (instanceItem @ Instance{}) =
|
||||||
if maybePartInfo == Nothing then
|
if maybePartInfo == Nothing then
|
||||||
return instanceItem
|
return instanceItem
|
||||||
else if partKind == Interface then
|
else if partKind == Interface then
|
||||||
-- inline instantiation of an interface
|
-- inline instantiation of an interface
|
||||||
convertNested $ Generate $ map GenModuleItem $
|
convertNested $ Generate $ map GenModuleItem $
|
||||||
inlineInstance [] []
|
inlineInstance rs []
|
||||||
partItems instanceName paramBindings portBindings
|
partItems instanceName paramBindings portBindings
|
||||||
else if not $ null (extractModportInstances partInfo) then do
|
else if not $ null (extractModportInstances partInfo) then do
|
||||||
modports <- embedScopes (\l () -> l) ()
|
modports <- embedScopes (\l () -> l) ()
|
||||||
-- inline instantiation of a module
|
-- inline instantiation of a module
|
||||||
convertNested $ Generate $ map GenModuleItem $
|
convertNested $ Generate $ map GenModuleItem $
|
||||||
inlineInstance
|
inlineInstance rs
|
||||||
(modportBindings modports)
|
(modportBindings modports)
|
||||||
(modportSubstitutions modports)
|
|
||||||
partItems instanceName paramBindings portBindings
|
partItems instanceName paramBindings portBindings
|
||||||
else
|
else
|
||||||
return instanceItem
|
return instanceItem
|
||||||
where
|
where
|
||||||
Instance part rawParamBindings instanceName [] rawPortBindings =
|
Instance part rawParamBindings instanceName rs rawPortBindings =
|
||||||
instanceItem
|
instanceItem
|
||||||
maybePartInfo = Map.lookup part parts
|
maybePartInfo = Map.lookup part parts
|
||||||
Just partInfo = maybePartInfo
|
Just partInfo = maybePartInfo
|
||||||
|
|
@ -85,19 +102,73 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
||||||
|
|
||||||
modportInstances = extractModportInstances partInfo
|
modportInstances = extractModportInstances partInfo
|
||||||
modportBindings modports = mapMaybe
|
modportBindings modports = mapMaybe
|
||||||
(inferModportBinding modports modportInstances) portBindings
|
(inferModportBinding modports modportInstances) $
|
||||||
modportSubstitutions modports = concatMap
|
map (second $ addImpliedSlice modports) portBindings
|
||||||
(expandModportBinding modports) (modportBindings modports)
|
second f = \(a, b) -> (a, f b)
|
||||||
|
|
||||||
traverseModuleItemM other = return other
|
traverseModuleItemM other = return other
|
||||||
|
|
||||||
-- determines the underlying modport and interface instances associated
|
-- add explicit slices for bindings of entire modport instance arrays
|
||||||
-- with the given port binding, if it is a modport binding
|
addImpliedSlice :: Scopes [ModportDecl] -> Expr -> Expr
|
||||||
|
addImpliedSlice modports (orig @ (Dot expr modportName)) =
|
||||||
|
case lookupElem modports (InstArrKey expr) of
|
||||||
|
Just (_, _, InstArrVal l r) ->
|
||||||
|
Dot (Range expr NonIndexed (l, r)) modportName
|
||||||
|
_ -> orig
|
||||||
|
addImpliedSlice modports expr =
|
||||||
|
case lookupElem modports (InstArrKey expr) of
|
||||||
|
Just (_, _, InstArrVal l r) ->
|
||||||
|
Range expr NonIndexed (l, r)
|
||||||
|
_ -> expr
|
||||||
|
|
||||||
|
-- elaborates and resolves provided modport bindings
|
||||||
inferModportBinding :: Scopes [ModportDecl] -> ModportInstances ->
|
inferModportBinding :: Scopes [ModportDecl] -> ModportInstances ->
|
||||||
PortBinding -> Maybe ModportBinding
|
PortBinding -> Maybe ModportBinding
|
||||||
inferModportBinding _ _ ("", _) =
|
|
||||||
error "internal inferModportBinding invariant violated"
|
|
||||||
inferModportBinding modports modportInstances (portName, expr) =
|
inferModportBinding modports modportInstances (portName, expr) =
|
||||||
|
if maybeInfo == Nothing
|
||||||
|
then Nothing
|
||||||
|
else Just (portName, modportBinding)
|
||||||
|
where
|
||||||
|
modportBinding = (substitutions, replaceBit modportE)
|
||||||
|
substitutions =
|
||||||
|
genSubstitutions modports base instanceE modportE
|
||||||
|
maybeInfo =
|
||||||
|
lookupModportBinding modports modportInstances portName bitd
|
||||||
|
Just (instanceE, modportE) = maybeInfo
|
||||||
|
|
||||||
|
(exprUndot, bitd) = case expr of
|
||||||
|
Dot subExpr x -> (subExpr, Dot bitdUndot x)
|
||||||
|
_ -> (expr, bitdUndot)
|
||||||
|
bitdUndot = case exprUndot of
|
||||||
|
Range subExpr _ _ -> Bit subExpr taggedOffset
|
||||||
|
Bit subExpr _ -> Bit subExpr untaggedOffset
|
||||||
|
_ -> exprUndot
|
||||||
|
bitReplacement = case exprUndot of
|
||||||
|
Range _ mode range -> \e -> Range e mode range
|
||||||
|
Bit _ idx -> flip Bit idx
|
||||||
|
_ -> id
|
||||||
|
base = case exprUndot of
|
||||||
|
Range{} -> Bit (Ident portName) Tag
|
||||||
|
_ -> Ident portName
|
||||||
|
|
||||||
|
untaggedOffset = Ident $ modportBaseName portName
|
||||||
|
taggedOffset = BinOp Add Tag untaggedOffset
|
||||||
|
|
||||||
|
replaceBit :: Expr -> Expr
|
||||||
|
replaceBit (Bit subExpr idx) =
|
||||||
|
if idx == untaggedOffset || idx == taggedOffset
|
||||||
|
then bitReplacement subExpr
|
||||||
|
else Bit subExpr idx
|
||||||
|
replaceBit (Dot subExpr x) =
|
||||||
|
Dot (replaceBit subExpr) x
|
||||||
|
replaceBit (Ident x) = Ident x
|
||||||
|
replaceBit _ = error "replaceBit invariant violated"
|
||||||
|
|
||||||
|
-- determines the underlying modport and interface instances associated
|
||||||
|
-- with the given port binding, if it is a modport binding
|
||||||
|
lookupModportBinding :: Scopes [ModportDecl] -> ModportInstances
|
||||||
|
-> Identifier -> Expr -> Maybe (Expr, Expr)
|
||||||
|
lookupModportBinding modports modportInstances portName expr =
|
||||||
if bindingIsModport then
|
if bindingIsModport then
|
||||||
-- provided specific instance modport
|
-- provided specific instance modport
|
||||||
foundModport expr
|
foundModport expr
|
||||||
|
|
@ -116,11 +187,11 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
||||||
modportName = case lookup portName modportInstances of
|
modportName = case lookup portName modportInstances of
|
||||||
Just (_, x) -> x
|
Just (_, x) -> x
|
||||||
Nothing -> error $ "can't deduce modport for interface "
|
Nothing -> error $ "can't deduce modport for interface "
|
||||||
++ " bound to port " ++ portName
|
++ show expr ++ " bound to port " ++ portName
|
||||||
|
|
||||||
foundModport modportE =
|
foundModport modportE =
|
||||||
Just (portName, (instanceE, modportE))
|
Just (findInstance modportE, qualifyModport modportE)
|
||||||
where instanceE = findInstance modportE
|
|
||||||
findInstance :: Expr -> Expr
|
findInstance :: Expr -> Expr
|
||||||
findInstance e =
|
findInstance e =
|
||||||
case lookupElem modports (Dot e "") of
|
case lookupElem modports (Dot e "") of
|
||||||
|
|
@ -128,18 +199,27 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
||||||
Bit e' _ -> findInstance e'
|
Bit e' _ -> findInstance e'
|
||||||
Dot e' _ -> findInstance e'
|
Dot e' _ -> findInstance e'
|
||||||
_ -> error "internal invariant violated"
|
_ -> error "internal invariant violated"
|
||||||
Just (accesses, _, _) ->
|
Just (accesses, _, _) -> accessesToExpr $ init accesses
|
||||||
foldl accessToExpr (Ident topName) rest
|
qualifyModport :: Expr -> Expr
|
||||||
where Access topName Nil : rest = init accesses
|
qualifyModport e =
|
||||||
|
case lookupElem modports e of
|
||||||
|
Just (accesses, _, _) -> accessesToExpr accesses
|
||||||
|
Nothing -> accessesToExpr $ init accesses
|
||||||
|
where Just (accesses, _, _) =
|
||||||
|
lookupElem modports (Dot e "")
|
||||||
|
accessesToExpr :: [Access] -> Expr
|
||||||
|
accessesToExpr accesses =
|
||||||
|
foldl accessToExpr (Ident topName) rest
|
||||||
|
where Access topName Nil : rest = accesses
|
||||||
accessToExpr :: Expr -> Access -> Expr
|
accessToExpr :: Expr -> Access -> Expr
|
||||||
accessToExpr e (Access x Nil) = Dot e x
|
accessToExpr e (Access x Nil) = Dot e x
|
||||||
accessToExpr e (Access x i) = Bit (Dot e x) i
|
accessToExpr e (Access x i) = Bit (Dot e x) i
|
||||||
|
|
||||||
-- expand a modport binding into a series of expression substitutions
|
-- expand a modport binding into a series of expression substitutions
|
||||||
expandModportBinding :: Scopes [ModportDecl]
|
genSubstitutions :: Scopes [ModportDecl] -> Expr -> Expr -> Expr
|
||||||
-> ModportBinding -> [(Expr, Expr)]
|
-> [(Expr, Expr)]
|
||||||
expandModportBinding modports (portName, (instanceE, modportE)) =
|
genSubstitutions modports baseE instanceE modportE =
|
||||||
(Ident portName, instanceE) :
|
(baseE, instanceE) :
|
||||||
map toPortBinding modportDecls
|
map toPortBinding modportDecls
|
||||||
where
|
where
|
||||||
a = lookupElem modports modportE
|
a = lookupElem modports modportE
|
||||||
|
|
@ -148,7 +228,7 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
||||||
if a == Nothing then b else a
|
if a == Nothing then b else a
|
||||||
toPortBinding (_, x, e) = (x', e')
|
toPortBinding (_, x, e) = (x', e')
|
||||||
where
|
where
|
||||||
x' = Dot (Ident portName) x
|
x' = Dot baseE x
|
||||||
e' = prefixExpr e
|
e' = prefixExpr e
|
||||||
prefixExpr :: Expr -> Expr
|
prefixExpr :: Expr -> Expr
|
||||||
prefixExpr (Ident x) =
|
prefixExpr (Ident x) =
|
||||||
|
|
@ -212,22 +292,29 @@ impliedModport =
|
||||||
|
|
||||||
-- convert an interface-bound module instantiation or an interface instantiation
|
-- convert an interface-bound module instantiation or an interface instantiation
|
||||||
-- into a series of equivalent inlined module items
|
-- into a series of equivalent inlined module items
|
||||||
inlineInstance :: [ModportBinding] -> [(Expr, Expr)] -> [ModuleItem]
|
inlineInstance :: [Range] -> [ModportBinding] -> [ModuleItem]
|
||||||
-> Identifier -> [ParamBinding] -> [PortBinding] -> [ModuleItem]
|
-> Identifier -> [ParamBinding] -> [PortBinding] -> [ModuleItem]
|
||||||
inlineInstance modportBindings modportSubstitutions items
|
inlineInstance ranges modportBindings items
|
||||||
instanceName instanceParams instancePorts =
|
instanceName instanceParams instancePorts =
|
||||||
comment :
|
comment :
|
||||||
|
map (MIPackageItem . Decl) bindingBaseParams ++
|
||||||
map (MIPackageItem . Decl) parameterBinds ++
|
map (MIPackageItem . Decl) parameterBinds ++
|
||||||
Generate [GenBlock instanceName $ map GenModuleItem items']
|
(wrapInstance $ GenBlock instanceName $ map GenModuleItem items')
|
||||||
: portBindings
|
: portBindings
|
||||||
where
|
where
|
||||||
items' = evalScoper
|
items' = evalScoper
|
||||||
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM ""
|
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM ""
|
||||||
$ map (traverseNestedModuleItems rewriteItem) $
|
$ map (traverseNestedModuleItems rewriteItem) $
|
||||||
if null modportBindings
|
if null modportBindings
|
||||||
then Modport "" (impliedModport items) : items
|
then dimensionModport : bundleModport : items
|
||||||
else items
|
else items
|
||||||
|
|
||||||
|
-- synthetic modports to be collected and removed after inlining
|
||||||
|
bundleModport = Modport "" (impliedModport items)
|
||||||
|
dimensionModport = if not isArray
|
||||||
|
then MIPackageItem $ Decl $ CommentDecl "not an instance array"
|
||||||
|
else InstArrEncoded arrayLeft arrayRight
|
||||||
|
|
||||||
inlineKind =
|
inlineKind =
|
||||||
if null modportBindings
|
if null modportBindings
|
||||||
then "interface"
|
then "interface"
|
||||||
|
|
@ -239,7 +326,7 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
filter notSubstituted instancePorts
|
filter notSubstituted instancePorts
|
||||||
notSubstituted :: PortBinding -> Bool
|
notSubstituted :: PortBinding -> Bool
|
||||||
notSubstituted (portName, _) =
|
notSubstituted (portName, _) =
|
||||||
lookup (portName) modportBindings == Nothing
|
lookup portName modportBindings == Nothing
|
||||||
|
|
||||||
rewriteItem :: ModuleItem -> ModuleItem
|
rewriteItem :: ModuleItem -> ModuleItem
|
||||||
rewriteItem =
|
rewriteItem =
|
||||||
|
|
@ -273,6 +360,7 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
traverseStmtLHSsM traverseLHSM
|
traverseStmtLHSsM traverseLHSM
|
||||||
|
|
||||||
-- used for replacing usages of modports in the module being inlined
|
-- used for replacing usages of modports in the module being inlined
|
||||||
|
modportSubstitutions = concatMap (fst . snd) modportBindings
|
||||||
lhsReplacements = map (\(x, y) -> (toLHS x, toLHS y)) exprReplacements
|
lhsReplacements = map (\(x, y) -> (toLHS x, toLHS y)) exprReplacements
|
||||||
exprReplacements = filter ((/= Nil) . snd) modportSubstitutions
|
exprReplacements = filter ((/= Nil) . snd) modportSubstitutions
|
||||||
-- LHSs are replaced using simple substitutions
|
-- LHSs are replaced using simple substitutions
|
||||||
|
|
@ -287,10 +375,21 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
else traverseSinglyNestedLHSs (tagLHS scopes) lhs
|
else traverseSinglyNestedLHSs (tagLHS scopes) lhs
|
||||||
replaceLHS :: LHS -> LHS
|
replaceLHS :: LHS -> LHS
|
||||||
replaceLHS (LHSDot lhs "@") = lhs
|
replaceLHS (LHSDot lhs "@") = lhs
|
||||||
|
replaceLHS (LHSDot (LHSBit lhs elt) field) =
|
||||||
|
case lookup (LHSDot (LHSBit lhs Tag) field) lhsReplacements of
|
||||||
|
Just resolved -> replaceLHSArrTag elt resolved
|
||||||
|
Nothing -> LHSDot (replaceLHS $ LHSBit lhs elt) field
|
||||||
|
replaceLHS (LHSBit lhs elt) =
|
||||||
|
case lookup (LHSBit lhs Tag) lhsReplacements of
|
||||||
|
Just resolved -> replaceLHSArrTag elt resolved
|
||||||
|
Nothing -> LHSBit (replaceLHS lhs) elt
|
||||||
replaceLHS lhs =
|
replaceLHS lhs =
|
||||||
case lookup lhs lhsReplacements of
|
case lookup lhs lhsReplacements of
|
||||||
Just lhs' -> lhs'
|
Just lhs' -> lhs'
|
||||||
Nothing -> traverseSinglyNestedLHSs replaceLHS lhs
|
Nothing -> traverseSinglyNestedLHSs replaceLHS lhs
|
||||||
|
replaceLHSArrTag :: Expr -> LHS -> LHS
|
||||||
|
replaceLHSArrTag =
|
||||||
|
traverseNestedLHSs . (traverseLHSExprs . replaceArrTag)
|
||||||
-- top-level expressions may be modports bound to other modports
|
-- top-level expressions may be modports bound to other modports
|
||||||
traverseExprM :: Expr -> Scoper Expr Expr
|
traverseExprM :: Expr -> Scoper Expr Expr
|
||||||
traverseExprM expr = do
|
traverseExprM expr = do
|
||||||
|
|
@ -321,17 +420,40 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
replaceExpr' expr
|
replaceExpr' expr
|
||||||
replaceExpr' :: Expr -> Expr
|
replaceExpr' :: Expr -> Expr
|
||||||
replaceExpr' (Dot expr "@") = expr
|
replaceExpr' (Dot expr "@") = expr
|
||||||
|
replaceExpr' (Dot (Bit expr elt) field) =
|
||||||
|
case lookup (Dot (Bit expr Tag) field) exprReplacements of
|
||||||
|
Just resolved -> replaceArrTag (replaceExpr' elt) resolved
|
||||||
|
Nothing -> Dot (replaceExpr' $ Bit expr elt) field
|
||||||
|
replaceExpr' (Bit expr elt) =
|
||||||
|
case lookup (Bit expr Tag) exprReplacements of
|
||||||
|
Just resolved -> replaceArrTag (replaceExpr' elt) resolved
|
||||||
|
Nothing -> Bit (replaceExpr' expr) (replaceExpr' elt)
|
||||||
replaceExpr' expr =
|
replaceExpr' expr =
|
||||||
case lookup expr exprReplacements of
|
case lookup expr exprReplacements of
|
||||||
Just expr' -> expr'
|
Just expr' -> expr'
|
||||||
Nothing -> traverseSinglyNestedExprs replaceExpr' expr
|
Nothing -> traverseSinglyNestedExprs replaceExpr' expr
|
||||||
|
replaceArrTag :: Expr -> Expr -> Expr
|
||||||
|
replaceArrTag replacement Tag = replacement
|
||||||
|
replaceArrTag replacement expr =
|
||||||
|
traverseSinglyNestedExprs (replaceArrTag replacement) expr
|
||||||
|
|
||||||
removeModportInstance :: ModuleItem -> ModuleItem
|
removeModportInstance :: ModuleItem -> ModuleItem
|
||||||
removeModportInstance (MIPackageItem (Decl (Variable d t x a e))) =
|
removeModportInstance (MIPackageItem (Decl (Variable d t x a e))) =
|
||||||
MIPackageItem $ Decl $
|
MIPackageItem $ Decl $
|
||||||
if lookup x modportBindings /= Nothing
|
if maybeModportBinding == Nothing then
|
||||||
then CommentDecl $ "removed modport instance " ++ x
|
Variable d t x a e
|
||||||
else Variable d t x a e
|
else if makeBindingBaseExpr modportE == Nothing then
|
||||||
|
CommentDecl $ "removed modport instance " ++ x
|
||||||
|
else if null a then
|
||||||
|
localparam (modportBaseName x) bindingBaseExpr
|
||||||
|
else
|
||||||
|
localparam (modportBaseName x) $
|
||||||
|
BinOp Sub bindingBaseExpr (sliceLo NonIndexed $ head a)
|
||||||
|
where
|
||||||
|
maybeModportBinding = lookup x modportBindings
|
||||||
|
Just (_, modportE) = maybeModportBinding
|
||||||
|
bindingBaseExpr = Ident $ bindingBaseName ++ x
|
||||||
|
|
||||||
removeModportInstance other = other
|
removeModportInstance other = other
|
||||||
|
|
||||||
removeDeclDir :: ModuleItem -> ModuleItem
|
removeDeclDir :: ModuleItem -> ModuleItem
|
||||||
|
|
@ -343,6 +465,26 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
_ -> t
|
_ -> t
|
||||||
removeDeclDir other = other
|
removeDeclDir other = other
|
||||||
|
|
||||||
|
-- capture the lower bound for each modport array binding
|
||||||
|
bindingBaseParams = map makeBindingBaseParam modportBindings
|
||||||
|
makeBindingBaseParam :: ModportBinding -> Decl
|
||||||
|
makeBindingBaseParam (portName, (_, modportE)) =
|
||||||
|
case makeBindingBaseExpr modportE of
|
||||||
|
Just expr -> localparam (bindingBaseName ++ portName) expr
|
||||||
|
Nothing -> CommentDecl "no-op"
|
||||||
|
bindingBaseName = "_sv2v_bind_base_" ++ shortHash instanceName ++ "_"
|
||||||
|
makeBindingBaseExpr :: Expr -> Maybe Expr
|
||||||
|
makeBindingBaseExpr modportE =
|
||||||
|
case modportE of
|
||||||
|
Dot (Range _ mode range) _ -> Just $ sliceLo mode range
|
||||||
|
Range _ mode range -> Just $ sliceLo mode range
|
||||||
|
Dot (Bit _ idx) _ -> Just idx
|
||||||
|
Bit _ idx -> Just idx
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
localparam :: Identifier -> Expr -> Decl
|
||||||
|
localparam = Param Localparam (Implicit Unspecified [])
|
||||||
|
|
||||||
paramTmp = "_tmp_" ++ (shortHash (items, instanceName)) ++ "_"
|
paramTmp = "_tmp_" ++ (shortHash (items, instanceName)) ++ "_"
|
||||||
|
|
||||||
parameterBinds = map makeParameterBind instanceParams
|
parameterBinds = map makeParameterBind instanceParams
|
||||||
|
|
@ -371,10 +513,15 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
portBindingItem :: PortBinding -> Maybe ModuleItem
|
portBindingItem :: PortBinding -> Maybe ModuleItem
|
||||||
portBindingItem (_, Nil) = Nothing
|
portBindingItem (_, Nil) = Nothing
|
||||||
portBindingItem (ident, expr) =
|
portBindingItem (ident, expr) =
|
||||||
|
Just $ wrapInstance $ GenModuleItem $
|
||||||
if findDeclDir ident == Input
|
if findDeclDir ident == Input
|
||||||
then bind (LHSDot (LHSIdent instanceName) ident) expr
|
then bind (LHSDot (inj LHSBit LHSIdent) ident) expr
|
||||||
else bind (toLHS expr) (Dot (Ident instanceName) ident)
|
else bind (toLHS expr) (Dot (inj Bit Ident) ident)
|
||||||
where bind a b = Just $ Assign AssignOptionNone a b
|
where
|
||||||
|
bind = Assign AssignOptionNone
|
||||||
|
inj bit idn = if null ranges
|
||||||
|
then idn instanceName
|
||||||
|
else bit (idn instanceName) (Ident loopVar)
|
||||||
|
|
||||||
declDirs = execWriter $
|
declDirs = execWriter $
|
||||||
mapM (collectDeclsM collectDeclDir) items
|
mapM (collectDeclsM collectDeclDir) items
|
||||||
|
|
@ -397,6 +544,50 @@ inlineInstance modportBindings modportSubstitutions items
|
||||||
Nothing -> error $ "trying to bind an " ++ inlineKind
|
Nothing -> error $ "trying to bind an " ++ inlineKind
|
||||||
++ " output to " ++ show expr ++ " but that can't be an LHS"
|
++ " output to " ++ show expr ++ " but that can't be an LHS"
|
||||||
|
|
||||||
|
-- for instance arrays, a unique identifier to be used as a genvar
|
||||||
|
loopVar = "_sv2v_arr_" ++ shortHash (instanceName, ranges)
|
||||||
|
|
||||||
|
isArray = not $ null ranges
|
||||||
|
[arrayRange @ (arrayLeft, arrayRight)] = ranges
|
||||||
|
|
||||||
|
-- wrap the given item in a generate loop if necessary
|
||||||
|
wrapInstance :: GenItem -> ModuleItem
|
||||||
|
wrapInstance item =
|
||||||
|
Generate $
|
||||||
|
if not isArray then
|
||||||
|
[item]
|
||||||
|
else
|
||||||
|
[ GenModuleItem (Genvar loopVar)
|
||||||
|
, GenFor inits cond incr item
|
||||||
|
]
|
||||||
|
where
|
||||||
|
inits = (loopVar, arrayLeft)
|
||||||
|
cond = endianCondExpr arrayRange
|
||||||
|
(BinOp Ge (Ident loopVar) arrayRight)
|
||||||
|
(BinOp Le (Ident loopVar) arrayRight)
|
||||||
|
incr = (loopVar, AsgnOp Add, step)
|
||||||
|
step = endianCondExpr arrayRange
|
||||||
|
(UniOp UniSub $ RawNum 1) (RawNum 1)
|
||||||
|
|
||||||
|
-- used for modport array binding offset placeholders
|
||||||
|
pattern Tag :: Expr
|
||||||
|
pattern Tag = Ident "%"
|
||||||
|
|
||||||
|
modportBaseName :: Identifier -> Identifier
|
||||||
|
modportBaseName = (++) "_sv2v_base_"
|
||||||
|
|
||||||
|
-- the dimensions of interface instance arrays are encoded as synthetic modports
|
||||||
|
-- during inlining, enabling subsequent modport bindings to implicitly use the
|
||||||
|
-- bounds of the interface instance array when the bounds are unspecified
|
||||||
|
pattern InstArrName :: Identifier
|
||||||
|
pattern InstArrName = "~instance_array_dimensions~"
|
||||||
|
pattern InstArrVal :: Expr -> Expr -> [ModportDecl]
|
||||||
|
pattern InstArrVal l r = [(Local, "l", l), (Local, "r", r)]
|
||||||
|
pattern InstArrKey :: Expr -> Expr
|
||||||
|
pattern InstArrKey expr = Dot (Bit expr (RawNum 0)) InstArrName
|
||||||
|
pattern InstArrEncoded :: Expr -> Expr -> ModuleItem
|
||||||
|
pattern InstArrEncoded l r = Modport InstArrName (InstArrVal l r)
|
||||||
|
|
||||||
type Binding t = (Identifier, t)
|
type Binding t = (Identifier, t)
|
||||||
-- give a set of bindings explicit names
|
-- give a set of bindings explicit names
|
||||||
resolveBindings :: Show t => [Identifier] -> [Binding t] -> [Binding t]
|
resolveBindings :: Show t => [Identifier] -> [Binding t] -> [Binding t]
|
||||||
|
|
@ -419,3 +610,9 @@ parameterNames =
|
||||||
collectDeclM (Param Parameter _ x _) = tell [x]
|
collectDeclM (Param Parameter _ x _) = tell [x]
|
||||||
collectDeclM (ParamType Parameter x _) = tell [x]
|
collectDeclM (ParamType Parameter x _) = tell [x]
|
||||||
collectDeclM _ = return ()
|
collectDeclM _ = return ()
|
||||||
|
|
||||||
|
-- determines the lower bound for the given slice
|
||||||
|
sliceLo :: PartSelectMode -> Range -> Expr
|
||||||
|
sliceLo NonIndexed (l, r) = endianCondExpr (l, r) r l
|
||||||
|
sliceLo IndexedPlus (base, _) = base
|
||||||
|
sliceLo IndexedMinus (base, len) = BinOp Add (BinOp Sub base len) (RawNum 1)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
interface Interface(i);
|
||||||
|
input i;
|
||||||
|
logic v;
|
||||||
|
logic o;
|
||||||
|
task tick;
|
||||||
|
$display("I i = %b, v = %b, o = %b", i, v, o);
|
||||||
|
endtask
|
||||||
|
initial $display("Hello I'm Interface!");
|
||||||
|
modport ModportA(
|
||||||
|
input .i(i ^ 1'b1),
|
||||||
|
output v
|
||||||
|
);
|
||||||
|
modport ModportB(
|
||||||
|
input .i(i),
|
||||||
|
output .v(o)
|
||||||
|
);
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module ModuleA(i);
|
||||||
|
parameter flip = 0;
|
||||||
|
Interface i;
|
||||||
|
assign i.v = i.i ^ 1'(flip);
|
||||||
|
task tick;
|
||||||
|
$display("A i.v = %b", i.v);
|
||||||
|
endtask
|
||||||
|
initial $display("Hello I'm ModuleA %0d!", flip);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleASet(is);
|
||||||
|
parameter flip2 = 0;
|
||||||
|
parameter flip1 = 0;
|
||||||
|
parameter flip0 = 0;
|
||||||
|
Interface is [2:0];
|
||||||
|
assign is[2].v = is[2].i ^ 1'(flip2);
|
||||||
|
assign is[1].v = is[1].i ^ 1'(flip1);
|
||||||
|
assign is[0].v = is[0].i ^ 1'(flip0);
|
||||||
|
task tick;
|
||||||
|
$display("AS i.v = %b", is[2].v);
|
||||||
|
$display("AS i.v = %b", is[1].v);
|
||||||
|
$display("AS i.v = %b", is[0].v);
|
||||||
|
endtask
|
||||||
|
initial begin
|
||||||
|
$display("Hello I'm ModuleASet %0d %0d %0d!", flip2, flip1, flip0);
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleCSet(is);
|
||||||
|
parameter flip2 = 0;
|
||||||
|
parameter flip1 = 0;
|
||||||
|
parameter flip0 = 0;
|
||||||
|
Interface.ModportB is [2:0];
|
||||||
|
assign is[2].v = is[2].i ^ 1'(flip2);
|
||||||
|
assign is[1].v = is[1].i ^ 1'(flip1);
|
||||||
|
assign is[0].v = is[0].i ^ 1'(flip0);
|
||||||
|
task tick;
|
||||||
|
$display("CS i.v = %b", is[2].v);
|
||||||
|
$display("CS i.v = %b", is[1].v);
|
||||||
|
$display("CS i.v = %b", is[0].v);
|
||||||
|
endtask
|
||||||
|
initial begin
|
||||||
|
$display("Hello I'm ModuleCSet %0d %0d %0d!", flip2, flip1, flip0);
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleB(is);
|
||||||
|
parameter WIDTH = 1;
|
||||||
|
Interface is [WIDTH-1:0];
|
||||||
|
logic [WIDTH-1:0] i_concat;
|
||||||
|
logic [WIDTH-1:0] v_concat;
|
||||||
|
for (genvar i = WIDTH - 1; i >= 0; i = i - 1) begin
|
||||||
|
assign i_concat[i] = is[i].i;
|
||||||
|
assign v_concat[i] = is[i].v;
|
||||||
|
end
|
||||||
|
task tick;
|
||||||
|
$display("B i_concat = %b, v_concat = %b", i_concat, v_concat);
|
||||||
|
bn.tick;
|
||||||
|
endtask
|
||||||
|
initial $display("Hello I'm ModuleB %0d!", WIDTH);
|
||||||
|
ModuleBNested #(WIDTH) bn(is);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleBNested(is);
|
||||||
|
parameter WIDTH = 1;
|
||||||
|
Interface is [WIDTH-1:0];
|
||||||
|
logic [WIDTH-1:0] i_concat;
|
||||||
|
logic [WIDTH-1:0] v_concat;
|
||||||
|
for (genvar i = WIDTH - 1; i >= 0; i = i - 1) begin
|
||||||
|
assign i_concat[i] = is[i].i;
|
||||||
|
assign v_concat[i] = is[i].v;
|
||||||
|
end
|
||||||
|
task tick;
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", i_concat, v_concat);
|
||||||
|
endtask
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top;
|
||||||
|
logic inp;
|
||||||
|
|
||||||
|
Interface intfX[2:0](inp);
|
||||||
|
|
||||||
|
ModuleA #(0) xa2(intfX[2]);
|
||||||
|
ModuleA #(1) xa1(intfX[1]);
|
||||||
|
ModuleA #(1) xa0(intfX[0]);
|
||||||
|
|
||||||
|
ModuleB #(3) xb20(intfX[2:0]);
|
||||||
|
ModuleB #(2) xb21(intfX[2:1]);
|
||||||
|
ModuleB #(1) xb22(intfX[2:2]);
|
||||||
|
ModuleB #(1) xb11(intfX[1:1]);
|
||||||
|
ModuleB #(1) xb00(intfX[0:0]);
|
||||||
|
ModuleB #(3) xbf(intfX);
|
||||||
|
|
||||||
|
ModuleASet #(1, 1, 0) xs(intfX[2:0].ModportB);
|
||||||
|
|
||||||
|
Interface intfY[2:0](inp);
|
||||||
|
|
||||||
|
ModuleA #(0) ya2(intfY[2].ModportA);
|
||||||
|
ModuleA #(1) ya1(intfY[1].ModportA);
|
||||||
|
ModuleA #(1) ya0(intfY[0].ModportA);
|
||||||
|
|
||||||
|
ModuleB #(3) yb20(intfY[2:0].ModportA);
|
||||||
|
ModuleB #(2) yb21(intfY[2:1].ModportA);
|
||||||
|
ModuleB #(1) yb22(intfY[2:2].ModportA);
|
||||||
|
ModuleB #(1) yb11(intfY[1:1].ModportA);
|
||||||
|
ModuleB #(1) yb00(intfY[0:0].ModportA);
|
||||||
|
ModuleB #(3) ybf(intfY.ModportA);
|
||||||
|
|
||||||
|
ModuleCSet #(0, 0, 1) ys(intfY[2:0]);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
inp = 0; tick;
|
||||||
|
inp = 1; tick;
|
||||||
|
inp = 0; tick;
|
||||||
|
inp = 1; tick;
|
||||||
|
end
|
||||||
|
|
||||||
|
task tick;
|
||||||
|
#1;
|
||||||
|
|
||||||
|
intfX[2].tick;
|
||||||
|
intfX[1].tick;
|
||||||
|
intfX[0].tick;
|
||||||
|
|
||||||
|
xa2.tick;
|
||||||
|
xa1.tick;
|
||||||
|
xa0.tick;
|
||||||
|
|
||||||
|
xb20.tick;
|
||||||
|
xb21.tick;
|
||||||
|
xb22.tick;
|
||||||
|
xb11.tick;
|
||||||
|
xb00.tick;
|
||||||
|
xbf.tick;
|
||||||
|
|
||||||
|
xs.tick;
|
||||||
|
|
||||||
|
intfY[2].tick;
|
||||||
|
intfY[1].tick;
|
||||||
|
intfY[0].tick;
|
||||||
|
|
||||||
|
ya2.tick;
|
||||||
|
ya1.tick;
|
||||||
|
ya0.tick;
|
||||||
|
|
||||||
|
yb20.tick;
|
||||||
|
yb21.tick;
|
||||||
|
yb22.tick;
|
||||||
|
yb11.tick;
|
||||||
|
yb00.tick;
|
||||||
|
ybf.tick;
|
||||||
|
|
||||||
|
ys.tick;
|
||||||
|
endtask
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
module top;
|
||||||
|
reg inp;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$display("Hello I'm Interface!");
|
||||||
|
$display("Hello I'm Interface!");
|
||||||
|
$display("Hello I'm Interface!");
|
||||||
|
|
||||||
|
$display("Hello I'm ModuleA 0!");
|
||||||
|
$display("Hello I'm ModuleA 1!");
|
||||||
|
$display("Hello I'm ModuleA 1!");
|
||||||
|
|
||||||
|
$display("Hello I'm ModuleB 3!");
|
||||||
|
$display("Hello I'm ModuleB 2!");
|
||||||
|
$display("Hello I'm ModuleB 1!");
|
||||||
|
$display("Hello I'm ModuleB 1!");
|
||||||
|
$display("Hello I'm ModuleB 1!");
|
||||||
|
$display("Hello I'm ModuleB 3!");
|
||||||
|
|
||||||
|
$display("Hello I'm ModuleASet 1 1 0!");
|
||||||
|
|
||||||
|
$display("Hello I'm Interface!");
|
||||||
|
$display("Hello I'm Interface!");
|
||||||
|
$display("Hello I'm Interface!");
|
||||||
|
|
||||||
|
$display("Hello I'm ModuleA 0!");
|
||||||
|
$display("Hello I'm ModuleA 1!");
|
||||||
|
$display("Hello I'm ModuleA 1!");
|
||||||
|
|
||||||
|
$display("Hello I'm ModuleB 3!");
|
||||||
|
$display("Hello I'm ModuleB 2!");
|
||||||
|
$display("Hello I'm ModuleB 1!");
|
||||||
|
$display("Hello I'm ModuleB 1!");
|
||||||
|
$display("Hello I'm ModuleB 1!");
|
||||||
|
$display("Hello I'm ModuleB 3!");
|
||||||
|
|
||||||
|
$display("Hello I'm ModuleCSet 0 0 1!");
|
||||||
|
|
||||||
|
inp = 0; tick;
|
||||||
|
inp = 1; tick;
|
||||||
|
inp = 0; tick;
|
||||||
|
inp = 1; tick;
|
||||||
|
end
|
||||||
|
|
||||||
|
task tick; begin
|
||||||
|
#1;
|
||||||
|
|
||||||
|
$display("I i = %b, v = %b, o = %b", inp, inp, inp ^ 1'b1);
|
||||||
|
$display("I i = %b, v = %b, o = %b", inp, inp ^ 1'b1, inp ^ 1'b1);
|
||||||
|
$display("I i = %b, v = %b, o = %b", inp, inp ^ 1'b1, inp);
|
||||||
|
|
||||||
|
$display("A i.v = %b", inp);
|
||||||
|
$display("A i.v = %b", inp ^ 1'b1);
|
||||||
|
$display("A i.v = %b", inp ^ 1'b1);
|
||||||
|
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {3 {inp}}, {inp, inp ^ 1'b1, inp ^ 1'b1});
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {3 {inp}}, {inp, inp ^ 1'b1, inp ^ 1'b1});
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {2 {inp}}, {inp, inp ^ 1'b1});
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {2 {inp}}, {inp, inp ^ 1'b1});
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {1 {inp}}, inp);
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {1 {inp}}, inp);
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {1 {inp}}, inp ^ 1'b1);
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {1 {inp}}, inp ^ 1'b1);
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {1 {inp}}, inp ^ 1'b1);
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {1 {inp}}, inp ^ 1'b1);
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {3 {inp}}, {inp, inp ^ 1'b1, inp ^ 1'b1});
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {3 {inp}}, {inp, inp ^ 1'b1, inp ^ 1'b1});
|
||||||
|
|
||||||
|
$display("AS i.v = %b", inp ^ 1'b1);
|
||||||
|
$display("AS i.v = %b", inp ^ 1'b1);
|
||||||
|
$display("AS i.v = %b", inp);
|
||||||
|
|
||||||
|
$display("I i = %b, v = %b, o = %b", inp, inp ^ 1'b1, inp);
|
||||||
|
$display("I i = %b, v = %b, o = %b", inp, inp, inp);
|
||||||
|
$display("I i = %b, v = %b, o = %b", inp, inp, inp ^ 1'b1);
|
||||||
|
|
||||||
|
$display("A i.v = %b", inp ^ 1'b1);
|
||||||
|
$display("A i.v = %b", inp);
|
||||||
|
$display("A i.v = %b", inp);
|
||||||
|
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {3 {~inp}}, {inp ^ 1'b1, inp, inp});
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {3 {~inp}}, {inp ^ 1'b1, inp, inp});
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {2 {~inp}}, {inp ^ 1'b1, inp});
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {2 {~inp}}, {inp ^ 1'b1, inp});
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {1 {~inp}}, inp ^ 1'b1);
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {1 {~inp}}, inp ^ 1'b1);
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {1 {~inp}}, inp);
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {1 {~inp}}, inp);
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {1 {~inp}}, inp);
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {1 {~inp}}, inp);
|
||||||
|
$display("B i_concat = %b, v_concat = %b", {3 {~inp}}, {inp ^ 1'b1, inp, inp});
|
||||||
|
$display("BN i_concat = %b, v_concat = %b", {3 {~inp}}, {inp ^ 1'b1, inp, inp});
|
||||||
|
|
||||||
|
$display("CS i.v = %b", inp);
|
||||||
|
$display("CS i.v = %b", inp);
|
||||||
|
$display("CS i.v = %b", inp ^ 1'b1);
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
interface Interface;
|
||||||
|
logic x;
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module top;
|
||||||
|
Interface intfs[3:2][8:5]();
|
||||||
|
for (genvar x = 2; x <= 3; x = x + 1)
|
||||||
|
for (genvar y = 5; y <= 8; y = y + 1)
|
||||||
|
assign intfs[x][y].x = '1;
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
module top;
|
||||||
|
generate
|
||||||
|
if (1) begin : block
|
||||||
|
wire [3:2][8:5] xs;
|
||||||
|
genvar x, y;
|
||||||
|
for (x = 2; x <= 3; x = x + 1)
|
||||||
|
for (y = 5; y <= 8; y = y + 1)
|
||||||
|
assign xs[x][y] = 1'b1;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
`define SHADOW \
|
||||||
|
integer i; \
|
||||||
|
Interface intfs[1:0]();
|
||||||
|
|
||||||
|
interface Interface;
|
||||||
|
integer x;
|
||||||
|
modport ModportA(input .x(x + 1));
|
||||||
|
modport ModportB(input .x(x + 2));
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module ModuleA(intf);
|
||||||
|
Interface intf;
|
||||||
|
`SHADOW
|
||||||
|
initial #1 $display("ModuleA got %0d", intf.x);
|
||||||
|
ModuleN n(intf);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleB(intf);
|
||||||
|
Interface.ModportA intf;
|
||||||
|
`SHADOW
|
||||||
|
initial #1 $display("ModuleB got %0d", intf.x);
|
||||||
|
ModuleN n(intf);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleC(intf);
|
||||||
|
Interface.ModportB intf;
|
||||||
|
`SHADOW
|
||||||
|
initial #1 $display("ModuleC got %0d", intf.x);
|
||||||
|
ModuleN n(intf);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ModuleN(intf);
|
||||||
|
Interface intf;
|
||||||
|
`SHADOW
|
||||||
|
initial #1 $display("ModuleN got %0d", intf.x);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top;
|
||||||
|
Interface intfs[4:8]();
|
||||||
|
`define LOOP for (genvar i = 4; i <= 8; ++i)
|
||||||
|
`LOOP initial intfs[i].x = i ** 2;
|
||||||
|
`LOOP ModuleA a1(intfs[i]);
|
||||||
|
`LOOP ModuleA a2(intfs[i].ModportA);
|
||||||
|
`LOOP ModuleA a3(intfs[i].ModportB);
|
||||||
|
`LOOP ModuleB b1(intfs[i]);
|
||||||
|
`LOOP ModuleB b2(intfs[i].ModportA);
|
||||||
|
`LOOP ModuleC c1(intfs[i]);
|
||||||
|
`LOOP ModuleC c2(intfs[i].ModportB);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
module top;
|
||||||
|
genvar i;
|
||||||
|
generate
|
||||||
|
|
||||||
|
initial #1;
|
||||||
|
|
||||||
|
`define PRINT(X, offset) \
|
||||||
|
for (i = 4; i <= 8; i = i + 1) \
|
||||||
|
initial begin \
|
||||||
|
$display(`"Module``X got %0d`", i ** 2 + offset); \
|
||||||
|
$display("ModuleN got %0d", i ** 2 + offset); \
|
||||||
|
end
|
||||||
|
|
||||||
|
`PRINT(A, 0)
|
||||||
|
`PRINT(A, 1)
|
||||||
|
`PRINT(A, 2)
|
||||||
|
|
||||||
|
`PRINT(B, 1)
|
||||||
|
`PRINT(B, 1)
|
||||||
|
|
||||||
|
`PRINT(C, 2)
|
||||||
|
`PRINT(C, 2)
|
||||||
|
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
interface Interface;
|
||||||
|
logic x;
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module Module(intfs);
|
||||||
|
parameter LEFT = 0;
|
||||||
|
parameter RIGHT = 0;
|
||||||
|
Interface intfs[LEFT:RIGHT];
|
||||||
|
logic [LEFT:RIGHT] xs;
|
||||||
|
localparam LO = LEFT > RIGHT ? RIGHT : LEFT;
|
||||||
|
localparam HI = LEFT > RIGHT ? LEFT : RIGHT;
|
||||||
|
for (genvar i = LO; i <= HI; i = i + 1) begin
|
||||||
|
// intentional shadowing of dimension constants
|
||||||
|
localparam LEFT = 0;
|
||||||
|
localparam RIGHT = 0;
|
||||||
|
assign xs[i] = intfs[i].x;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module Instance();
|
||||||
|
parameter LEFT = 0;
|
||||||
|
parameter RIGHT = 0;
|
||||||
|
|
||||||
|
parameter INNER_LEFT = 0;
|
||||||
|
parameter INNER_RIGHT = 0;
|
||||||
|
parameter INNER_OFFSET = 0;
|
||||||
|
|
||||||
|
reg [LEFT:RIGHT] xs;
|
||||||
|
|
||||||
|
localparam DIR = LEFT >= RIGHT ? -1 : 1;
|
||||||
|
Interface intfs[LEFT:RIGHT]();
|
||||||
|
generate
|
||||||
|
genvar i;
|
||||||
|
for (i = LEFT; i <= RIGHT; i = i + DIR)
|
||||||
|
assign intfs[i].x = xs[i];
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
// intentional name collision with localparams in the module
|
||||||
|
localparam LO = INNER_LEFT >= INNER_RIGHT ? INNER_RIGHT : INNER_LEFT;
|
||||||
|
localparam HI = INNER_LEFT >= INNER_RIGHT ? INNER_LEFT : INNER_RIGHT;
|
||||||
|
localparam LEN = HI - LO + 1;
|
||||||
|
|
||||||
|
Module #(INNER_LEFT + INNER_OFFSET, INNER_RIGHT + INNER_OFFSET)
|
||||||
|
l(intfs[INNER_LEFT:INNER_RIGHT]);
|
||||||
|
Module #(INNER_LEFT + INNER_OFFSET, INNER_RIGHT + INNER_OFFSET)
|
||||||
|
m(intfs[LO+:LEN]);
|
||||||
|
Module #(INNER_LEFT + INNER_OFFSET, INNER_RIGHT + INNER_OFFSET)
|
||||||
|
n(intfs[HI-:LEN]);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
module Module(xs);
|
||||||
|
parameter LEFT = 0;
|
||||||
|
parameter RIGHT = 0;
|
||||||
|
input wire [LEFT:RIGHT] xs;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module Instance();
|
||||||
|
parameter LEFT = 0;
|
||||||
|
parameter RIGHT = 0;
|
||||||
|
|
||||||
|
parameter INNER_LEFT = 0;
|
||||||
|
parameter INNER_RIGHT = 0;
|
||||||
|
parameter INNER_OFFSET = 0;
|
||||||
|
|
||||||
|
reg [LEFT:RIGHT] xs;
|
||||||
|
|
||||||
|
localparam LO = INNER_LEFT >= INNER_RIGHT ? INNER_RIGHT : INNER_LEFT;
|
||||||
|
localparam HI = INNER_LEFT >= INNER_RIGHT ? INNER_LEFT : INNER_RIGHT;
|
||||||
|
localparam LEN = HI - LO + 1;
|
||||||
|
|
||||||
|
Module #(INNER_LEFT + INNER_OFFSET, INNER_RIGHT + INNER_OFFSET)
|
||||||
|
l(xs[INNER_LEFT:INNER_RIGHT]);
|
||||||
|
Module #(INNER_LEFT + INNER_OFFSET, INNER_RIGHT + INNER_OFFSET)
|
||||||
|
m(xs[LO+:LEN]);
|
||||||
|
Module #(INNER_LEFT + INNER_OFFSET, INNER_RIGHT + INNER_OFFSET)
|
||||||
|
n(xs[HI-:LEN]);
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
module Test();
|
||||||
|
parameter BASE = 0;
|
||||||
|
parameter SIZE = 0;
|
||||||
|
parameter DIR = 0;
|
||||||
|
|
||||||
|
localparam LEFT = BASE;
|
||||||
|
localparam RIGHT = BASE + DIR * (SIZE - 1);
|
||||||
|
|
||||||
|
genvar left, right, offset;
|
||||||
|
generate
|
||||||
|
for (left = LEFT + SIZE; left <= RIGHT + SIZE; left = left + 1)
|
||||||
|
for (right = LEFT + SIZE; right <= RIGHT + SIZE; right = right + 1)
|
||||||
|
if ((left - right) * DIR <= 0)
|
||||||
|
for (offset = -2 + SIZE; offset <= 2 + SIZE; offset = offset + 1)
|
||||||
|
begin
|
||||||
|
|
||||||
|
Instance #(
|
||||||
|
LEFT, RIGHT,
|
||||||
|
left - SIZE, right - SIZE, offset - SIZE
|
||||||
|
) i();
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
i.xs = 1;
|
||||||
|
while (i.xs != 0) begin
|
||||||
|
#1;
|
||||||
|
$display("LEFT=%2d RIGHT=%2d INNER_LEFT=%2d INNER_RIGHT=%2d INNER_OFFSET=%2d i.xs=%b i.l.xs=%b i.m.xs=%b i.n.xs=%b",
|
||||||
|
LEFT, RIGHT,
|
||||||
|
left - SIZE, right - SIZE, offset - SIZE,
|
||||||
|
i.xs, i.l.xs, i.m.xs, i.n.xs);
|
||||||
|
i.xs = i.xs + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module Suite();
|
||||||
|
parameter SIZE = 0;
|
||||||
|
genvar base;
|
||||||
|
generate
|
||||||
|
for (base = -2 + SIZE; base <= 2 + SIZE; base = base + 1) begin
|
||||||
|
Test #(base - SIZE, SIZE, -1) b();
|
||||||
|
Test #(base - SIZE, SIZE, 1) f();
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top;
|
||||||
|
Suite #(2) s2();
|
||||||
|
Suite #(3) s3();
|
||||||
|
Suite #(4) s4();
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue