From f9d46d548eb0e221168c1d85a850a7f6be9c2ea7 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 3 Apr 2019 21:31:49 -0400 Subject: [PATCH] cleanup of Enum conversion; additional test --- src/Convert/Enum.hs | 77 +++++++++++++++++++++++++++------------------ test/basic/enum.sv | 56 +++++++++++++++++++++++++++++++++ test/basic/enum.v | 30 ++++++++++++++++++ test/basic/run.sh | 3 ++ 4 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 test/basic/enum.sv create mode 100644 test/basic/enum.v create mode 100755 test/basic/run.sh diff --git a/src/Convert/Enum.hs b/src/Convert/Enum.hs index 34dd898..3627da7 100644 --- a/src/Convert/Enum.hs +++ b/src/Convert/Enum.hs @@ -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") diff --git a/test/basic/enum.sv b/test/basic/enum.sv new file mode 100644 index 0000000..fabf4c7 --- /dev/null +++ b/test/basic/enum.sv @@ -0,0 +1,56 @@ +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 diff --git a/test/basic/enum.v b/test/basic/enum.v new file mode 100644 index 0000000..bcb2933 --- /dev/null +++ b/test/basic/enum.v @@ -0,0 +1,30 @@ +`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 diff --git a/test/basic/run.sh b/test/basic/run.sh new file mode 100755 index 0000000..0dc63aa --- /dev/null +++ b/test/basic/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh +NO_SEPARATE_TBS=1 +source ../lib/runner.sh