Commit cd8af036 by Zachary Snow

logic conversion supports generate block scoping

parent af319c36
...@@ -30,11 +30,14 @@ import Control.Monad.Writer ...@@ -30,11 +30,14 @@ import Control.Monad.Writer
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import Convert.Scoper
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
type Idents = Set.Set Identifier
type Ports = Map.Map Identifier [(Identifier, Direction)] type Ports = Map.Map Identifier [(Identifier, Direction)]
type Location = [Identifier]
type Locations = Set.Set Location
type ST = ScoperT Type (State Locations)
convert :: [AST] -> [AST] convert :: [AST] -> [AST]
convert = convert =
...@@ -63,40 +66,49 @@ convert = ...@@ -63,40 +66,49 @@ convert =
collectDeclDirsM _ = return () collectDeclDirsM _ = return ()
convertDescription :: Ports -> Description -> Description convertDescription :: Ports -> Description -> Description
convertDescription ports orig = convertDescription ports (description @ (Part _ _ Module _ _ _ _)) =
if shouldConvert evalState (operation description) Set.empty
then converted
else orig
where where
shouldConvert = case orig of operation =
Part _ _ Interface _ _ _ _ -> False -- log then rewrite
Part _ _ Module _ _ _ _ -> True partScoperT td tm tg ts >=>
PackageItem _ -> True partScoperT rd tm tg ts
Package _ _ _ -> False td = traverseDeclM
rd = rewriteDeclM
logics = execWriter (collectModuleItemsM collectLogicM orig) tm = traverseModuleItemM ports
collectLogicM :: ModuleItem -> Writer Idents () tg = traverseGenItemM
collectLogicM (MIPackageItem (Decl (Variable _ t x _ _))) = ts = traverseStmtM
case t of convertDescription _ other = other
IntegerVector TLogic _ _ -> tell $ Set.singleton x
_ -> return () traverseGenItemM :: GenItem -> ST GenItem
collectLogicM _ = return () traverseGenItemM = return
origIdents = Set.intersection logics $ traverseModuleItemM :: Ports -> ModuleItem -> ST ModuleItem
execWriter (collectModuleItemsM regIdents orig) traverseModuleItemM ports = embedScopes $ traverseModuleItem ports
fixed = traverseModuleItems fixModuleItem orig
fixedIdents = execWriter (collectModuleItemsM regIdents fixed) traverseModuleItem :: Ports -> Scopes Type -> ModuleItem -> ModuleItem
conversion = traverseDecls convertDecl . convertModuleItem traverseModuleItem ports scopes =
converted = traverseModuleItems conversion fixed fixModuleItem
where
isReg :: LHS -> Bool
isReg =
or . execWriter . collectNestedLHSsM isReg'
where
isRegType :: Type -> Bool
isRegType (IntegerVector TReg _ _) = True
isRegType _ = False
isReg' :: LHS -> Writer [Bool] ()
isReg' lhs =
case lookupLHS scopes lhs of
Just (_, _, t) -> tell [isRegType t]
_ -> tell [False]
fixModuleItem :: ModuleItem -> ModuleItem fixModuleItem :: ModuleItem -> ModuleItem
-- rewrite bad continuous assignments to use procedural assignments -- rewrite bad continuous assignments to use procedural assignments
fixModuleItem (Assign AssignOptionNone lhs expr) = fixModuleItem (Assign AssignOptionNone lhs expr) =
if Set.disjoint usedIdents origIdents if not (isReg lhs)
then Assign AssignOptionNone lhs expr then Assign AssignOptionNone lhs expr
else AlwaysC AlwaysComb $ Asgn AsgnOpEq Nothing lhs expr else AlwaysC AlwaysComb $ Asgn AsgnOpEq Nothing lhs expr
where
usedIdents = execWriter $ collectNestedLHSsM lhsIdents lhs
-- rewrite port bindings to use temporary nets where necessary -- rewrite port bindings to use temporary nets where necessary
fixModuleItem (Instance moduleName params instanceName rs bindings) = fixModuleItem (Instance moduleName params instanceName rs bindings) =
if null newItems if null newItems
...@@ -112,13 +124,13 @@ convertDescription ports orig = ...@@ -112,13 +124,13 @@ convertDescription ports orig =
newItems = concat newItemsList newItems = concat newItemsList
fixBinding :: PortBinding -> Int -> (PortBinding, [ModuleItem]) fixBinding :: PortBinding -> Int -> (PortBinding, [ModuleItem])
fixBinding (portName, expr) portIdx = fixBinding (portName, expr) portIdx =
if portDir /= Just Output || Set.disjoint usedIdents origIdents if not outputBound || not usesReg
then ((portName, expr), []) then ((portName, expr), [])
else ((portName, tmpExpr), items) else ((portName, tmpExpr), items)
where where
outputBound = portDir == Just Output
usesReg = Just True == fmap isReg (exprToLHS expr)
portDir = lookupPortDir portName portIdx portDir = lookupPortDir portName portIdx
usedIdents = execWriter $
collectNestedExprsM exprIdents expr
tmp = "sv2v_tmp_" ++ instanceName ++ "_" ++ portName tmp = "sv2v_tmp_" ++ instanceName ++ "_" ++ portName
tmpExpr = Ident tmp tmpExpr = Ident tmp
t = Net (NetType TWire) Unspecified t = Net (NetType TWire) Unspecified
...@@ -145,72 +157,57 @@ convertDescription ports orig = ...@@ -145,72 +157,57 @@ convertDescription ports orig =
Just l -> lookup portName l Just l -> lookup portName l
fixModuleItem other = other fixModuleItem other = other
-- rewrite variable declarations to have the correct type traverseDeclM :: Decl -> ST Decl
convertModuleItem (MIPackageItem (Decl (Variable dir (IntegerVector _ sg mr) ident a e))) = traverseDeclM (decl @ (Variable _ t x _ _)) =
MIPackageItem $ Decl $ Variable dir' (t mr) ident a e insertElem x t >> return decl
where
t = if Set.member ident fixedIdents
then IntegerVector TReg sg
else Net (NetType TWire) sg
dir' =
if dir == Inout && Set.member ident fixedIdents
then Output
else dir
convertModuleItem other = other
-- all other logics (i.e. inside of functions) become regs
convertDecl :: Decl -> Decl
convertDecl (Param s (IntegerVector _ sg []) x e) =
Param s (Implicit sg [(Number "0", Number "0")]) x e
convertDecl (Param s (IntegerVector _ sg rs) x e) =
Param s (Implicit sg rs) x e
convertDecl (Variable d (IntegerVector TLogic sg rs) x a e) =
Variable d (IntegerVector TReg sg rs) x a e
convertDecl other = other
regIdents :: ModuleItem -> Writer Idents ()
regIdents (item @ AlwaysC{}) = regIdents' item
regIdents (item @ Initial{}) = regIdents' item
regIdents (item @ Final{}) = regIdents' item
regIdents (item @ (MIPackageItem Task {})) = regIdents' item
regIdents (item @ (MIPackageItem Function{})) = regIdents' item
regIdents _ = return ()
regIdents' :: ModuleItem -> Writer Idents ()
regIdents' item = do
let write = traverseScopesM traverseDeclM return traverseStmtM item
leftovers <- execStateT write Set.empty
if Set.null leftovers
then return ()
else error $ "regIdents' got leftovers: " ++ show leftovers
traverseDeclM :: Monad m => Decl -> StateT Idents m Decl
traverseDeclM (decl @ (Variable _ _ x _ _)) =
modify (Set.insert x) >> return decl
traverseDeclM decl = return decl traverseDeclM decl = return decl
traverseStmtM :: Stmt -> StateT Idents (Writer Idents) Stmt rewriteDeclM :: Decl -> ST Decl
traverseStmtM (Timing _ stmt) = traverseStmtM stmt rewriteDeclM (Variable d t x a e) = do
(d', t') <- case t of
IntegerVector TLogic sg rs -> do
insertElem x t
details <- lookupIdentM x
let Just (accesses, _, _) = details
let location = map accessName accesses
usedAsReg <- lift $ gets $ Set.member location
blockLogic <- withinProcedureM
if usedAsReg || blockLogic
then do
let dir = if d == Inout then Output else d
return (dir, IntegerVector TReg sg rs)
else return (d, Net (NetType TWire) sg rs)
_ -> return (d, t)
insertElem x t'
return $ Variable d' t' x a e
rewriteDeclM (Param s (IntegerVector _ sg []) x e) =
return $ Param s (Implicit sg [(zero, zero)]) x e
where zero = Number "0"
rewriteDeclM (Param s (IntegerVector _ sg rs) x e) =
return $ Param s (Implicit sg rs) x e
rewriteDeclM decl = return decl
traverseStmtM :: Stmt -> ST Stmt
traverseStmtM (Timing timing stmt) =
-- ignore the timing LHSs
return $ Timing timing stmt
traverseStmtM (Subroutine (Ident f) args) = do traverseStmtM (Subroutine (Ident f) args) = do
case args of case args of
Args [_, Ident x, _] [] -> Args [_, Ident x, _] [] ->
-- assuming that no one will readmem into a local variable
if f == "$readmemh" || f == "$readmemb" if f == "$readmemh" || f == "$readmemb"
then lift $ tell $ Set.singleton x then collectLHSM $ LHSIdent x
else return () else return ()
_ -> return () _ -> return ()
return $ Subroutine (Ident f) args return $ Subroutine (Ident f) args
traverseStmtM stmt = do traverseStmtM stmt = do
-- only write down idents which aren't shadowed collectStmtLHSsM (collectNestedLHSsM collectLHSM) stmt
let regs = execWriter $ collectStmtLHSsM (collectNestedLHSsM lhsIdents) stmt
locals <- get
let globals = Set.difference regs locals
lift $ tell globals
return stmt return stmt
lhsIdents :: LHS -> Writer Idents () collectLHSM :: LHS -> ST ()
lhsIdents (LHSIdent x) = tell $ Set.singleton x collectLHSM lhs = do
lhsIdents _ = return () -- the collector recurses for us details <- lookupLHSM lhs
case details of
exprIdents :: Expr -> Writer Idents () Just (accesses, _, _) -> do
exprIdents (Ident x) = tell $ Set.singleton x let location = map accessName accesses
exprIdents _ = return () -- the collector recurses for us lift $ modify $ Set.insert location
Nothing -> return ()
...@@ -13,4 +13,31 @@ module top; ...@@ -13,4 +13,31 @@ module top;
$display("%b %b %b %b", x, y, z, f()); $display("%b %b %b %b", x, y, z, f());
$display("%b %b %b %b", x, y, z, f()); $display("%b %b %b %b", x, y, z, f());
end end
generate
begin : A
logic x;
begin : B
logic x;
end
begin : C
logic x;
end
assign x = B.x ^ C.x;
end
endgenerate
initial A.B.x = 0;
assign A.C.x = 1;
initial $display("%b %b %b %b", x, A.x, A.B.x, A.C.x);
logic t2l;
task t2;
input logic t2l;
top.t2l = t2l;
endtask
initial begin
$display("%b", t2l);
t2(1);
$display("%b", t2l);
end
endmodule endmodule
...@@ -17,4 +17,31 @@ module top; ...@@ -17,4 +17,31 @@ module top;
$display("%b %b %b %b", x, y, z, f(0)); $display("%b %b %b %b", x, y, z, f(0));
$display("%b %b %b %b", x, y, z, f(0)); $display("%b %b %b %b", x, y, z, f(0));
end end
generate
begin : A
wire x;
begin : B
reg x;
end
begin : C
wire x;
end
assign x = B.x ^ C.x;
end
endgenerate
initial A.B.x = 0;
assign A.C.x = 1;
initial $display("%b %b %b %b", x, A.x, A.B.x, A.C.x);
reg t2l;
task t2;
input reg t2l;
top.t2l = t2l;
endtask
initial begin
$display("%b", t2l);
t2(1);
$display("%b", t2l);
end
endmodule 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