preliminary struct conversion; return conversion

This commit is contained in:
Zachary Snow 2019-03-06 00:51:09 -05:00
parent 4d3669d356
commit 9699f5bf16
7 changed files with 351 additions and 35 deletions

View File

@ -15,8 +15,10 @@ import qualified Convert.CaseKW
import qualified Convert.Enum
import qualified Convert.Logic
import qualified Convert.PackedArray
import qualified Convert.Return
import qualified Convert.SplitPortDecl
import qualified Convert.StarPort
import qualified Convert.Struct
import qualified Convert.Typedef
import qualified Convert.Unique
@ -28,6 +30,8 @@ phases YOSYS =
, Convert.Enum.convert
, Convert.PackedArray.convert
, Convert.StarPort.convert
, Convert.Struct.convert
, Convert.Return.convert
, Convert.Typedef.convert
, Convert.Unique.convert
]

View File

@ -29,7 +29,6 @@
module Convert.PackedArray (convert) where
import Text.Read (readMaybe)
import Control.Monad.State
import Data.List (partition)
import qualified Data.Set as Set
@ -174,7 +173,7 @@ unflattener writeToFlatVariant arr (t, (majorHi, majorLo)) =
arrUnflat = prefix arr
index = prefix "_tmp_index"
(minorHi, minorLo) = head $ snd $ typeRanges t
size = simplify $ BinOp Add (BinOp Sub minorHi minorLo) (Number "1")
size = rangeSize (minorHi, minorLo)
localparam :: Identifier -> Expr -> GenItem
localparam x v = GenModuleItem $ MIDecl $ Localparam (Implicit []) x v
origRange = ( (BinOp Add (Ident startBit)
@ -185,28 +184,6 @@ typeIsImplicit :: Type -> Bool
typeIsImplicit (Implicit _) = True
typeIsImplicit _ = False
-- basic expression simplfication utility to help us generate nicer code in the
-- common case of ranges like `[FOO-1:0]`
simplify :: Expr -> Expr
simplify (BinOp op e1 e2) =
case (op, e1', e2') of
(Add, Number "0", e) -> e
(Add, e, Number "0") -> e
(Sub, e, Number "0") -> e
(Add, BinOp Sub e (Number "1"), Number "1") -> e
(Add, e, BinOp Sub (Number "0") (Number "1")) -> BinOp Sub e (Number "1")
(_ , Number a, Number b) ->
case (op, readMaybe a :: Maybe Int, readMaybe b :: Maybe Int) of
(Add, Just x, Just y) -> Number $ show (x + y)
(Sub, Just x, Just y) -> Number $ show (x - y)
(Mul, Just x, Just y) -> Number $ show (x * y)
_ -> BinOp op e1' e2'
_ -> BinOp op e1' e2'
where
e1' = simplify e1
e2' = simplify e2
simplify other = other
-- prefix a string with a namespace of sorts
prefix :: Identifier -> Identifier
prefix ident = "_sv2v_" ++ ident
@ -220,8 +197,8 @@ flattenRanges rs =
where
(s1, e1) = head rs
(s2, e2) = head $ tail rs
size1 = BinOp Add (BinOp Sub s1 e1) (Number "1")
size2 = BinOp Add (BinOp Sub s2 e2) (Number "1")
size1 = rangeSize (s1, e1)
size2 = rangeSize (s2, e2)
upper = BinOp Add (BinOp Mul size1 size2) (BinOp Sub e1 (Number "1"))
r' = (simplify upper, e1)
rs' = (tail $ tail rs) ++ [r']
@ -254,7 +231,7 @@ rewriteModuleItem info =
else Range (Ident i) r
where
(a, b) = head $ snd $ typeRanges $ fst $ typeDims Map.! i
size = BinOp Add (BinOp Sub a b) (Number "1")
size = rangeSize (a, b)
s' = BinOp Sub (BinOp Mul size (BinOp Add s (Number "1"))) (Number "1")
e' = BinOp Mul size e
r' = (simplify s', simplify e')

22
src/Convert/Return.hs Normal file
View File

@ -0,0 +1,22 @@
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `return`
-}
module Convert.Return (convert) where
import Convert.Traverse
import Language.SystemVerilog.AST
convert :: AST -> AST
convert = traverseDescriptions $ traverseModuleItems convertFunction
convertFunction :: ModuleItem -> ModuleItem
convertFunction (Function ml t f decls stmts) =
Function ml t f decls (map (traverseNestedStmts convertStmt) stmts)
where
convertStmt :: Stmt -> Stmt
convertStmt (Return e) = AsgnBlk (LHSIdent f) e
convertStmt other = other
convertFunction other = other

231
src/Convert/Struct.hs Normal file
View File

@ -0,0 +1,231 @@
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `packed struct`
-}
module Convert.Struct (convert) where
import Data.Maybe (isJust)
import Data.List (sortOn)
import Data.Tuple (swap)
import Control.Monad.Writer
import qualified Data.Map.Strict as Map
import Convert.Traverse
import Language.SystemVerilog.AST
type TypeFunc = [Range] -> Type
type StructInfo = (Type, Map.Map Identifier (Range, Expr))
type Structs = Map.Map TypeFunc StructInfo
type Types = Map.Map Identifier Type
convert :: AST -> AST
convert = traverseDescriptions convertDescription
convertDescription :: Description -> Description
convertDescription description =
traverseModuleItems (traverseTypes $ convertType structs) $
traverseModuleItems (traverseAsgns $ convertAsgn structs types) $
description
where
structs = execWriter $ collectModuleItemsM
(collectTypesM collectType) description
typesA = execWriter $ collectModuleItemsM
(collectDeclsM collectDecl) description
typesB = execWriter $ collectModuleItemsM
collectFunction description
types = Map.union typesA typesB
-- write down unstructured versions of a packed struct type
collectType :: Type -> Writer Structs ()
collectType (Struct True fields _) = do
if canUnstructure
then tell $ Map.singleton
(Struct True fields)
(unstructType, unstructFields)
else return ()
where
zero = Number "0"
typeRange :: Type -> Range
typeRange t =
if null ranges then (zero, zero) else head ranges
where ranges = snd $ typeRanges t
-- extract info about the fields
fieldTypes = map fst fields
fieldRanges = map typeRange fieldTypes
fieldSizes = map rangeSize fieldRanges
-- layout the fields into the unstructured type; note that `scanr` is
-- used here because SystemVerilog structs are laid out backwards
fieldLos = map simplify $ tail $ scanr (BinOp Add) (Number "0") fieldSizes
fieldHis = map simplify $ init $ scanr (BinOp Add) (Number "-1") fieldSizes
-- create the mapping structure for the unstructured fields
unstructOffsets = map simplify $ map snd fieldRanges
unstructRanges = zip fieldHis fieldLos
keys = map snd fields
vals = zip unstructRanges unstructOffsets
unstructFields = Map.fromList $ zip keys vals
-- create the unstructured type
tf = fst $ typeRanges $ head fieldTypes
structSize = foldl1 (BinOp Add) fieldSizes
packedRange = (simplify $ BinOp Sub structSize (Number "1"), zero)
unstructType = tf [packedRange]
-- TODO: For now, we only convert packed structs which contain fields
-- with all the same base type. We might be able to get away with
-- converting everything to a Logic type. This should work in cases of
-- mixed `wire`/`logic` or `reg`/`logic`.
fieldClasses = map (show . fst . typeRanges) fieldTypes
canUnstructure = all (head fieldClasses ==) fieldClasses
collectType _ = return ()
-- convert a struct type to its unstructured equivalent
convertType :: Structs -> Type -> Type
convertType structs t1 =
case Map.lookup tf1 structs of
Nothing -> t1
Just (t2, _) -> tf2 (rs2 ++ rs1)
where (tf2, rs2) = typeRanges t2
where (tf1, rs1) = typeRanges t1
-- write down the type a declarations
collectDecl :: Decl -> Writer Types ()
collectDecl (Variable _ t x a _) =
-- We add the unpacked dimensions to the type so that our type traversal can
-- correctly match-off the dimensions whenever we see a `Bit` or `Range`
-- expression.
tell $ Map.singleton x (tf $ rs ++ a)
where (tf, rs) = typeRanges t
collectDecl (Parameter t x _) = tell $ Map.singleton x t
collectDecl (Localparam t x _) = tell $ Map.singleton x t
-- write down the return type of a function
collectFunction :: ModuleItem -> Writer Types ()
collectFunction (Function _ t f _ _) = tell $ Map.singleton f t
collectFunction _ = return ()
convertAsgn :: Structs -> Types -> (LHS, Expr) -> (LHS, Expr)
convertAsgn structs types (lhs, expr) =
(lhs', expr')
where
(typ, lhs') = convertLHS lhs
expr' = snd $ convertSubExpr $ convertExpr typ expr
-- converting LHSs by looking at the innermost types first
convertLHS :: LHS -> (Type, LHS)
convertLHS (LHSIdent x) =
case Map.lookup x types of
Nothing -> (Implicit [], LHSIdent x)
Just t -> (t, LHSIdent x)
convertLHS (LHSBit l e) =
(tf $ tail rs, LHSBit l' e)
where
(t, l') = convertLHS l
(tf, rs) = typeRanges t
convertLHS (LHSRange l r ) =
(tf rs', LHSRange l' r)
where
(t, l') = convertLHS l
(tf, rs) = typeRanges t
rs' = r : tail rs
convertLHS (LHSDot l x ) =
case t of
InterfaceT _ _ _ -> (Implicit [], l')
Struct _ _ _ -> case Map.lookup structTf structs of
Nothing -> (fieldType, LHSDot l' x)
Just (structT, m) -> (tf [tr], LHSRange l' r)
where
(tf, _) = typeRanges structT
(r @ (hi, lo), base) = m Map.! x
hi' = BinOp Add base $ BinOp Sub hi lo
lo' = base
tr = (simplify hi', simplify lo')
_ -> error $ "convertLHS encountered dot for bad type: " ++ show l
where
(t, l') = convertLHS l
Struct p fields [] = t
structTf = Struct p fields
fieldType = lookupFieldType fields x
convertLHS (LHSConcat lhss) =
(Implicit [], LHSConcat $ map (snd . convertLHS) lhss)
-- try expression conversion by looking at the *outermost* type first
convertExpr :: Type -> Expr -> Expr
convertExpr (Struct True fields []) (Pattern items) =
if Map.notMember structTf structs
then Pattern items''
else Concat exprs
where
subMap = \(Just ident, subExpr) ->
(Just ident, convertExpr (lookupFieldType fields ident) subExpr)
structTf = Struct True fields
items' =
-- if the pattern does not use identifiers, use the
-- identifiers from the struct type definition in order
if not (all (isJust . fst) items)
then zip (map (Just. snd) fields) (map snd items)
else items
items'' = map subMap items'
fieldRange = \(Just x, _) -> lookupUnstructRange structTf x
exprs = map snd $ reverse $ sortOn fieldRange items''
convertExpr _ other = other
-- try expression conversion by looking at the *innermost* type first
convertSubExpr :: Expr -> (Type, Expr)
convertSubExpr (Ident x) =
case Map.lookup x types of
Nothing -> (Implicit [], Ident x)
Just t -> (t, Ident x)
convertSubExpr (Access e x) =
if Map.notMember structTf structs
then (fieldType, Access e' x)
else (fieldType, Range e' r)
where
(subExprType, e') = convertSubExpr e
Struct p fields [] = subExprType
structTf = Struct p fields
fieldType = lookupFieldType fields x
r = lookupUnstructRange structTf x
convertSubExpr (Range eOuter (rOuter @ (hiO, loO))) =
-- VCS doesn't allow ranges to be cascaded, so we need to combine
-- nested Ranges into a single range. My understanding of the
-- semantics are that a range return a new, zero-indexed sub-range.
case eOuter' of
Range eInner (hiI, loI) ->
(t, Range eInner (simplify hi, simplify lo))
where
hi = BinOp Add (BinOp Sub hiI loI) hiO
lo = BinOp Add loI loO
_ -> (t, Range eOuter' rOuter)
where (t, eOuter') = convertSubExpr eOuter
convertSubExpr (Concat exprs) =
(Implicit [], Concat $ map (snd . convertSubExpr) exprs)
convertSubExpr (BinOp op e1 e2) =
(Implicit [], BinOp op e1' e2')
where
(_, e1') = convertSubExpr e1
(_, e2') = convertSubExpr e2
-- TODO: There are other expression cases that we probably need to
-- recurse into. That said, it's not clear to me how much we really
-- expect to see things like concatenated packed structs, for example.
convertSubExpr other = (Implicit [], other)
-- lookup the range of a field in its unstructured type
lookupUnstructRange :: TypeFunc -> Identifier -> Range
lookupUnstructRange structTf fieldName =
fieldRangeMap Map.! fieldName
where fieldRangeMap = Map.map fst $ snd $ structs Map.! structTf
-- lookup the type of a field in the given field list
lookupFieldType :: [(Type, Identifier)] -> Identifier -> Type
lookupFieldType fields fieldName = fieldMap Map.! fieldName
where fieldMap = Map.fromList $ map swap fields

View File

@ -36,6 +36,10 @@ module Convert.Traverse
, traverseGenItemsM
, traverseGenItems
, collectGenItemsM
, traverseAsgnsM
, traverseAsgns
, collectAsgnsM
, traverseNestedStmts
) where
import Data.Maybe (fromJust)
@ -339,8 +343,25 @@ traverseTypesM :: Monad m => MapperM m Type -> MapperM m ModuleItem
traverseTypesM mapper item =
miMapper item >>= traverseDeclsM declMapper >>= traverseExprsM exprMapper
where
fullMapper t = tm t >>= mapper
tm (Reg r) = return $ Reg r
tm (Wire r) = return $ Wire r
tm (Logic r) = return $ Logic r
tm (Alias x r) = return $ Alias x r
tm (Implicit r) = return $ Implicit r
tm (IntegerT ) = return $ IntegerT
tm (InterfaceT x my r) = return $ InterfaceT x my r
tm (Enum Nothing vals r) =
return $ Enum Nothing vals r
tm (Enum (Just t) vals r) = do
t' <- fullMapper t
return $ Enum (Just t') vals r
tm (Struct p fields r) = do
types <- mapM fullMapper $ map fst fields
let idents = map snd fields
return $ Struct p (zip types idents) r
exprMapper (Cast t e) = do
t' <- mapper t
t' <- fullMapper t
-- TODO HACK: If the cast type is no longer "simple", we just drop
-- the case altogether. This probably doesn't work great in all
-- cases.
@ -349,13 +370,13 @@ traverseTypesM mapper item =
else Cast t' e
exprMapper other = return other
declMapper (Parameter t x e) =
mapper t >>= \t' -> return $ Parameter t' x e
fullMapper t >>= \t' -> return $ Parameter t' x e
declMapper (Localparam t x e) =
mapper t >>= \t' -> return $ Localparam t' x e
fullMapper t >>= \t' -> return $ Localparam t' x e
declMapper (Variable d t x a me) =
mapper t >>= \t' -> return $ Variable d t' x a me
fullMapper t >>= \t' -> return $ Variable d t' x a me
miMapper (Function l t x d s) =
mapper t >>= \t' -> return $ Function l t' x d s
fullMapper t >>= \t' -> return $ Function l t' x d s
miMapper other = return other
traverseTypes :: Mapper Type -> Mapper ModuleItem
@ -398,3 +419,30 @@ traverseNestedGenItemsM mapper = fullMapper
gim (GenModuleItem moduleItem) =
return $ GenModuleItem moduleItem
gim (GenNull) = return GenNull
traverseAsgnsM :: Monad m => MapperM m (LHS, Expr) -> MapperM m ModuleItem
traverseAsgnsM mapper = moduleItemMapper
where
moduleItemMapper item = miMapperA item >>= miMapperB
miMapperA (Assign lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ Assign lhs' expr'
miMapperA other = return other
miMapperB = traverseStmtsM stmtMapper
stmtMapper (AsgnBlk lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ AsgnBlk lhs' expr'
stmtMapper (Asgn lhs expr) = do
(lhs', expr') <- mapper (lhs, expr)
return $ Asgn lhs' expr'
stmtMapper other = return other
traverseAsgns :: Mapper (LHS, Expr) -> Mapper ModuleItem
traverseAsgns = unmonad traverseAsgnsM
collectAsgnsM :: Monad m => CollectorM m (LHS, Expr) -> CollectorM m ModuleItem
collectAsgnsM = collectify traverseAsgnsM
traverseNestedStmts :: Mapper Stmt -> Mapper Stmt
traverseNestedStmts = unmonad traverseNestedStmtsM

View File

@ -26,11 +26,14 @@ module Language.SystemVerilog.AST
, Range
, GenCase
, typeRanges
, simplify
, rangeSize
) where
import Data.List
import Data.Maybe
import Text.Printf
import Text.Read (readMaybe)
type Identifier = String
@ -119,10 +122,13 @@ instance Show Type where
showItem (t, x) = printf "%s %s;" (show t) x
instance Show ([Range] -> Type) where
show tf = show (tf [])
show tf = show (tf [])
instance Eq ([Range] -> Type) where
(==) tf1 tf2 = (show $ tf1 []) == (show $ tf2 [])
(==) tf1 tf2 = (tf1 []) == (tf2 [])
instance Ord ([Range] -> Type) where
compare tf1 tf2 = compare (show tf1) (show tf2)
typeRanges :: Type -> ([Range] -> Type, [Range])
typeRanges (Reg r) = (Reg , r)
@ -130,7 +136,7 @@ typeRanges (Wire r) = (Wire , r)
typeRanges (Logic r) = (Logic , r)
typeRanges (Alias t r) = (Alias t, r)
typeRanges (Implicit r) = (Implicit, r)
typeRanges (IntegerT ) = (error "ranges cannot be applied to IntegerT", [])
typeRanges (IntegerT ) = (\[] -> IntegerT, [])
typeRanges (Enum t v r) = (Enum t v, r)
typeRanges (Struct p l r) = (Struct p l, r)
typeRanges (InterfaceT x my r) = (InterfaceT x my, r)
@ -523,3 +529,29 @@ instance Show Lifetime where
showLifetime :: Maybe Lifetime -> String
showLifetime Nothing = ""
showLifetime (Just l) = show l ++ " "
-- basic expression simplfication utility to help us generate nicer code in the
-- common case of ranges like `[FOO-1:0]`
simplify :: Expr -> Expr
simplify (BinOp op e1 e2) =
case (op, e1', e2') of
(Add, Number "0", e) -> e
(Add, e, Number "0") -> e
(Sub, e, Number "0") -> e
(Add, BinOp Sub e (Number "1"), Number "1") -> e
(Add, e, BinOp Sub (Number "0") (Number "1")) -> BinOp Sub e (Number "1")
(_ , Number a, Number b) ->
case (op, readMaybe a :: Maybe Int, readMaybe b :: Maybe Int) of
(Add, Just x, Just y) -> Number $ show (x + y)
(Sub, Just x, Just y) -> Number $ show (x - y)
(Mul, Just x, Just y) -> Number $ show (x * y)
_ -> BinOp op e1' e2'
_ -> BinOp op e1' e2'
where
e1' = simplify e1
e2' = simplify e2
simplify other = other
rangeSize :: Range -> Expr
rangeSize (s, e) =
simplify $ BinOp Add (BinOp Sub s e) (Number "1")

View File

@ -46,8 +46,10 @@ executable sv2v
Convert.Enum
Convert.Logic
Convert.PackedArray
Convert.Return
Convert.SplitPortDecl
Convert.StarPort
Convert.Struct
Convert.Typedef
Convert.Traverse
Convert.Unique