Commit f9d46d54 by Zachary Snow

cleanup of Enum conversion; additional test

parent 383754fa
...@@ -3,17 +3,25 @@ ...@@ -3,17 +3,25 @@
- -
- Conversion for `enum` - Conversion for `enum`
- -
- TODO: We do not yet properly support enums which specify the value for some, - This conversion replaces the enum items with localparams declared within any
- but not all items. My understanding is that they should continue in order - modules in which that enum type appears. This is not necessarily foolproof,
- from the previous value. - as some tools do allow the use of an enum item even if the actual enum type
- does not appear in that description.
-
- 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
- values take on the value of the previous item, plus 1.
-
- It is an error for multiple items of the same enum to take on the same value,
- whether implicitly or explicitly. We catch try to catch "obvious" instances
- of conflicts.
-} -}
module Convert.Enum (convert) where module Convert.Enum (convert) where
import Text.Read (readMaybe)
import Data.Maybe (fromMaybe)
import Data.List (sortOn)
import Control.Monad.Writer import Control.Monad.Writer
import Data.List (elemIndices, sortOn)
import Data.Maybe (fromMaybe)
import qualified Data.Set as Set import qualified Data.Set as Set
import Convert.Traverse import Convert.Traverse
...@@ -32,36 +40,45 @@ convertDescription :: Description -> Description ...@@ -32,36 +40,45 @@ convertDescription :: Description -> Description
convertDescription (description @ (Part _ _ _ _ _ _)) = convertDescription (description @ (Part _ _ _ _ _ _)) =
Part extern kw lifetime name ports (enumItems ++ items) Part extern kw lifetime name ports (enumItems ++ items)
where where
enumPairs = sortOn snd $ concatMap (uncurry enumVals) $ Set.toList enums -- replace and collect the enum types in this description
enumItems = map (\(x, v) -> MIDecl $ Localparam (Implicit Unspecified []) x v) enumPairs
(Part extern kw lifetime name ports items, enums) = (Part extern kw lifetime name ports items, enums) =
runWriter $ traverseModuleItemsM (traverseTypesM traverseType) $ runWriter $
traverseModuleItemsM (traverseTypesM traverseType) $
traverseModuleItems (traverseExprs $ traverseNestedExprs traverseExpr) $ traverseModuleItems (traverseExprs $ traverseNestedExprs traverseExpr) $
description description
traverseType :: Type -> Writer Enums Type -- convert the collected enums into their corresponding localparams
traverseType (Enum t v r) = do itemType = Implicit Unspecified []
() <- tell $ Set.singleton (t, v) enumPairs = sortOn snd $ concatMap (enumVals . snd) $ Set.toList enums
let baseType = fromMaybe defaultType t enumItems = map (\(x, v) -> MIDecl $ Localparam itemType x v) enumPairs
let (tf, rs) = typeRanges baseType
return $ tf (rs ++ r)
traverseType other = return other
-- drop any enum type casts in favor of implicit conversion from the
-- converted type
traverseExpr :: Expr -> Expr
traverseExpr (Cast (Left (Enum _ _ _)) e) = e
traverseExpr other = other
convertDescription other = other convertDescription other = other
enumVals :: Maybe Type -> [(Identifier, Maybe Expr)] -> [(Identifier, Expr)] -- replace, but write down, enum types
enumVals _ l = zip traverseType :: Type -> Writer Enums Type
(map fst l) traverseType (Enum t v r) = do
(tail $ scanl step (Number "-1") (map snd l)) () <- tell $ Set.singleton (t, v)
let baseType = fromMaybe defaultType t
let (tf, rs) = typeRanges baseType
return $ tf (rs ++ r)
traverseType other = return other
-- drop any enum type casts in favor of implicit conversion from the
-- converted type
traverseExpr :: Expr -> Expr
traverseExpr (Cast (Left (Enum _ _ _)) e) = e
traverseExpr other = other
enumVals :: [(Identifier, Maybe Expr)] -> [(Identifier, Expr)]
enumVals l =
-- check for obviously duplicate values
if noDuplicates
then res
else error $ "enum conversion has duplicate vals: " ++ show res
where where
keys = map fst l
vals = tail $ scanl step (Number "-1") (map snd l)
res = zip keys 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 (Number n) Nothing =
case (readMaybe n) :: Maybe Int of
Just value -> Number (show $ value + 1)
Nothing -> BinOp Add (Number n) (Number "1")
step expr Nothing = step expr Nothing =
BinOp Add expr (Number "1") simplify $ BinOp Add expr (Number "1")
typedef enum {
A_1, A_2, A_3
} EnumA;
typedef enum {
B_1 = 2, B_2 = 1, B_3 = 3
} EnumB;
typedef enum {
C_1 = 20, C_2 = 0, C_3 = 19
} EnumC;
typedef enum {
D_1 = 'h10, D_2, D_3
} EnumD;
typedef enum {
E_1, E_2 = 'h10, E_3, E_4, E_5 = 'b10, E_6
} EnumE;
`define PRINT(val) $display("%02d", val);
module top;
EnumA dummyA;
EnumB dummyB;
EnumC dummyC;
EnumD dummyD;
EnumE dummyE;
initial begin
`PRINT(A_1)
`PRINT(A_2)
`PRINT(A_3)
`PRINT(B_1)
`PRINT(B_2)
`PRINT(B_3)
`PRINT(C_1)
`PRINT(C_2)
`PRINT(C_3)
`PRINT(D_1)
`PRINT(D_2)
`PRINT(D_3)
`PRINT(E_1)
`PRINT(E_2)
`PRINT(E_3)
`PRINT(E_4)
`PRINT(E_5)
`PRINT(E_6)
end
endmodule
`define PRINT(val) $display("%02d", val);
module top;
initial begin
`PRINT(0)
`PRINT(1)
`PRINT(2)
`PRINT(2)
`PRINT(1)
`PRINT(3)
`PRINT(20)
`PRINT(0)
`PRINT(19)
`PRINT(16)
`PRINT(17)
`PRINT(18)
`PRINT(0)
`PRINT(16)
`PRINT(17)
`PRINT(18)
`PRINT(2)
`PRINT(3)
end
endmodule
#!/bin/sh
NO_SEPARATE_TBS=1
source ../lib/runner.sh
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