Commit f9d46d54 by Zachary Snow

cleanup of Enum conversion; additional test

parent 383754fa
......@@ -3,17 +3,25 @@
-
- Conversion for `enum`
-
- TODO: We do not yet properly support enums which specify the value for some,
- but not all items. My understanding is that they should continue in order
- from the previous value.
- This conversion replaces the enum items with localparams declared within any
- modules in which that enum type appears. This is not necessarily foolproof,
- 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
import Text.Read (readMaybe)
import Data.Maybe (fromMaybe)
import Data.List (sortOn)
import Control.Monad.Writer
import Data.List (elemIndices, sortOn)
import Data.Maybe (fromMaybe)
import qualified Data.Set as Set
import Convert.Traverse
......@@ -32,36 +40,45 @@ convertDescription :: Description -> Description
convertDescription (description @ (Part _ _ _ _ _ _)) =
Part extern kw lifetime name ports (enumItems ++ items)
where
enumPairs = sortOn snd $ concatMap (uncurry enumVals) $ Set.toList enums
enumItems = map (\(x, v) -> MIDecl $ Localparam (Implicit Unspecified []) x v) enumPairs
-- replace and collect the enum types in this description
(Part extern kw lifetime name ports items, enums) =
runWriter $ traverseModuleItemsM (traverseTypesM traverseType) $
runWriter $
traverseModuleItemsM (traverseTypesM traverseType) $
traverseModuleItems (traverseExprs $ traverseNestedExprs traverseExpr) $
description
traverseType :: Type -> Writer Enums Type
traverseType (Enum t v r) = do
() <- 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
-- convert the collected enums into their corresponding localparams
itemType = Implicit Unspecified []
enumPairs = sortOn snd $ concatMap (enumVals . snd) $ Set.toList enums
enumItems = map (\(x, v) -> MIDecl $ Localparam itemType x v) enumPairs
convertDescription other = other
enumVals :: Maybe Type -> [(Identifier, Maybe Expr)] -> [(Identifier, Expr)]
enumVals _ l = zip
(map fst l)
(tail $ scanl step (Number "-1") (map snd l))
-- replace, but write down, enum types
traverseType :: Type -> Writer Enums Type
traverseType (Enum t v r) = do
() <- 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
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 _ (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 =
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