diff --git a/Convert.hs b/Convert.hs index baf7275..4e702c2 100644 --- a/Convert.hs +++ b/Convert.hs @@ -4,106 +4,28 @@ - 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] +import qualified Convert.AlwaysKW +import qualified Convert.Logic --- 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. +type Phase = [Module] -> [Module] -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 +phases :: [Phase] +phases = + [ Convert.AlwaysKW.convert + , Convert.Logic.convert + ] -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) +run :: Phase +run = foldr (.) id phases -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 (Timing _ s) = getStmtLHSs s -getStmtLHSs (Null) = [] - -getTypeInfoModuleItem :: ModulePorts -> ModuleItem -> TypeInfo -getTypeInfoModuleItem _ (Assign lhs _) = - Map.fromList $ zip (getLHSIdentifiers lhs) (repeat onlyAsWire) -getTypeInfoModuleItem _ (AlwaysC _ 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 +convert :: Phase +convert modules = + let modules' = run modules + in + if modules == modules' + then modules + else convert modules' diff --git a/Convert/AlwaysKW.hs b/Convert/AlwaysKW.hs new file mode 100644 index 0000000..055f985 --- /dev/null +++ b/Convert/AlwaysKW.hs @@ -0,0 +1,25 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `always_comb` and `always_ff` + -} + +module Convert.AlwaysKW (convert) where + +import Convert.Template.ModuleItem (moduleItemConverter) + +import Language.SystemVerilog.AST + +convert :: [Module] -> [Module] +convert = moduleItemConverter convertModuleItem + +-- Conversions: +-- `always_comb` -> `always @*` +-- `always_ff` -> `always` + +convertModuleItem :: ModuleItem -> ModuleItem +convertModuleItem (AlwaysC AlwaysComb stmt) = + AlwaysC Always $ Timing SenseStar stmt +convertModuleItem (AlwaysC AlwaysFF stmt) = + AlwaysC Always stmt +convertModuleItem other = other diff --git a/Convert/Logic.hs b/Convert/Logic.hs new file mode 100644 index 0000000..206ea05 --- /dev/null +++ b/Convert/Logic.hs @@ -0,0 +1,61 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `logic` + -} + +-- 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 + +import qualified Data.Set as Set + +import Language.SystemVerilog.AST + +type RegIdents = Set.Set String + +convert :: [Module] -> [Module] +convert modules = map convertModule modules + +convertModule :: Module -> Module +convertModule (Module name ports items) = + Module name ports $ map (convertModuleItem idents) items + where + idents = Set.unions $ map getRegIdents items + +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 (Timing _ s) = getStmtLHSs s +getStmtLHSs (Null) = [] + +getLHSIdents :: LHS -> [Identifier] +getLHSIdents (LHS vx ) = [vx] +getLHSIdents (LHSBit vx _) = [vx] +getLHSIdents (LHSRange vx _) = [vx] +getLHSIdents (LHSConcat lhss) = concat $ map getLHSIdents lhss + +getRegIdents :: ModuleItem -> RegIdents +getRegIdents (AlwaysC _ stmt) = + Set.fromList idents + where + lhss = getStmtLHSs stmt + idents = concat $ map getLHSIdents lhss +getRegIdents _ = Set.empty + +convertModuleItem :: RegIdents -> ModuleItem -> ModuleItem +convertModuleItem idents (LocalNet (Logic mr) ident val) = + LocalNet (t mr) ident val + where + t = if Set.member ident idents then Reg else Wire +convertModuleItem _ other = other diff --git a/Convert/Template/ModuleItem.hs b/Convert/Template/ModuleItem.hs new file mode 100644 index 0000000..0594b9f --- /dev/null +++ b/Convert/Template/ModuleItem.hs @@ -0,0 +1,44 @@ +{- sv2v + - Author: Zachary Snow + - + - Template converter for ModuleItem transformations + - + - Also has coverage for ModuleItems inside of generate blocks + -} + +module Convert.Template.ModuleItem (moduleItemConverter) where + +import Data.Maybe +import Language.SystemVerilog.AST + +type Converter = ModuleItem -> ModuleItem + +moduleItemConverter :: Converter -> ([Module] -> [Module]) +moduleItemConverter f = convert f + +convert :: Converter -> [Module] -> [Module] +convert f modules = map (convertModule f) modules + +convertModule :: Converter -> Module -> Module +convertModule f (Module name ports items) = + Module name ports $ map (convertModuleItem f) items + +convertModuleItem :: Converter -> ModuleItem -> ModuleItem +convertModuleItem f (Generate items) = f $ Generate $ map (convertGenItem f) items +convertModuleItem f other = f other + +convertGenItem :: Converter -> GenItem -> GenItem +convertGenItem f item = convertGenItem' item + where + convertGenItem' :: GenItem -> GenItem + convertGenItem' (GenBlock x items) = GenBlock x $ map convertGenItem' items + convertGenItem' (GenFor a b c d items) = GenFor a b c d $ map convertGenItem' items + convertGenItem' (GenIf e i1 i2) = GenIf e (convertGenItem' i1) (convertGenItem' i2) + convertGenItem' (GenNull) = GenNull + convertGenItem' (GenModuleItem moduleItem) = GenModuleItem $ f moduleItem + convertGenItem' (GenCase e cases def) = GenCase e cases' def' + where + cases' = zip (map fst cases) (map (convertGenItem' . snd) cases) + def' = if def == Nothing + then Nothing + else Just $ convertGenItem' $ fromJust def diff --git a/sv2v.cabal b/sv2v.cabal index 4b626e0..81c180c 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -60,6 +60,9 @@ executable sv2v Language.SystemVerilog.Parser.Preprocess Language.SystemVerilog.Parser.Tokens Convert + Convert.AlwaysKW + Convert.Logic + Convert.Template.ModuleItem ghc-options: -O3 -threaded