1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
{-|
Module : Test.VeriFuzz.VerilogAST
Description : Definition of the Verilog AST types.
Copyright : (c) Yann Herklotz Grave 2018
License : GPL-3
Maintainer : ymherklotz@gmail.com
Stability : experimental
Portability : POSIX
Defines the types to build a Verilog AST.
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Test.VeriFuzz.VerilogAST where
import Control.Lens
import Data.Text as T
import Data.Text (Text)
import Test.QuickCheck as QC
-- | Identifier in Verilog. This is just a string of characters that can either
-- be lowercase and uppercase for now. This might change in the future though,
-- as Verilog supports many more characters in Identifiers.
newtype Identifier = Identifier { _getIdentifier :: Text }
deriving (Show, Eq)
-- | A number in Verilog which contains a size and a value.
data Number = Number { _numSize :: Int
, _numVal :: Int
} deriving (Show, Eq)
-- | Binary operators that are currently supported in the verilog generation.
data BinaryOperator = BinAnd -- ^ Binary And (&).
| BinOr -- ^ Binary Or (|).
| BinXor -- ^ Binary Xor (^).
deriving (Show, Eq)
-- | Unary operators that are currently supported by the generator.
data UnaryOperator = UnNot -- ^ Not (!).
| UnMinus -- ^ Minus (-).
deriving (Show, Eq)
-- | A primary expression which can either be a number or an identifier.
data Primary = PrimNum Number -- ^ Number in primary expression.
| PrimId Identifier -- ^ Identifier in primary expression.
deriving (Show, Eq)
-- | Verilog expression, which can either be a primary expression, unary
-- expression, binary operator expression or a conditional expression.
data Expression = PrimExpr Primary
| UnPrimExpr { _exprUnOp :: UnaryOperator
, _exprPrim :: Primary
}
| OpExpr { _exprLhs :: Expression
, _exprBinOp :: BinaryOperator
, _exprRhs :: Expression
}
| CondExpr { _exprCond :: Expression
, _exprTrue :: Expression
, _exprFalse :: Expression
}
deriving (Show, Eq)
-- | Continuous assignment which can be in the body of a statement.
data ContAssign = ContAssign { _contAssignNetLVal :: Identifier
, _contAssignExpr :: Expression
} deriving (Show, Eq)
-- | Different port direction that are supported in Verilog.
data PortDir = Input -- ^ Input direction for port (@input@).
| Output -- ^ Output direction for port (@output@).
| InOut -- ^ Inout direction for port (@inout@).
deriving (Show, Eq)
-- | Port declaration.
data Port = Port { _portDir :: PortDir
, _portName :: Identifier
} deriving (Show, Eq)
-- | Module item which is the body of the module expression.
newtype ModuleItem = Assign ContAssign
deriving (Show, Eq)
-- | 'module' module_identifier [list_of_ports] ';' { module_item } 'end_module'
data ModuleDecl = ModuleDecl { _moduleId :: Identifier
, _modPorts :: [Port]
, _moduleItems :: [ModuleItem]
} deriving (Show, Eq)
-- | Description of the Verilog module.
newtype Description = Description { _getDescription :: ModuleDecl }
deriving (Show, Eq)
-- | The complete sourcetext for the Verilog module.
newtype SourceText = SourceText { _getSourceText :: [Description] }
deriving (Show, Eq)
-- Generate Arbitrary instances for the AST
instance QC.Arbitrary Identifier where
arbitrary = Identifier . T.pack <$>
(QC.shuffle (['a'..'z'] <> ['A'..'Z']) >>= QC.sublistOf)
instance QC.Arbitrary Number where
arbitrary = Number <$> suchThat QC.arbitrary (>0) <*> QC.arbitrary
instance QC.Arbitrary BinaryOperator where
arbitrary = QC.elements [BinAnd, BinOr, BinXor]
instance QC.Arbitrary UnaryOperator where
arbitrary = QC.elements [UnNot, UnMinus]
instance QC.Arbitrary Primary where
arbitrary = PrimNum <$> QC.arbitrary
instance QC.Arbitrary PortDir where
arbitrary = QC.elements [Input, Output, InOut]
instance QC.Arbitrary Port where
arbitrary = Port <$> QC.arbitrary <*> QC.arbitrary
instance QC.Arbitrary Expression where
arbitrary = QC.frequency [ (1, OpExpr <$> QC.arbitrary <*> QC.arbitrary <*> QC.arbitrary)
, (2, PrimExpr <$> arbitrary)
]
instance QC.Arbitrary ContAssign where
arbitrary = ContAssign <$> QC.arbitrary <*> QC.arbitrary
instance QC.Arbitrary ModuleItem where
arbitrary = Assign <$> QC.arbitrary
instance QC.Arbitrary ModuleDecl where
arbitrary = ModuleDecl <$> QC.arbitrary <*> QC.arbitrary <*> QC.arbitrary
instance QC.Arbitrary Description where
arbitrary = Description <$> QC.arbitrary
instance QC.Arbitrary SourceText where
arbitrary = SourceText <$> QC.arbitrary
-- Create all the necessary lenses
makeLenses ''Identifier
makeLenses ''Number
makeLenses ''SourceText
makeLenses ''Description
makeLenses ''ModuleDecl
makeLenses ''ModuleItem
makeLenses ''Port
makeLenses ''PortDir
makeLenses ''BinaryOperator
makeLenses ''UnaryOperator
makeLenses ''Primary
makeLenses ''Expression
makeLenses ''ContAssign
-- Helper functions for the AST
-- | Create a number expression which will be stored in a primary expression.
numExpr :: Int -> Int -> Expression
numExpr = ((PrimExpr . PrimNum) .) . Number
-- | Create an empty module.
emptyMod :: ModuleDecl
emptyMod = ModuleDecl (Identifier "") [] []
-- | Set a module name for a module declaration.
setModName :: Text -> ModuleDecl -> ModuleDecl
setModName str = moduleId .~ Identifier str
-- | Add a port to the module declaration.
addModPort :: Port -> ModuleDecl -> ModuleDecl
addModPort port = modPorts %~ (:) port
|