diff --git a/Convert.hs b/Convert.hs new file mode 100644 index 0000000..086a66e --- /dev/null +++ b/Convert.hs @@ -0,0 +1,108 @@ +{- sv2v + - Author: Zachary Snow + - + - SystemVerilog to Verilog conversion + -} + +-- XXX: Note that, for now, we're going to shove the first few conversions all +-- into this same file, more or less. As patterns start becoming clearer, we +-- should be making helpers to make traversing the AST much easier. + +-- 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. + +module Convert (convert) where + +--import Data.List +import Text.Printf +import Data.Maybe +import qualified Data.Set as Set +import qualified Data.Map.Strict as Map + +import Language.SystemVerilog.AST + +data Possibility = AsWire | AsReg deriving (Eq, Ord) +type Possibilities = Set.Set Possibility +type TypeInfo = Map.Map String Possibilities +type ModulePorts = Map.Map String [Direction] + +-- TODO: It now seems like logic only becomes reg if it is assigned to in an +-- always block. If this is true, it obviously could dramatically simplify this +-- initial transformation. + +convert :: [Module] -> [Module] +convert modules = map (convertModule portsInfo) modules + where + portsInfo = Map.fromList $ map getPorts modules + getPorts :: Module -> (Identifier, [Direction]) + getPorts (Module name ports items) = + let portDirMap = Map.fromList $ mapMaybe getDirection items + in (name, map (portDirMap Map.!) ports) + where + getDirection :: ModuleItem -> Maybe (Identifier, Direction) + getDirection (PortDecl dir _ ident) = Just (ident, dir) + getDirection _ = Nothing + +convertModule :: ModulePorts -> Module -> Module +convertModule modules (Module name ports items) = + Module name ports (map (convertModuleItem info) items) + where + info = foldr (Map.unionWith Set.intersection) Map.empty (map (getTypeInfoModuleItem modules) items) + +getLHSIdentifiers :: LHS -> [Identifier] +getLHSIdentifiers (LHS vx ) = [vx] +getLHSIdentifiers (LHSBit vx _) = [vx] +getLHSIdentifiers (LHSRange vx _) = [vx] +getLHSIdentifiers (LHSConcat lhss) = concat $ map getLHSIdentifiers lhss + +onlyAsWire :: Possibilities +onlyAsWire = Set.fromList [AsWire] +onlyAsReg :: Possibilities +onlyAsReg = Set.fromList [AsReg] +asEither :: Possibilities +asEither = Set.fromList [AsWire, AsReg] + +getStmtLHSs :: Stmt -> [LHS] +getStmtLHSs (Block _ stmts) = concat $ map getStmtLHSs stmts +getStmtLHSs (Case e cases (Just stmt)) = (getStmtLHSs stmt) ++ (getStmtLHSs $ Case e cases Nothing) +getStmtLHSs (Case _ cases Nothing) = concat $ map getStmtLHSs $ map snd cases +getStmtLHSs (BlockingAssignment lhs _) = [lhs] +getStmtLHSs (NonBlockingAssignment lhs _) = [lhs] +getStmtLHSs (For _ _ _ stmt) = getStmtLHSs stmt +getStmtLHSs (If _ s1 s2) = (getStmtLHSs s1) ++ (getStmtLHSs s2) +getStmtLHSs (Null) = [] + +getTypeInfoModuleItem :: ModulePorts -> ModuleItem -> TypeInfo +getTypeInfoModuleItem _ (Assign lhs _) = + Map.fromList $ zip (getLHSIdentifiers lhs) (repeat onlyAsWire) +getTypeInfoModuleItem _ (Always _ stmt) = + Map.fromList $ zip idents (repeat onlyAsReg) + where + lhss = getStmtLHSs stmt + idents = concat $ map getLHSIdentifiers lhss +--getTypeInfoModuleItem modules (Instance name _ _ bindings) = +-- case Map.lookup name modules of +-- Nothing -> Map.empty +-- Just dirs -> +-- +-- where +-- isDirect :: PortBinding -> Bool +-- isDirect x = snd x == Nothing +-- directs = map fst $ filter isDirect bindings +--getTypeInfoModuleItem _ (Function (Maybe FuncRet) Identifier [(Bool, BlockItemDeclaration)] Stmt +--getTypeInfoModuleItem _ (Generate [GenItem] +getTypeInfoModuleItem _ _ = Map.empty + +convertModuleItem :: TypeInfo -> ModuleItem -> ModuleItem +convertModuleItem info (LocalNet (Logic mr) ident val) = + LocalNet (t mr) ident val + where + t = case Map.lookup ident info of + Nothing -> Wire + Just possibilities -> + if Set.member AsWire possibilities then Wire + else if Set.member AsReg possibilities then Reg + else error $ printf "item %s has not possibilities" ident +convertModuleItem _ other = other diff --git a/Language/SystemVerilog/AST.hs b/Language/SystemVerilog/AST.hs index 678780b..953012f 100644 --- a/Language/SystemVerilog/AST.hs +++ b/Language/SystemVerilog/AST.hs @@ -65,13 +65,15 @@ instance Show Direction where show Inout = "inout" data Type - = Reg (Maybe Range) - | Wire (Maybe Range) + = Reg (Maybe Range) + | Wire (Maybe Range) + | Logic (Maybe Range) deriving Eq instance Show Type where - show (Reg r) = "reg " ++ (showRange r) - show (Wire r) = "wire " ++ (showRange r) + show (Reg r) = "reg " ++ (showRange r) + show (Wire r) = "wire " ++ (showRange r) + show (Logic r) = "logic " ++ (showRange r) data ModuleItem = Comment String diff --git a/Language/SystemVerilog/Parser/Lex.x b/Language/SystemVerilog/Parser/Lex.x index 860eb59..55d4f39 100644 --- a/Language/SystemVerilog/Parser/Lex.x +++ b/Language/SystemVerilog/Parser/Lex.x @@ -78,6 +78,7 @@ tokens :- "input" { tok KW_input } "integer" { tok KW_integer } "localparam" { tok KW_localparam } + "logic" { tok KW_logic } "module" { tok KW_module } "negedge" { tok KW_negedge } "or" { tok KW_or } diff --git a/Language/SystemVerilog/Parser/Parse.y b/Language/SystemVerilog/Parser/Parse.y index 32f70ce..a9b564c 100644 --- a/Language/SystemVerilog/Parser/Parse.y +++ b/Language/SystemVerilog/Parser/Parse.y @@ -39,6 +39,7 @@ import Language.SystemVerilog.Parser.Tokens "input" { Token KW_input _ _ } "integer" { Token KW_integer _ _ } "localparam" { Token KW_localparam _ _ } +"logic" { Token KW_logic _ _ } "module" { Token KW_module _ _ } "negedge" { Token KW_negedge _ _ } "or" { Token KW_or _ _ } @@ -201,10 +202,12 @@ PortDeclsFollow :: { [ModuleItem] } PortDecl(delim) :: { [ModuleItem] } : "inout" opt(NetType) opt(Range) Identifiers delim { portDeclToModuleItems Inout $2 $3 (zip $4 (repeat Nothing)) } | "input" opt(NetType) opt(Range) Identifiers delim { portDeclToModuleItems Input $2 $3 (zip $4 (repeat Nothing)) } - | "output" opt(NetType) opt(Range) Identifiers delim { portDeclToModuleItems Output $2 $3 (zip $4 (repeat Nothing)) } - | "output" "reg" opt(Range) VariablePortIdentifiers delim { portDeclToModuleItems Output (Just Reg) $3 $4 } -NetType - : "wire" { Wire } + | "output" "wire" opt(Range) Identifiers delim { portDeclToModuleItems Output (Just Wire ) $3 (zip $4 (repeat Nothing)) } + | "output" "reg" opt(Range) VariablePortIdentifiers delim { portDeclToModuleItems Output (Just Reg ) $3 $4 } + | "output" "logic" opt(Range) VariablePortIdentifiers delim { portDeclToModuleItems Output (Just Logic) $3 $4 } +NetType :: { Maybe Range -> Type } + : "wire" { Wire } + | "logic" { Logic } VariablePortIdentifiers :: { [(Identifier, Maybe Expr)] } : VariablePortIdentifier { [$1] } | VariablePortIdentifiers "," VariablePortIdentifier { $1 ++ [$3] } @@ -218,8 +221,9 @@ ModuleItems :: { [ModuleItem] } ModuleItem :: { [ModuleItem] } : PortDecl(";") { $1 } - | "reg" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Reg $2) $3 } - | "wire" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Wire $2) $3 } + | "reg" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Reg $2) $3 } + | "wire" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Wire $2) $3 } + | "logic" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Logic $2) $3 } | ParameterDeclaration { map MIParameter $1 } | LocalparamDeclaration { map MILocalparam $1 } | IntegerDeclaration { map MIIntegerV $1 } diff --git a/sv2v.cabal b/sv2v.cabal index 7c40636..4b626e0 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -49,7 +49,8 @@ executable sv2v happy >= 1 && < 2 build-depends: array, - base + base, + containers other-modules: Language.SystemVerilog Language.SystemVerilog.AST @@ -58,6 +59,7 @@ executable sv2v Language.SystemVerilog.Parser.Parse Language.SystemVerilog.Parser.Preprocess Language.SystemVerilog.Parser.Tokens + Convert ghc-options: -O3 -threaded diff --git a/sv2v.hs b/sv2v.hs index caaa5d8..ace3993 100644 --- a/sv2v.hs +++ b/sv2v.hs @@ -10,12 +10,14 @@ import System.Environment import Language.SystemVerilog.Parser +import Convert (convert) + main :: IO () main = do [filePath] <- getArgs content <- readFile filePath let ast = parseFile [] filePath content - let res = Right ast + let res = Right (convert ast) case res of Left _ -> do --hPrint stderr err