mirror of https://github.com/zachjs/sv2v.git
always construct conversion; more modular conversion approach
This commit is contained in:
parent
35a75cc46f
commit
659461b8d2
112
Convert.hs
112
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'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- 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
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- 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
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue