Commit 2b377cef by Zachary Snow

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
parent 8eac9b01
{-# LANGUAGE PatternSynonyms #-}
{- sv2v {- sv2v
- Author: Zachary Snow <zach@zachjs.com> - Author: Zachary Snow <zach@zachjs.com>
- -
...@@ -11,6 +12,7 @@ import Data.Maybe (mapMaybe) ...@@ -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 ...@@ -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
then files
else traverseFiles
(collectDescriptionsM collectPart)
(map . convertDescription) (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) = ...@@ -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) = ...@@ -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) = ...@@ -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) = ...@@ -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
qualifyModport :: Expr -> Expr
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 foldl accessToExpr (Ident topName) rest
where Access topName Nil : rest = init accesses 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) = ...@@ -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 = ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 = ...@@ -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)
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
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
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
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
`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
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
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
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
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment