Commit 88579c6d by Zachary Snow

logic conversion fixes produced reg-to-output bindings

- generally cleaned up and documented the Logic conversion
- made exprToLHS a shared helper function, now uses Maybe
- ported existing local exprToLHS helpers to the new one
parent 55a54437
...@@ -249,7 +249,7 @@ inlineInterface (ports, items) (instanceName, instancePorts) = ...@@ -249,7 +249,7 @@ inlineInterface (ports, items) (instanceName, instancePorts) =
portBindingItem (ident, Just expr) = portBindingItem (ident, Just expr) =
Just $ if declDirs Map.! ident == Input Just $ if declDirs Map.! ident == Input
then Assign Nothing (LHSIdent ident) expr then Assign Nothing (LHSIdent ident) expr
else Assign Nothing (exprToLHS expr) (Ident ident) else Assign Nothing (toLHS expr) (Ident ident)
portBindingItem (_, Nothing) = Nothing portBindingItem (_, Nothing) = Nothing
declDirs = execWriter $ declDirs = execWriter $
...@@ -261,12 +261,9 @@ inlineInterface (ports, items) (instanceName, instancePorts) = ...@@ -261,12 +261,9 @@ inlineInterface (ports, items) (instanceName, instancePorts) =
else return () else return ()
collectDeclDir _ = return () collectDeclDir _ = return ()
exprToLHS :: Expr -> LHS toLHS :: Expr -> LHS
exprToLHS (Ident x ) = LHSIdent x toLHS expr =
exprToLHS (Bit l e ) = LHSBit (exprToLHS l) e case exprToLHS expr of
exprToLHS (Range l m r) = LHSRange (exprToLHS l) m r Just lhs -> lhs
exprToLHS (Dot l x ) = LHSDot (exprToLHS l) x Nothing -> error $ "trying to bind an interface output to " ++
exprToLHS (Concat ls ) = LHSConcat $ map exprToLHS ls show expr ++ " but that can't be an LHS"
exprToLHS other =
error $ "trying to bind (part of) an interface output to " ++
show other ++ " but that can't be an LHS"
{- sv2v {- sv2v
- Author: Zachary Snow <zach@zachjs.com> - Author: Zachary Snow <zach@zachjs.com>
- -
- Conversion for `logic` - Conversion from `logic` to `wire` or `reg`
-
- We convert a module-level logic to a reg if it is assigned to in an always or
- initial block. Other module-level logics become wires. All other logics
- (i.e., in a function) become regs.
-
- The struct conversion and Verilog-2005's lack of permissive net vs. variable
- resolution leads to some interesting special cases for this conversion, as
- parts of a struct may be used as a variable, while other parts may be used as
- a net.
-
- 1) If a reg, or a portion thereof, is assigned by a continuous assignment
- item, then that assignment is converted to a procedural assignment within an
- added `always_comb` item.
-
- 2) If a reg, or a portion thereof, is bound to an output port, then that
- binding is replaced by a temporary net declaration, and a procedural
- assignment is added which updates the reg to the value of the new net.
-} -}
-- Regarding `logic` conversion: The SystemVerilog grammar has the concept of a
-- `data_declaration`, which seems to cover things much more generally. While
-- obviously `logic` can appear as module items or ports, they can also be
-- function arguments, for example.
-- It seems like logic only becomes reg if it is assigned to in an always block.
module Convert.Logic (convert) where module Convert.Logic (convert) where
import Control.Monad.Writer import Control.Monad.Writer
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
type Idents = Set.Set Identifier type Idents = Set.Set Identifier
type Ports = Map.Map (Identifier, Identifier) Direction
convert :: AST -> AST convert :: AST -> AST
convert = traverseDescriptions convertDescription convert ast =
traverseDescriptions (convertDescription ports) ast
where
ports = execWriter $ collectDescriptionsM collectPortsM ast
collectPortsM :: Description -> Writer Ports ()
collectPortsM (orig @ (Part _ _ _ name portNames _)) =
collectModuleItemsM collectPortDirsM orig
where
collectPortDirsM :: ModuleItem -> Writer Ports ()
collectPortDirsM (MIDecl (Variable dir _ ident _ _)) =
if dir == Local then
return ()
else if elem ident portNames then
tell $ Map.singleton (name, ident) dir
else
error $ "encountered decl with a dir that isn't a port: "
++ show (dir, ident)
collectPortDirsM _ = return ()
collectPortsM _ = return ()
convertDescription :: Description -> Description convertDescription :: Ports -> Description -> Description
convertDescription orig = convertDescription ports orig =
if shouldConvert if shouldConvert
then traverseModuleItems conversion orig then traverseModuleItems conversion orig
else orig else orig
...@@ -38,12 +68,47 @@ convertDescription orig = ...@@ -38,12 +68,47 @@ convertDescription orig =
conversion = traverseDecls convertDecl . convertModuleItem conversion = traverseDecls convertDecl . convertModuleItem
idents = execWriter (collectModuleItemsM regIdents orig) idents = execWriter (collectModuleItemsM regIdents orig)
convertModuleItem :: ModuleItem -> ModuleItem convertModuleItem :: ModuleItem -> ModuleItem
-- rewrite bad continuous assignments to use procedural assignments
convertModuleItem (Assign Nothing lhs expr) = convertModuleItem (Assign Nothing lhs expr) =
if Set.null $ Set.intersection usedIdents idents if Set.disjoint usedIdents idents
then Assign Nothing lhs expr then Assign Nothing lhs expr
else AlwaysC AlwaysComb $ AsgnBlk AsgnOpEq lhs expr else AlwaysC AlwaysComb $ AsgnBlk AsgnOpEq lhs expr
where where
usedIdents = execWriter $ collectNestedLHSsM lhsIdents lhs usedIdents = execWriter $ collectNestedLHSsM lhsIdents lhs
-- rewrite port bindings to use temporary nets where necessary
convertModuleItem (Instance moduleName params instanceName rs bindings) =
if null newItems
then Instance moduleName params instanceName rs bindings
else Generate $ map GenModuleItem $
(MIPackageItem $ Comment "rewrote reg-to-output bindings") :
newItems ++
[Instance moduleName params instanceName rs bindings']
where
(bindings', newItemsList) = unzip $ map fixBinding bindings
newItems = concat newItemsList
fixBinding :: PortBinding -> (PortBinding, [ModuleItem])
fixBinding (portName, Just expr) =
if portDir /= Just Output || Set.disjoint usedIdents idents
then ((portName, Just expr), [])
else ((portName, Just tmpExpr), items)
where
portDir = Map.lookup (moduleName, portName) ports
usedIdents = execWriter $
collectNestedExprsM exprIdents expr
tmp = "sv2v_tmp_" ++ instanceName ++ "_" ++ portName
tmpExpr = Ident tmp
t = Net TWire [(Bits $ Right expr, Number "0")]
items =
[ MIDecl $ Variable Local t tmp [] Nothing
, AlwaysC AlwaysComb $ AsgnBlk AsgnOpEq lhs tmpExpr]
lhs = case exprToLHS expr of
Just l -> l
Nothing ->
error $ "bad non-lhs, non-net expr "
++ show expr ++ " connected to output port "
++ portName ++ " of " ++ instanceName
fixBinding other = (other, [])
-- rewrite variable declarations to have the correct type
convertModuleItem (MIDecl (Variable dir (IntegerVector TLogic sg mr) ident a me)) = convertModuleItem (MIDecl (Variable dir (IntegerVector TLogic sg mr) ident a me)) =
MIDecl $ Variable dir (t mr) ident a me MIDecl $ Variable dir (t mr) ident a me
where where
...@@ -74,5 +139,9 @@ regIdents (Initial stmt) = ...@@ -74,5 +139,9 @@ regIdents (Initial stmt) =
regIdents _ = return () regIdents _ = return ()
lhsIdents :: LHS -> Writer Idents () lhsIdents :: LHS -> Writer Idents ()
lhsIdents (LHSIdent vx ) = tell $ Set.singleton vx lhsIdents (LHSIdent x) = tell $ Set.singleton x
lhsIdents _ = return () -- the collector recurses for us lhsIdents _ = return () -- the collector recurses for us
exprIdents :: Expr -> Writer Idents ()
exprIdents (Ident x) = tell $ Set.singleton x
exprIdents _ = return () -- the collector recurses for us
...@@ -466,9 +466,12 @@ exprMapperHelpers exprMapper = ...@@ -466,9 +466,12 @@ exprMapperHelpers exprMapper =
declMapper (Localparam t x e) = declMapper (Localparam t x e) =
exprMapper e >>= return . Localparam t x exprMapper e >>= return . Localparam t x
declMapper (Variable d t x a me) = do declMapper (Variable d t x a me) = do
let (tf, rs) = typeRanges t
rs' <- mapM rangeMapper rs
let t' = tf rs'
a' <- mapM rangeMapper a a' <- mapM rangeMapper a
me' <- maybeExprMapper me me' <- maybeExprMapper me
return $ Variable d t x a' me' return $ Variable d t' x a' me'
traverseExprsM' :: Monad m => TFStrategy -> MapperM m Expr -> MapperM m ModuleItem traverseExprsM' :: Monad m => TFStrategy -> MapperM m Expr -> MapperM m ModuleItem
traverseExprsM' strat exprMapper = moduleItemMapper traverseExprsM' strat exprMapper = moduleItemMapper
......
...@@ -25,6 +25,7 @@ module Language.SystemVerilog.AST ...@@ -25,6 +25,7 @@ module Language.SystemVerilog.AST
, module Op , module Op
, module Stmt , module Stmt
, module Type , module Type
, exprToLHS
) where ) where
import Language.SystemVerilog.AST.Attr as Attr import Language.SystemVerilog.AST.Attr as Attr
...@@ -39,3 +40,19 @@ import Language.SystemVerilog.AST.Stmt as Stmt ...@@ -39,3 +40,19 @@ import Language.SystemVerilog.AST.Stmt as Stmt
import Language.SystemVerilog.AST.Type as Type import Language.SystemVerilog.AST.Type as Type
type AST = [Description] type AST = [Description]
exprToLHS :: Expr -> Maybe LHS
exprToLHS (Ident x ) = Just $ LHSIdent x
exprToLHS (Bit l e ) = do
l' <- exprToLHS l
Just $ LHSBit l' e
exprToLHS (Range l m r) = do
l' <- exprToLHS l
Just $ LHSRange l' m r
exprToLHS (Dot l x ) = do
l' <- exprToLHS l
Just $ LHSDot l' x
exprToLHS (Concat ls ) = do
ls' <- mapM exprToLHS ls
Just $ LHSConcat ls'
exprToLHS _ = Nothing
...@@ -533,7 +533,7 @@ NOutputGate :: { (Maybe Identifier, [LHS], Expr) } ...@@ -533,7 +533,7 @@ NOutputGate :: { (Maybe Identifier, [LHS], Expr) }
: opt(Identifier) "(" NOutputGateItems { ($1, fst $3, snd $3) } : opt(Identifier) "(" NOutputGateItems { ($1, fst $3, snd $3) }
NOutputGateItems :: { ([LHS], Expr) } NOutputGateItems :: { ([LHS], Expr) }
: Expr ")" { ([], $1) } : Expr ")" { ([], $1) }
| Expr "," NOutputGateItems { (fst $3 ++ [exprToLHS $1], snd $3) } | Expr "," NOutputGateItems { (fst $3 ++ [toLHS $1], snd $3) }
NInputGateKW :: { NInputGateKW } NInputGateKW :: { NInputGateKW }
: "and" { GateAnd } : "and" { GateAnd }
...@@ -938,12 +938,10 @@ combineTags (Just a) (Just b) = ...@@ -938,12 +938,10 @@ combineTags (Just a) (Just b) =
combineTags Nothing other = other combineTags Nothing other = other
combineTags other _ = other combineTags other _ = other
exprToLHS :: Expr -> LHS toLHS :: Expr -> LHS
exprToLHS (Ident x ) = LHSIdent x toLHS expr =
exprToLHS (Bit e b ) = LHSBit (exprToLHS e) b case exprToLHS expr of
exprToLHS (Range e m r) = LHSRange (exprToLHS e) m r Just lhs -> lhs
exprToLHS (Dot e x ) = LHSDot (exprToLHS e) x Nothing -> error $ "Parse error: cannot convert expression to LHS: "
exprToLHS (Concat es ) = LHSConcat (map exprToLHS es) ++ show expr
exprToLHS other =
error $ "Parse error: cannot convert expression to LHS: " ++ show other
} }
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