diff --git a/Convert.hs b/Convert.hs index 4e702c2..149c3c6 100644 --- a/Convert.hs +++ b/Convert.hs @@ -10,22 +10,24 @@ import Language.SystemVerilog.AST import qualified Convert.AlwaysKW import qualified Convert.Logic +import qualified Convert.Typedef -type Phase = [Module] -> [Module] +type Phase = AST -> AST phases :: [Phase] phases = [ Convert.AlwaysKW.convert , Convert.Logic.convert + , Convert.Typedef.convert ] run :: Phase run = foldr (.) id phases convert :: Phase -convert modules = - let modules' = run modules +convert descriptions = + let descriptions' = run descriptions in - if modules == modules' - then modules - else convert modules' + if descriptions == descriptions' + then descriptions + else convert descriptions' diff --git a/Convert/AlwaysKW.hs b/Convert/AlwaysKW.hs index 055f985..bb16eab 100644 --- a/Convert/AlwaysKW.hs +++ b/Convert/AlwaysKW.hs @@ -10,7 +10,7 @@ import Convert.Template.ModuleItem (moduleItemConverter) import Language.SystemVerilog.AST -convert :: [Module] -> [Module] +convert :: AST -> AST convert = moduleItemConverter convertModuleItem -- Conversions: diff --git a/Convert/Logic.hs b/Convert/Logic.hs index 206ea05..cd8bdcb 100644 --- a/Convert/Logic.hs +++ b/Convert/Logic.hs @@ -19,14 +19,15 @@ import Language.SystemVerilog.AST type RegIdents = Set.Set String -convert :: [Module] -> [Module] -convert modules = map convertModule modules +convert :: AST -> AST +convert descriptions = map convertDescription descriptions -convertModule :: Module -> Module -convertModule (Module name ports items) = +convertDescription :: Description -> Description +convertDescription (Module name ports items) = Module name ports $ map (convertModuleItem idents) items where idents = Set.unions $ map getRegIdents items +convertDescription other = other getStmtLHSs :: Stmt -> [LHS] getStmtLHSs (Block _ stmts) = concat $ map getStmtLHSs stmts diff --git a/Convert/Template/ModuleItem.hs b/Convert/Template/ModuleItem.hs index 0594b9f..857c7d4 100644 --- a/Convert/Template/ModuleItem.hs +++ b/Convert/Template/ModuleItem.hs @@ -13,15 +13,16 @@ import Language.SystemVerilog.AST type Converter = ModuleItem -> ModuleItem -moduleItemConverter :: Converter -> ([Module] -> [Module]) +moduleItemConverter :: Converter -> (AST -> AST) moduleItemConverter f = convert f -convert :: Converter -> [Module] -> [Module] -convert f modules = map (convertModule f) modules +convert :: Converter -> AST -> AST +convert f modules = map (convertDescription f) modules -convertModule :: Converter -> Module -> Module -convertModule f (Module name ports items) = +convertDescription :: Converter -> Description -> Description +convertDescription f (Module name ports items) = Module name ports $ map (convertModuleItem f) items +convertDescription _ (Typedef a b) = Typedef a b convertModuleItem :: Converter -> ModuleItem -> ModuleItem convertModuleItem f (Generate items) = f $ Generate $ map (convertGenItem f) items diff --git a/Convert/Typedef.hs b/Convert/Typedef.hs new file mode 100644 index 0000000..95bac01 --- /dev/null +++ b/Convert/Typedef.hs @@ -0,0 +1,56 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `typedef` + -} + +-- TODO: Right now we only support typedefs for module data items. Function +-- parameters, block items, etc., probably support typedefs, too. + +module Convert.Typedef (convert) where + +import Data.Maybe +import qualified Data.Map as Map + +import Language.SystemVerilog.AST + +type Types = Map.Map Identifier Type + +convert :: AST -> AST +convert descriptions = + filter (not . isTypedef) $ map (convertDescription types) descriptions + where + types = Map.fromList $ mapMaybe getTypedef descriptions + getTypedef :: Description -> Maybe (Identifier, Type) + getTypedef (Typedef a b) = Just (b, a) + getTypedef _ = Nothing + +isTypedef :: Description -> Bool +isTypedef (Typedef _ _) = True +isTypedef _ = False + +convertDescription :: Types -> Description -> Description +convertDescription types (Module name ports items) = + Module name ports $ map (convertModuleItem types) items +convertDescription _ other = other + +resolveType :: Types -> Type -> Type +resolveType _ (Reg mr) = Reg mr +resolveType _ (Wire mr) = Wire mr +resolveType _ (Logic mr) = Logic mr +resolveType types (Alias st mr1) = + case resolveType types $ types Map.! st of + (Reg mr2) -> Reg $ combineRanges mr1 mr2 + (Wire mr2) -> Wire $ combineRanges mr1 mr2 + (Logic mr2) -> Logic $ combineRanges mr1 mr2 + (Alias _ _) -> error $ "resolveType invariant failed on " ++ st + where + combineRanges :: Maybe Range -> Maybe Range -> Maybe Range + combineRanges Nothing other = other + combineRanges other Nothing = other + combineRanges _ _ = error $ "alias " ++ st ++ " leads to 2-D vectorized type" + +convertModuleItem :: Types -> ModuleItem -> ModuleItem +convertModuleItem types (LocalNet t ident val) = + LocalNet (resolveType types t) ident val +convertModuleItem _ other = other diff --git a/Language/SystemVerilog/AST.hs b/Language/SystemVerilog/AST.hs index 767b215..5b7381a 100644 --- a/Language/SystemVerilog/AST.hs +++ b/Language/SystemVerilog/AST.hs @@ -1,6 +1,6 @@ module Language.SystemVerilog.AST ( Identifier - , Module (..) + , Description(..) , ModuleItem (..) , Direction (..) , Type (..) @@ -16,6 +16,7 @@ module Language.SystemVerilog.AST , IntegerV (..) , GenItem (..) , AlwaysKW (..) + , AST , PortBinding , Case , Range @@ -38,12 +39,15 @@ type Identifier = String -- basing invariant checks. I want to avoid making a full type-checker though, -- as we should only be given valid SystemVerilog input files. -data Module +type AST = [Description] + +data Description = Module Identifier [Identifier] [ModuleItem] + | Typedef Type Identifier deriving Eq -instance Show Module where - showList modules _ = intercalate "\n" $ map show modules +instance Show Description where + showList descriptions _ = intercalate "\n" $ map show descriptions show (Module name ports items) = unlines [ "module " ++ name ++ portsStr ++ ";" , indent $ unlines' $ map show items @@ -53,6 +57,7 @@ instance Show Module where if null ports then "" else indentedParenList ports + show (Typedef t x) = printf "typedef %s %s;" (show t) x data Direction = Input @@ -69,12 +74,14 @@ data Type = Reg (Maybe Range) | Wire (Maybe Range) | Logic (Maybe Range) + | Alias String (Maybe Range) deriving Eq instance Show Type where show (Reg r) = "reg " ++ (showRange r) show (Wire r) = "wire " ++ (showRange r) show (Logic r) = "logic " ++ (showRange r) + show (Alias t r) = t ++ " " ++ (showRange r) data ModuleItem = Comment String diff --git a/Language/SystemVerilog/Parser.hs b/Language/SystemVerilog/Parser.hs index d4f2719..b6dc7f5 100644 --- a/Language/SystemVerilog/Parser.hs +++ b/Language/SystemVerilog/Parser.hs @@ -10,8 +10,8 @@ import Language.SystemVerilog.Parser.Preprocess import Language.SystemVerilog.Parser.Tokens -- | Parses a file given a table of predefined macros, the file name, and the file contents. -parseFile :: [(String, String)] -> FilePath -> String -> [Module] -parseFile env file content = modules tokens +parseFile :: [(String, String)] -> FilePath -> String -> AST +parseFile env file content = descriptions tokens where tokens = map relocate $ alexScanTokens $ preprocess env file content relocate :: Token -> Token diff --git a/Language/SystemVerilog/Parser/Lex.x b/Language/SystemVerilog/Parser/Lex.x index 3320bb9..c16330e 100644 --- a/Language/SystemVerilog/Parser/Lex.x +++ b/Language/SystemVerilog/Parser/Lex.x @@ -82,6 +82,7 @@ tokens :- "parameter" { tok KW_parameter } "posedge" { tok KW_posedge } "reg" { tok KW_reg } + "typedef" { tok KW_typedef } "wire" { tok KW_wire } @simpleIdentifier { tok Id_simple } diff --git a/Language/SystemVerilog/Parser/Parse.y b/Language/SystemVerilog/Parser/Parse.y index 2aeef25..a5b5672 100644 --- a/Language/SystemVerilog/Parser/Parse.y +++ b/Language/SystemVerilog/Parser/Parse.y @@ -1,5 +1,5 @@ { -module Language.SystemVerilog.Parser.Parse (modules) where +module Language.SystemVerilog.Parser.Parse (descriptions) where import Data.Bits import Data.List @@ -9,7 +9,7 @@ import Language.SystemVerilog.AST import Language.SystemVerilog.Parser.Tokens } -%name modules +%name descriptions %tokentype { Token } %error { parseError } @@ -50,6 +50,7 @@ import Language.SystemVerilog.Parser.Tokens "parameter" { Token KW_parameter _ _ } "posedge" { Token KW_posedge _ _ } "reg" { Token KW_reg _ _ } +"typedef" { Token KW_typedef _ _ } "wire" { Token KW_wire _ _ } simpleIdentifier { Token Id_simple _ _ } @@ -164,14 +165,27 @@ opt(p) :: { Maybe a } : p { Just $1 } | { Nothing } -Modules :: { [Module] } +Descriptions :: { [Description] } : {- empty -} { [] } - | Modules Module { $1 ++ [$2] } + | Descriptions Description { $1 ++ [$2] } -Module :: { Module } - : "module" Identifier Params ";" ModuleItems "endmodule" opt(";") { Module $2 [] ($3 ++ $5) } - | "module" Identifier Params PortNames ";" ModuleItems "endmodule" opt(";") { Module $2 $4 ($3 ++ $6) } - | "module" Identifier Params PortDecls ";" ModuleItems "endmodule" opt(";") { Module $2 (getPortNames $4) ($3 ++ $4 ++ $6) } +Description :: { Description } + : Module opt(";") { $1 } + | Typedef opt(";") { $1 } + +Typedef :: { Description } + : "typedef" Type Identifier ";" { Typedef $2 $3 } + +Type :: { Type } + : "wire" opt(Range) { Wire $2 } + | "reg" opt(Range) { Reg $2 } + | "logic" opt(Range) { Logic $2 } + | Identifier opt(Range) { Alias $1 $2 } + +Module :: { Description } + : "module" Identifier Params ";" ModuleItems "endmodule" { Module $2 [] ($3 ++ $5) } + | "module" Identifier Params PortNames ";" ModuleItems "endmodule" { Module $2 $4 ($3 ++ $6) } + | "module" Identifier Params PortDecls ";" ModuleItems "endmodule" { Module $2 (getPortNames $4) ($3 ++ $4 ++ $6) } Params :: { [ModuleItem] } : {- empty -} { [] } @@ -224,14 +238,17 @@ 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 } - | "logic" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Logic $2) $3 } + -- TODO: Allowing Ranges on aliases creates conflicts + | Identifier VariableIdentifiers ";" { map (uncurry $ LocalNet (Alias $1 Nothing)) $2 } + | "wire" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Wire $2) $3 } + | "reg" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Reg $2) $3 } + | "logic" opt(Range) VariableIdentifiers ";" { map (uncurry $ LocalNet $ Logic $2) $3 } | ParameterDeclaration { map MIParameter $1 } | LocalparamDeclaration { map MILocalparam $1 } | IntegerDeclaration { map MIIntegerV $1 } | "assign" LHS "=" Expr ";" { [Assign $2 $4] } | AlwaysKW Stmt { [AlwaysC $1 $2] } + | Identifier ModuleInstantiations ";" { map (uncurry $ Instance $1 []) $2 } | Identifier ParameterBindings ModuleInstantiations ";" { map (uncurry $ Instance $1 $2) $3 } | "function" opt(RangeOrType) Identifier FunctionItems Stmt "endfunction" { [Function $2 $3 $4 $5] } | "genvar" Identifiers ";" { map Genvar $2 } @@ -337,8 +354,7 @@ Binding :: { (Identifier, Maybe Expr) } | Expr { ("", Just $1) } ParameterBindings :: { [(Identifier, Maybe Expr)] } - : {- empty -} { [] } - | "#" "(" BindingsNonEmpty ")" { $3 } + : "#" "(" BindingsNonEmpty ")" { $3 } Stmts :: { [Stmt] } : {- empty -} { [] } diff --git a/sv2v.cabal b/sv2v.cabal index 81c180c..058b87a 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -62,6 +62,7 @@ executable sv2v Convert Convert.AlwaysKW Convert.Logic + Convert.Typedef Convert.Template.ModuleItem ghc-options: -O3