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
|
{-# 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
newtype Identifier = Identifier { _getIdentifier :: Text }
deriving (Show)
data Number = Number { _numSize :: Int
, _numVal :: Int
} deriving (Show)
data BinaryOperator = BinAnd
| BinOr
| BinXor
deriving (Show)
data UnaryOperator = UnNot
| UnMinus
deriving (Show)
data Primary = PrimNum Number
| PrimId Identifier
deriving (Show)
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)
data ContAssign = ContAssign { _contAssignNetLVal :: Identifier
, _contAssignExpr :: Expression
} deriving (Show)
data PortDir = Input
| Output
| InOut
deriving (Show)
data Port = Port { _portName :: Identifier
, _portDir :: PortDir
} deriving (Show)
newtype ModuleItem = Assign ContAssign
deriving (Show)
-- | 'module' module_identifier [list_of_ports] ';' { module_item } 'end_module'
data ModuleDecl = ModuleDecl { _moduleId :: Identifier
, _modPorts :: [Port]
, _moduleItems :: [ModuleItem]
} deriving (Show)
newtype Description = Description { _getDescription :: ModuleDecl }
deriving (Show)
newtype SourceText = SourceText { _getSourceText :: [Description] }
deriving (Show)
-- 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 <$> QC.arbitrary <*> 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
numExpr :: Int -> Int -> Expression
numExpr = ((PrimExpr . PrimNum) .) . Number
emptyMod :: ModuleDecl
emptyMod = ModuleDecl (Identifier "") [] []
setModName :: Text -> ModuleDecl -> ModuleDecl
setModName str = moduleId .~ Identifier str
addModPort :: Port -> ModuleDecl -> ModuleDecl
addModPort port = modPorts %~ (:) port
|