Commit 97b2d1d1 by Zachary Snow

fix declaration order of generated enum items

parent ecf047e3
...@@ -3,12 +3,10 @@ ...@@ -3,12 +3,10 @@
- -
- Conversion for `enum` - Conversion for `enum`
- -
- This conversion replaces the enum items with localparams declared within any - This conversion replaces the enum items with localparams declared at the
- modules in which that enum type appears. This is not necessarily foolproof, - global scope. We leave it to the package item nesting conversion to determine
- as some tools do allow the use of an enum item even if the actual enum type - where the generated localparams are needed. The localparams are explicitly
- does not appear in that description. The localparams are explicitly sized to - sized to match the size of the converted enum type.
- match the size of the converted enum type. This conversion includes only enum
- items which are actually used within a given description.
- -
- SystemVerilog allows for enums to have any number of the items' values - SystemVerilog allows for enums to have any number of the items' values
- specified or unspecified. If the first one is unspecified, it is 0. All other - specified or unspecified. If the first one is unspecified, it is 0. All other
...@@ -22,7 +20,7 @@ ...@@ -22,7 +20,7 @@
module Convert.Enum (convert) where module Convert.Enum (convert) where
import Control.Monad.Writer import Control.Monad.Writer
import Data.List (elemIndices, partition, sortOn) import Data.List (elemIndices)
import qualified Data.Set as Set import qualified Data.Set as Set
import Convert.Traverse import Convert.Traverse
...@@ -30,70 +28,31 @@ import Language.SystemVerilog.AST ...@@ -30,70 +28,31 @@ import Language.SystemVerilog.AST
type EnumInfo = (Maybe Range, [(Identifier, Maybe Expr)]) type EnumInfo = (Maybe Range, [(Identifier, Maybe Expr)])
type Enums = Set.Set EnumInfo type Enums = Set.Set EnumInfo
type Idents = Set.Set Identifier
type EnumItem = ((Maybe Range, Identifier), Expr)
convert :: [AST] -> [AST] convert :: [AST] -> [AST]
convert = map $ traverseDescriptions convertDescription convert = map $ concatMap convertDescription
defaultType :: Type defaultType :: Type
defaultType = IntegerVector TLogic Unspecified [(Number "31", Number "0")] defaultType = IntegerVector TLogic Unspecified [(Number "31", Number "0")]
convertDescription :: Description -> Description convertDescription :: Description -> [Description]
convertDescription (description @ Part{}) = convertDescription (description @ Package{}) =
Part attrs extern kw lifetime name ports (enumItems ++ items) [Package ml name (items ++ enumItems)]
where where (Package ml name items, enumItems) = convertDescription' description
-- replace and collect the enum types in this description convertDescription description =
(Part attrs extern kw lifetime name ports items, enumPairs) = (map PackageItem enumItems) ++ [description']
convertDescription' description where (description', enumItems) = convertDescription' description
-- convert the collected enums into their corresponding localparams
enumItems = map MIPackageItem $ map toItem $ sortOn snd $ convergeUsage items enumPairs
convertDescription (description @ (Package _ _ _)) =
Package ml name (items ++ enumItems)
where
-- replace and collect the enum types in this description
(Package ml name items, enumPairs) =
convertDescription' description
-- convert the collected enums into their corresponding localparams
enumItems = map toItem $ sortOn snd $ enumPairs
convertDescription other = other
-- replace and collect the enum types in a description -- replace and collect the enum types in a description
convertDescription' :: Description -> (Description, [EnumItem]) convertDescription' :: Description -> (Description, [PackageItem])
convertDescription' description = convertDescription' description =
(description', enumPairs) (description', enumItems)
where where
-- replace and collect the enum types in this description -- replace and collect the enum types in this description
(description', enums) = runWriter $ (description', enums) = runWriter $
traverseModuleItemsM (traverseTypesM traverseType) description traverseModuleItemsM (traverseTypesM traverseType) description
-- convert the collected enums into their corresponding localparams -- convert the collected enums into their corresponding localparams
enumPairs = concatMap enumVals $ Set.toList enums enumItems = concatMap makeEnumItems $ Set.toList enums
-- add only the enums actually used in the given items
convergeUsage :: [ModuleItem] -> [EnumItem] -> [EnumItem]
convergeUsage items enums =
if null usedEnums
then []
else usedEnums ++ convergeUsage (enumItems ++ items) unusedEnums
where
-- determine which of the enum items are actually used here
(usedEnums, unusedEnums) = partition isUsed enums
enumItems = map MIPackageItem $ map toItem usedEnums
isUsed ((_, x), _) = Set.member x usedIdents
usedIdents = execWriter $ mapM collectModuleItemM items
collectModuleItemM = collectNestedModuleItemsM $ collectExprsM $
collectNestedExprsM collectIdent
collectIdent :: Expr -> Writer Idents ()
collectIdent (Ident x) = tell $ Set.singleton x
collectIdent _ = return ()
toItem :: EnumItem -> PackageItem
toItem ((mr, x), v) =
Decl $ Param Localparam itemType x v'
where
v' = simplify v
rs = maybe [] (\a -> [a]) mr
itemType = Implicit Unspecified rs
toBaseType :: Maybe Type -> Type toBaseType :: Maybe Type -> Type
toBaseType Nothing = defaultType toBaseType Nothing = defaultType
...@@ -123,19 +82,24 @@ traverseType other = return other ...@@ -123,19 +82,24 @@ traverseType other = return other
simplifyRange :: Range -> Range simplifyRange :: Range -> Range
simplifyRange (a, b) = (simplify a, simplify b) simplifyRange (a, b) = (simplify a, simplify b)
enumVals :: EnumInfo -> [EnumItem] makeEnumItems :: EnumInfo -> [PackageItem]
enumVals (mr, l) = makeEnumItems (mr, l) =
-- check for obviously duplicate values -- check for obviously duplicate values
if noDuplicates if noDuplicates
then res then zipWith toPackageItem keys vals
else error $ "enum conversion has duplicate vals: " else error $ "enum conversion has duplicate vals: "
++ show (zip keys vals) ++ show (zip keys vals)
where where
keys = map fst l keys = map fst l
vals = tail $ scanl step (Number "-1") (map snd l) vals = tail $ scanl step (Number "-1") (map snd l)
res = zip (zip (repeat mr) keys) vals
noDuplicates = all (null . tail . flip elemIndices vals) vals noDuplicates = all (null . tail . flip elemIndices vals) vals
step :: Expr -> Maybe Expr -> Expr step :: Expr -> Maybe Expr -> Expr
step _ (Just expr) = expr step _ (Just expr) = expr
step expr Nothing = step expr Nothing =
simplify $ BinOp Add expr (Number "1") simplify $ BinOp Add expr (Number "1")
rs = maybe [] (\a -> [a]) mr
itemType = Implicit Unspecified rs
toPackageItem :: Identifier -> Expr -> PackageItem
toPackageItem x v =
Decl $ Param Localparam itemType x v'
where v' = simplify v
...@@ -3,6 +3,15 @@ localparam Y = 5'(Z); ...@@ -3,6 +3,15 @@ localparam Y = 5'(Z);
localparam X = 5'(Y); localparam X = 5'(Y);
module top; module top;
parameter W = 3;
typedef enum logic [W-1:0] {
A, B
} E;
initial begin
$display("%b", A);
$display("%b", B);
end
initial begin initial begin
$display("%b", X); $display("%b", X);
$display("%b", Y); $display("%b", Y);
......
module top; module top;
initial begin initial begin
$display("%b", 3'b000);
$display("%b", 3'b001);
end
initial begin
$display("%b", 5'b1); $display("%b", 5'b1);
$display("%b", 5'b1); $display("%b", 5'b1);
$display("%b", 32'b1); $display("%b", 32'b1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment