vhdl_tb 0.7.7 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/tbgen +2 -5
- data/bin/vhdl_tb +2 -5
- data/lib/ast.rb +34 -4
- data/lib/compiler.rb +17 -44
- data/lib/generic_parser.rb +15 -0
- data/lib/lexer.rb +21 -8
- data/lib/parser.rb +732 -42
- data/lib/runner.rb +89 -0
- data/lib/token.rb +5 -0
- data/lib/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 313f1e44991a5318c80cedf07f0762100a2bfd71171c6de3dcdf75a4b6594bfb
|
4
|
+
data.tar.gz: 7c6c361dfef387ae6767c4b59113145f0e71ab8e35217fa46272b8d69322fc32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b8fdf9e01c639116a968b6e88873eeece3100ad9e7741b092ff6e98e2387a3391c9320ba0e7c7d484d2d9db3183026bcf8de09b7648d1d2379a043236b21e34
|
7
|
+
data.tar.gz: c4a5947e34d387336f174e8259991a9884080d35bebd6c8c50e38c5b8834f97071a7a7aa7ce7d5e74ce05036d8fe46df808b2e8e19f9454463c2e16c51f57b91
|
data/bin/tbgen
CHANGED
data/bin/vhdl_tb
CHANGED
data/lib/ast.rb
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
module VHDL_TB
|
2
|
-
|
2
|
+
class AstNode
|
3
|
+
end
|
4
|
+
|
5
|
+
class Root < AstNode
|
6
|
+
attr_accessor :design_units
|
7
|
+
def initialize design_units=[]
|
8
|
+
@design_units=design_units
|
9
|
+
end
|
10
|
+
|
11
|
+
def << e
|
12
|
+
@design_units << e
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
3
16
|
Entity=Struct.new(:name,:generics,:ports)
|
4
17
|
Generic=Struct.new(:name,:type,:init)
|
5
18
|
Input=Struct.new(:name,:type)
|
@@ -24,10 +37,27 @@ module VHDL_TB
|
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
40
|
+
class Expression < AstNode
|
41
|
+
end
|
27
42
|
|
28
|
-
Binary
|
29
|
-
|
30
|
-
|
43
|
+
class Binary < Expression
|
44
|
+
attr_accessor :lhs,:op,:rhs
|
45
|
+
def initialize lhs=nil,op=nil,rhs=nil
|
46
|
+
@lhs,@op,@rhs=lhs,op,rhs
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class FuncCall
|
51
|
+
attr_accessor :name,:actual_args
|
52
|
+
def initialize name=nil,args=[]
|
53
|
+
@name,@args=name,args
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Timed
|
58
|
+
attr_accessor :lhs,:rhs
|
59
|
+
def initialize lhs,rhs
|
60
|
+
@lhs,@rhs=lhs,rhs
|
31
61
|
end
|
32
62
|
end
|
33
63
|
end
|
data/lib/compiler.rb
CHANGED
@@ -8,60 +8,37 @@ require_relative 'version'
|
|
8
8
|
|
9
9
|
module VHDL_TB
|
10
10
|
|
11
|
-
|
11
|
+
TestBench=Struct.new(:name)
|
12
12
|
|
13
13
|
class Compiler
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
attr_accessor :options
|
16
|
+
attr_accessor :ast
|
17
|
+
|
18
|
+
def initialize options={}
|
18
19
|
@engine=ERB.new(IO.read "#{__dir__}/template.tb.vhd")
|
19
|
-
@parser=Parser.new
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
puts "
|
22
|
+
def compile filename
|
23
|
+
puts "analyzing VHDL file : #{filename}"
|
24
|
+
@ast=Parser.new.parse filename
|
25
|
+
analyze filename
|
26
|
+
generate
|
24
27
|
end
|
25
28
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
opt_parser = OptionParser.new do |opts|
|
30
|
-
opts.banner = "Usage: vhdl_tb (or tbgen) <filename>"
|
31
|
-
|
32
|
-
opts.on("-v", "--version", "Prints version") do |n|
|
33
|
-
puts VERSION
|
34
|
-
abort
|
35
|
-
end
|
36
|
-
|
37
|
-
opts.on("-h", "--help", "Prints this help") do
|
38
|
-
puts "Generates testbench in VHDL, from a given file containing an Entity-Architecture couple."
|
39
|
-
puts
|
40
|
-
puts opts
|
41
|
-
abort
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
begin
|
46
|
-
opt_parser.parse!(args)
|
47
|
-
@args=args
|
48
|
-
|
49
|
-
rescue Exception => e
|
50
|
-
puts e
|
51
|
-
#puts e.backtrace
|
52
|
-
exit
|
53
|
-
end
|
29
|
+
def parse_2 filename
|
30
|
+
@ast=Parser.new.parse_2 filename
|
31
|
+
pp @ast
|
54
32
|
end
|
55
33
|
|
56
|
-
def generate
|
34
|
+
def generate
|
57
35
|
@symtable=[]
|
58
36
|
@symtable << "clk"
|
59
37
|
@symtable << "reset_n"
|
60
38
|
@symtable << "sreset"
|
61
39
|
begin
|
62
|
-
analyze(entity_filename)
|
63
40
|
tb_txt=@engine.result(binding)
|
64
|
-
tb_filename="#{@tb.name}.vhd"
|
41
|
+
tb_filename="#{@tb.name}.vhd".downcase
|
65
42
|
File.open(tb_filename,'w'){|f| f.puts tb_txt}
|
66
43
|
puts "testbench generated : #{tb_filename}"
|
67
44
|
rescue Exception => e
|
@@ -72,15 +49,11 @@ module VHDL_TB
|
|
72
49
|
end
|
73
50
|
|
74
51
|
def analyze entity_filename
|
75
|
-
puts "analyzing VHDL file : #{entity_filename}"
|
76
|
-
|
77
|
-
root=Parser.new.parse entity_filename
|
78
|
-
|
79
52
|
#puts "parsed #{entity_filename}. Good."
|
80
|
-
@entity=
|
53
|
+
@entity=ast.design_units.find{|du| du.class==Entity}
|
81
54
|
puts "entity found : #{@entity.name} (#{@entity.ports.size} ports)"
|
82
55
|
|
83
|
-
@arch=
|
56
|
+
@arch=ast.design_units.find{|du| du.is_a? Architecture}
|
84
57
|
check
|
85
58
|
# prepare ERB through instance variables
|
86
59
|
@max_length=@entity.ports.map{|p| p.name.val.size}.max
|
data/lib/generic_parser.rb
CHANGED
@@ -18,8 +18,23 @@ class GenericParser
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
def maybe kind
|
22
|
+
if showNext.kind==kind
|
23
|
+
return acceptIt
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
21
28
|
def more?
|
22
29
|
!tokens.empty?
|
23
30
|
end
|
24
31
|
|
32
|
+
def lookahead n
|
33
|
+
showNext(k=n)
|
34
|
+
end
|
35
|
+
|
36
|
+
def niy
|
37
|
+
raise "NIY"
|
38
|
+
end
|
39
|
+
|
25
40
|
end
|
data/lib/lexer.rb
CHANGED
@@ -65,6 +65,7 @@ module VHDL_TB
|
|
65
65
|
keyword 'on'
|
66
66
|
keyword 'open'
|
67
67
|
keyword 'or'
|
68
|
+
keyword 'xor'
|
68
69
|
keyword 'others'
|
69
70
|
keyword 'out'
|
70
71
|
keyword 'package'
|
@@ -93,6 +94,7 @@ module VHDL_TB
|
|
93
94
|
keyword 'then'
|
94
95
|
keyword 'to'
|
95
96
|
keyword 'transport'
|
97
|
+
keyword 'time'
|
96
98
|
keyword 'type'
|
97
99
|
keyword 'unaffected'
|
98
100
|
keyword 'units'
|
@@ -105,37 +107,48 @@ module VHDL_TB
|
|
105
107
|
keyword 'with'
|
106
108
|
keyword 'xnor'
|
107
109
|
keyword 'xorkeyword '
|
110
|
+
keyword 'ns'
|
111
|
+
keyword 'ps'
|
112
|
+
keyword 'ms'
|
108
113
|
|
109
114
|
#.............................................................
|
110
|
-
token :comment
|
115
|
+
token :comment => /\A\-\-(.*)$/
|
116
|
+
|
111
117
|
token :selected_name => /\w+(\.\w+)+/ # /\S+\w+\.\w+/
|
112
|
-
token :
|
118
|
+
token :bit_string_literal => /([bB]|[oO]|[xX])"[^_]\w+"/
|
119
|
+
token :ident => /[a-zA-Z]\w*/
|
113
120
|
|
114
121
|
token :string_literal => /"[^"]*"/
|
115
122
|
token :char_literal => /'(\w+)'/
|
116
123
|
token :attribute_literal => /'(\w+)/
|
117
124
|
token :decimal_literal => /\d+(\.\d+)?(E([+-]?)\d+)?/
|
118
125
|
token :based_literal => /\d+#\w+(\.\w+)?#(E[+-]?\d+)/
|
119
|
-
token :bit_string_literal => /(b|o|x)"[^_]\w+"/
|
120
126
|
token :vassign => /\A\:\=/
|
127
|
+
token :sassign => /\A\<\=/
|
121
128
|
token :comma => /\A\,/
|
122
129
|
token :colon => /\A\:/
|
123
130
|
token :semicolon => /\A\;/
|
124
131
|
token :lparen => /\A\(/
|
125
132
|
token :rparen => /\A\)/
|
126
|
-
|
127
|
-
|
128
|
-
token :
|
133
|
+
|
134
|
+
# arith
|
135
|
+
token :add => /\A\+/
|
136
|
+
token :sub => /\A\-/
|
137
|
+
token :mul => /\A\*/
|
129
138
|
token :div => /\A\//
|
130
139
|
|
131
|
-
token :sassign => /\A\<\=/
|
132
140
|
token :imply => /\A\=\>/
|
141
|
+
# logical
|
133
142
|
token :eq => /\A\=/
|
134
|
-
token :ampersand => /\A\&/
|
135
143
|
token :neq => /\A\/\=/
|
136
144
|
token :gte => /\A\>\=/
|
137
145
|
token :gt => /\A\>/
|
138
146
|
token :lt => /\A\</
|
147
|
+
|
148
|
+
token :sassign => /\A\<\=/
|
149
|
+
|
150
|
+
token :ampersand => /\A\&/
|
151
|
+
|
139
152
|
token :urange => /\A<>/
|
140
153
|
token :dot => /\A\./
|
141
154
|
token :bar => /\|/
|
data/lib/parser.rb
CHANGED
@@ -32,6 +32,31 @@ module VHDL_TB
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def parse_2 filename
|
36
|
+
@tokens=lex(filename)
|
37
|
+
root=Root.new([])
|
38
|
+
while @tokens.any?
|
39
|
+
case showNext.kind
|
40
|
+
when :comment
|
41
|
+
root << acceptIt
|
42
|
+
when :library
|
43
|
+
root << parse_library
|
44
|
+
when :use
|
45
|
+
root << parse_use
|
46
|
+
when :entity
|
47
|
+
root << parse_entity
|
48
|
+
when :architecture
|
49
|
+
root << parse_architecture
|
50
|
+
when :package
|
51
|
+
root << parse_package
|
52
|
+
else
|
53
|
+
raise "got #{showNext}"
|
54
|
+
raise
|
55
|
+
end
|
56
|
+
end
|
57
|
+
root
|
58
|
+
end
|
59
|
+
|
35
60
|
def parse filename
|
36
61
|
@tokens=lex(filename)
|
37
62
|
#pp @tokens
|
@@ -39,10 +64,8 @@ module VHDL_TB
|
|
39
64
|
begin
|
40
65
|
consume_to :entity
|
41
66
|
root.design_units << entity=parse_entity
|
42
|
-
|
43
67
|
consume_to :architecture
|
44
68
|
root.design_units << archi=parse_architecture
|
45
|
-
|
46
69
|
rescue Exception => e
|
47
70
|
puts e.backtrace
|
48
71
|
puts e
|
@@ -61,46 +84,63 @@ module VHDL_TB
|
|
61
84
|
end
|
62
85
|
end
|
63
86
|
|
87
|
+
def parse_library
|
88
|
+
expect :library
|
89
|
+
expect :ident
|
90
|
+
while showNext.is_a?(:comma)
|
91
|
+
acceptIt
|
92
|
+
expeact :ident
|
93
|
+
end
|
94
|
+
expect :semicolon
|
95
|
+
end
|
96
|
+
|
97
|
+
def parse_use
|
98
|
+
expect :use
|
99
|
+
expect :selected_name
|
100
|
+
expect :semicolon
|
101
|
+
end
|
102
|
+
|
64
103
|
def parse_entity
|
65
104
|
entity=Entity.new(nil,nil,[])
|
66
105
|
expect :entity
|
67
|
-
entity.name=expect :
|
106
|
+
entity.name=expect :ident
|
68
107
|
expect :is
|
69
|
-
|
70
|
-
entity.generics=parse_generics
|
71
|
-
end
|
108
|
+
parse_generics?
|
72
109
|
if showNext.is_a? :port
|
73
110
|
entity.ports=parse_ports
|
74
111
|
end
|
75
112
|
expect :end
|
113
|
+
maybe :ident
|
76
114
|
if showNext.is_a? :semicolon
|
77
115
|
acceptIt
|
78
116
|
end
|
79
117
|
return entity
|
80
118
|
end
|
81
119
|
|
82
|
-
def parse_generics
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
120
|
+
def parse_generics?
|
121
|
+
if showNext.is_a? :generic
|
122
|
+
generics=[]
|
123
|
+
expect :generic
|
124
|
+
expect :lparen
|
125
|
+
while showNext.is_not_a? :rparen
|
126
|
+
generics << parse_generic
|
127
|
+
if showNext.is_a? :semicolon
|
128
|
+
acceptIt
|
129
|
+
end
|
90
130
|
end
|
131
|
+
expect :rparen
|
132
|
+
expect :semicolon
|
133
|
+
generics.flatten!
|
134
|
+
return generics
|
91
135
|
end
|
92
|
-
expect :rparen
|
93
|
-
expect :semicolon
|
94
|
-
generics.flatten!
|
95
|
-
generics
|
96
136
|
end
|
97
137
|
|
98
138
|
def parse_generic
|
99
139
|
ids=[]
|
100
|
-
ids << expect(:
|
140
|
+
ids << expect(:ident)
|
101
141
|
while showNext.is_a? :comma
|
102
142
|
acceptIt
|
103
|
-
ids << expect(:
|
143
|
+
ids << expect(:ident)
|
104
144
|
end
|
105
145
|
expect :colon
|
106
146
|
type=parse_type
|
@@ -129,13 +169,13 @@ module VHDL_TB
|
|
129
169
|
|
130
170
|
def parse_io
|
131
171
|
ids=[]
|
132
|
-
ids << expect(:
|
172
|
+
ids << expect(:ident)
|
133
173
|
while showNext.is_a? :comma
|
134
174
|
acceptIt
|
135
|
-
ids << expect(:
|
175
|
+
ids << expect(:ident)
|
136
176
|
end
|
137
177
|
expect :colon
|
138
|
-
if showNext.is_a? [:in,:out]
|
178
|
+
if showNext.is_a? [:in,:out,:inout]
|
139
179
|
dir=acceptIt
|
140
180
|
dir=dir.kind
|
141
181
|
end
|
@@ -146,8 +186,8 @@ module VHDL_TB
|
|
146
186
|
def parse_type
|
147
187
|
type=Identifier.new
|
148
188
|
case showNext.kind
|
149
|
-
when :
|
150
|
-
type.tok=
|
189
|
+
when :ident
|
190
|
+
type.tok=acceptIt
|
151
191
|
if showNext.is_a? :lparen
|
152
192
|
acceptIt
|
153
193
|
name=type.tok
|
@@ -166,36 +206,686 @@ module VHDL_TB
|
|
166
206
|
type
|
167
207
|
end
|
168
208
|
|
209
|
+
def parse_architecture
|
210
|
+
archi=Architecture.new
|
211
|
+
expect :architecture
|
212
|
+
archi.name=expect(:ident)
|
213
|
+
expect :of
|
214
|
+
archi.entity=expect(:ident)
|
215
|
+
expect :is
|
216
|
+
parse_archi_decls
|
217
|
+
parse_archi_body
|
218
|
+
archi
|
219
|
+
end
|
220
|
+
|
221
|
+
def parse_archi_decls
|
222
|
+
parse_decls
|
223
|
+
end
|
224
|
+
|
225
|
+
def parse_decls
|
226
|
+
decls=[]
|
227
|
+
while showNext.kind!=:begin and showNext.kind!=:end
|
228
|
+
case showNext.kind
|
229
|
+
when :constant
|
230
|
+
decls << parse_constant
|
231
|
+
when :type
|
232
|
+
decls << parse_typedecl
|
233
|
+
when :signal
|
234
|
+
decls << parse_signal
|
235
|
+
when :procedure
|
236
|
+
decls << parse_procedure
|
237
|
+
when :function
|
238
|
+
decls << parse_function
|
239
|
+
when :component
|
240
|
+
decls << parse_component_decl
|
241
|
+
when :attribute
|
242
|
+
decls << parse_attribute
|
243
|
+
when :variable
|
244
|
+
decls << parse_variable
|
245
|
+
else
|
246
|
+
raise "ERROR : parse_decls #{pp showNext}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
decls
|
250
|
+
end
|
251
|
+
|
252
|
+
def parse_constant
|
253
|
+
expect :constant
|
254
|
+
expect :ident
|
255
|
+
while showNext.is_a?(:comma)
|
256
|
+
acceptIt
|
257
|
+
expect :ident
|
258
|
+
end
|
259
|
+
expect :colon
|
260
|
+
parse_type
|
261
|
+
initialized?
|
262
|
+
expect :semicolon
|
263
|
+
end
|
264
|
+
|
265
|
+
def parse_typedecl
|
266
|
+
expect :type
|
267
|
+
expect :ident
|
268
|
+
expect :is
|
269
|
+
case showNext.kind
|
270
|
+
when :lparen
|
271
|
+
acceptIt
|
272
|
+
expect :ident
|
273
|
+
while showNext.is_a?(:comma)
|
274
|
+
acceptIt
|
275
|
+
expect :ident
|
276
|
+
end
|
277
|
+
expect :rparen
|
278
|
+
when :record
|
279
|
+
parse_record
|
280
|
+
else
|
281
|
+
raise "parse_typedecl : #{pp showNext}"
|
282
|
+
end
|
283
|
+
expect :semicolon
|
284
|
+
end
|
285
|
+
|
286
|
+
def parse_record
|
287
|
+
expect :record
|
288
|
+
while showNext.not_a?(:end)
|
289
|
+
parse_record_item
|
290
|
+
end
|
291
|
+
expect :end
|
292
|
+
expect :record
|
293
|
+
end
|
294
|
+
|
295
|
+
def parse_record_item
|
296
|
+
expect :ident
|
297
|
+
while showNext.is_a?(:comma)
|
298
|
+
acceptIt
|
299
|
+
expect :ident
|
300
|
+
end
|
301
|
+
expect :colon
|
302
|
+
parse_type
|
303
|
+
expect :semicolon
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
def parse_signal
|
308
|
+
expect :signal
|
309
|
+
expect :ident
|
310
|
+
while showNext.is_a?(:comma)
|
311
|
+
acceptIt
|
312
|
+
expect :ident
|
313
|
+
end
|
314
|
+
expect :colon
|
315
|
+
parse_type
|
316
|
+
initialized?
|
317
|
+
expect :semicolon
|
318
|
+
end
|
319
|
+
|
320
|
+
def parse_procedure
|
321
|
+
expect :procedure
|
322
|
+
expect :ident
|
323
|
+
if showNext.is_a?(:lparen)
|
324
|
+
acceptIt
|
325
|
+
parse_formal_parameters
|
326
|
+
expect :rparen
|
327
|
+
end
|
328
|
+
expect :is
|
329
|
+
parse_decls
|
330
|
+
expect :begin
|
331
|
+
parse_body
|
332
|
+
expect :end
|
333
|
+
expect :procedure
|
334
|
+
expect :semicolon
|
335
|
+
end
|
336
|
+
|
337
|
+
def parse_formal_parameters
|
338
|
+
ret=[]
|
339
|
+
parse_formal_parameter
|
340
|
+
while showNext.is_a?(:comma)
|
341
|
+
acceptIt
|
342
|
+
ret << parse_formal_parameter
|
343
|
+
end
|
344
|
+
ret.flatten!
|
345
|
+
ret
|
346
|
+
end
|
347
|
+
|
348
|
+
def parse_formal_parameter
|
349
|
+
expect :ident
|
350
|
+
while showNext.is_a?(:comma)
|
351
|
+
acceptIt
|
352
|
+
expect :ident
|
353
|
+
end
|
354
|
+
expect :colon
|
355
|
+
parse_type
|
356
|
+
end
|
357
|
+
|
358
|
+
def parse_function
|
359
|
+
expect :function
|
360
|
+
expect :ident
|
361
|
+
if showNext.is_a?(:lparen)
|
362
|
+
acceptIt
|
363
|
+
parse_formal_parameters
|
364
|
+
expect :rparen
|
365
|
+
end
|
366
|
+
|
367
|
+
expect :return
|
368
|
+
parse_type
|
369
|
+
|
370
|
+
unless showNext.is_a?(:semicolon)
|
371
|
+
expect :is
|
372
|
+
parse_decls
|
373
|
+
expect :begin
|
374
|
+
parse_body
|
375
|
+
expect :end
|
376
|
+
maybe :function
|
377
|
+
maybe :ident
|
378
|
+
end
|
379
|
+
expect :semicolon
|
380
|
+
end
|
381
|
+
|
382
|
+
def parse_component_decl
|
383
|
+
expect :component
|
384
|
+
expect :ident
|
385
|
+
expect :is
|
386
|
+
parse_generics?
|
387
|
+
parse_ports
|
388
|
+
expect :end
|
389
|
+
expect :component
|
390
|
+
expect :semicolon
|
391
|
+
end
|
392
|
+
|
393
|
+
def parse_attribute
|
394
|
+
expect :attribute
|
395
|
+
expect :ident
|
396
|
+
case showNext.kind
|
397
|
+
when :colon #declaration
|
398
|
+
acceptIt
|
399
|
+
parse_type
|
400
|
+
when :of # specification
|
401
|
+
acceptIt
|
402
|
+
expect :ident
|
403
|
+
expect :colon
|
404
|
+
consume_to :semicolon
|
405
|
+
else
|
406
|
+
raise "ERROR : parse_attribute #{showNext}"
|
407
|
+
end
|
408
|
+
expect :semicolon
|
409
|
+
end
|
410
|
+
|
411
|
+
def parse_variable
|
412
|
+
expect :variable
|
413
|
+
expect :ident
|
414
|
+
while showNext.is_a?(:comma)
|
415
|
+
acceptIt
|
416
|
+
expect :ident
|
417
|
+
end
|
418
|
+
expect :colon
|
419
|
+
parse_type
|
420
|
+
expect :semicolon
|
421
|
+
end
|
422
|
+
#======================================
|
423
|
+
def parse_archi_body
|
424
|
+
expect :begin
|
425
|
+
while !showNext.is_a?(:end)
|
426
|
+
parse_concurrent_stmt
|
427
|
+
end
|
428
|
+
expect :end
|
429
|
+
expect :ident
|
430
|
+
expect :semicolon
|
431
|
+
end
|
432
|
+
|
433
|
+
def parse_concurrent_stmt
|
434
|
+
parse_label?
|
435
|
+
case showNext.kind
|
436
|
+
when :process
|
437
|
+
parse_process
|
438
|
+
when :entity
|
439
|
+
parse_entity_instanciation
|
440
|
+
when :ident
|
441
|
+
parse_assign
|
442
|
+
when :component
|
443
|
+
parse_component_instanciation
|
444
|
+
else
|
445
|
+
raise "parse_concurrent_stmt : #{pp showNext}"
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def parse_label?
|
450
|
+
if lookahead(2).is_a?(:colon)
|
451
|
+
expect(:ident)
|
452
|
+
expect(:colon)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
def parse_process
|
457
|
+
expect :process
|
458
|
+
if showNext.is_a?(:lparen)
|
459
|
+
parse_sensitivity_list
|
460
|
+
end
|
461
|
+
parse_decls
|
462
|
+
expect :begin
|
463
|
+
parse_body
|
464
|
+
expect :end
|
465
|
+
expect :process
|
466
|
+
expect :semicolon
|
467
|
+
end
|
468
|
+
|
469
|
+
def parse_sensitivity_list
|
470
|
+
expect :lparen
|
471
|
+
expect :ident
|
472
|
+
while showNext.is_a?(:comma)
|
473
|
+
acceptIt
|
474
|
+
expect :ident
|
475
|
+
end
|
476
|
+
expect :rparen
|
477
|
+
end
|
478
|
+
|
479
|
+
def parse_component_instanciation
|
480
|
+
expect :component
|
481
|
+
expect :ident
|
482
|
+
parse_generic_map?
|
483
|
+
parse_port_map
|
484
|
+
expect :semicolon
|
485
|
+
end
|
486
|
+
|
487
|
+
def parse_generic_map?
|
488
|
+
if showNext.is_a? :generic
|
489
|
+
acceptIt
|
490
|
+
expect :map
|
491
|
+
expect :lparen
|
492
|
+
while !showNext.is_a?(:rparen)
|
493
|
+
parse_assoc
|
494
|
+
if showNext.is_a?(:comma)
|
495
|
+
acceptIt
|
496
|
+
end
|
497
|
+
end
|
498
|
+
expect :rparen
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
def parse_entity_instanciation
|
503
|
+
expect :entity
|
504
|
+
expect :selected_name
|
505
|
+
if showNext.is_a?(:lparen)
|
506
|
+
acceptIt
|
507
|
+
expect :ident
|
508
|
+
expect :rparen
|
509
|
+
end
|
510
|
+
parse_generic_map?
|
511
|
+
parse_port_map
|
512
|
+
expect :semicolon
|
513
|
+
end
|
514
|
+
|
515
|
+
def parse_port_map
|
516
|
+
expect :port
|
517
|
+
expect :map
|
518
|
+
expect :lparen
|
519
|
+
while !showNext.is_a?(:rparen)
|
520
|
+
parse_assoc
|
521
|
+
if showNext.is_a?(:comma)
|
522
|
+
acceptIt
|
523
|
+
end
|
524
|
+
end
|
525
|
+
expect :rparen
|
526
|
+
end
|
527
|
+
|
528
|
+
def parse_assoc
|
529
|
+
expect :ident
|
530
|
+
expect :imply
|
531
|
+
if showNext.is_a?(:open)
|
532
|
+
acceptIt
|
533
|
+
else
|
534
|
+
parse_expression
|
535
|
+
end
|
536
|
+
end
|
537
|
+
#============== package
|
538
|
+
|
539
|
+
def parse_package
|
540
|
+
expect :package
|
541
|
+
case showNext.kind
|
542
|
+
when :ident
|
543
|
+
parse_package_decl
|
544
|
+
when :body
|
545
|
+
parse_package_body
|
546
|
+
else
|
547
|
+
raise "ERROR : parse_package"
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
def parse_package_decl
|
552
|
+
expect :ident
|
553
|
+
expect :is
|
554
|
+
while !showNext.is_a?(:end)
|
555
|
+
parse_decls
|
556
|
+
end
|
557
|
+
expect :end
|
558
|
+
maybe :package
|
559
|
+
expect :semicolon
|
560
|
+
end
|
561
|
+
|
562
|
+
def parse_package_body
|
563
|
+
expect :body
|
564
|
+
expect :ident
|
565
|
+
expect :is
|
566
|
+
while !showNext.is_a?(:end)
|
567
|
+
parse_decls
|
568
|
+
end
|
569
|
+
expect :end
|
570
|
+
expect :package
|
571
|
+
expect :body
|
572
|
+
expect :semicolon
|
573
|
+
end
|
574
|
+
|
575
|
+
#============== body
|
576
|
+
def parse_body
|
577
|
+
while !showNext.is_a?(:end) and !showNext.is_a?(:elsif) and !showNext.is_a?(:else) and !showNext.is_a?(:when)
|
578
|
+
parse_seq_stmt
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
def parse_seq_stmt
|
583
|
+
#puts "parse_seq_stmt line #{showNext.pos.first}"
|
584
|
+
case showNext.kind
|
585
|
+
when :null
|
586
|
+
parse_null_stmt
|
587
|
+
when :if
|
588
|
+
parse_if_stmt
|
589
|
+
when :for
|
590
|
+
parse_for
|
591
|
+
when :while
|
592
|
+
parse_while
|
593
|
+
when :case
|
594
|
+
parse_case
|
595
|
+
when :wait
|
596
|
+
parse_wait
|
597
|
+
when :report
|
598
|
+
parse_report
|
599
|
+
when :return
|
600
|
+
parse_return
|
601
|
+
when :ident,:selected_name
|
602
|
+
parse_assign
|
603
|
+
else
|
604
|
+
raise "ERROR : parse_seq_stmt : #{pp showNext}"
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
def parse_null_stmt
|
609
|
+
expect :null
|
610
|
+
expect :semicolon
|
611
|
+
end
|
612
|
+
|
613
|
+
def parse_assign
|
614
|
+
parse_term
|
615
|
+
if showNext.is_a? [:vassign,:sassign]
|
616
|
+
acceptIt
|
617
|
+
end
|
618
|
+
|
619
|
+
parse_expression
|
620
|
+
|
621
|
+
while showNext.is_a?(:comma)
|
622
|
+
acceptIt
|
623
|
+
parse_expression
|
624
|
+
end
|
625
|
+
|
626
|
+
while showNext.is_a?(:when)
|
627
|
+
got_when=true
|
628
|
+
acceptIt
|
629
|
+
parse_expression
|
630
|
+
end
|
631
|
+
|
632
|
+
if got_when
|
633
|
+
expect :else
|
634
|
+
parse_expression
|
635
|
+
end
|
636
|
+
|
637
|
+
expect :semicolon
|
638
|
+
end
|
639
|
+
|
640
|
+
def parse_if_stmt
|
641
|
+
expect :if
|
642
|
+
parse_expression
|
643
|
+
expect :then
|
644
|
+
parse_body
|
645
|
+
while showNext.is_a?(:elsif)
|
646
|
+
parse_elsif
|
647
|
+
end
|
648
|
+
if showNext.is_a?(:else)
|
649
|
+
acceptIt
|
650
|
+
parse_body
|
651
|
+
end
|
652
|
+
expect :end
|
653
|
+
expect :if
|
654
|
+
expect :semicolon
|
655
|
+
end
|
656
|
+
|
657
|
+
def parse_elsif
|
658
|
+
expect :elsif
|
659
|
+
parse_expression
|
660
|
+
expect :then
|
661
|
+
parse_body
|
662
|
+
end
|
663
|
+
|
664
|
+
def parse_for
|
665
|
+
expect :for
|
666
|
+
expect :ident
|
667
|
+
expect :in
|
668
|
+
parse_expression
|
669
|
+
if showNext.is_a? :to
|
670
|
+
expect :to
|
671
|
+
parse_expression
|
672
|
+
end
|
673
|
+
expect :loop
|
674
|
+
parse_body
|
675
|
+
expect :end
|
676
|
+
expect :loop
|
677
|
+
expect :semicolon
|
678
|
+
end
|
679
|
+
|
680
|
+
def parse_while
|
681
|
+
niy
|
682
|
+
end
|
683
|
+
|
684
|
+
def parse_case
|
685
|
+
expect :case
|
686
|
+
parse_expression
|
687
|
+
expect :is
|
688
|
+
while showNext.is_a? :when
|
689
|
+
parse_when_case
|
690
|
+
end
|
691
|
+
expect :end
|
692
|
+
expect :case
|
693
|
+
expect :semicolon
|
694
|
+
end
|
695
|
+
|
696
|
+
def parse_when_case
|
697
|
+
expect :when
|
698
|
+
parse_expression
|
699
|
+
expect :imply
|
700
|
+
parse_body
|
701
|
+
end
|
702
|
+
|
703
|
+
def parse_wait
|
704
|
+
expect :wait
|
705
|
+
case showNext.kind
|
706
|
+
when :until
|
707
|
+
acceptIt
|
708
|
+
parse_expression
|
709
|
+
when :for
|
710
|
+
acceptIt
|
711
|
+
parse_expression
|
712
|
+
when :semicolon
|
713
|
+
else
|
714
|
+
raise "parse_wait : #{pp showNext}"
|
715
|
+
end
|
716
|
+
expect :semicolon
|
717
|
+
end
|
718
|
+
|
719
|
+
def parse_report
|
720
|
+
expect :report
|
721
|
+
parse_expression
|
722
|
+
expect :semicolon
|
723
|
+
end
|
724
|
+
|
725
|
+
def parse_return
|
726
|
+
expect :return
|
727
|
+
parse_expression
|
728
|
+
expect :semicolon
|
729
|
+
end
|
730
|
+
|
731
|
+
# ============================= expression ===============================
|
732
|
+
COMPARISON_OP=[:eq,:neq,:gt,:gte,:lt,:lte]
|
169
733
|
def parse_expression
|
170
|
-
|
171
|
-
while showNext.is_a?
|
734
|
+
t1=parse_additive
|
735
|
+
while more? && showNext.is_a?(COMPARISON_OP)
|
172
736
|
op=acceptIt
|
173
|
-
|
174
|
-
|
737
|
+
t2=parse_additive
|
738
|
+
t1=Binary.new(t1,op,t2)
|
739
|
+
end
|
740
|
+
return t1
|
741
|
+
end
|
742
|
+
|
743
|
+
ADDITIV_OP =[:add,:sub, :or, :xor] #xor ?
|
744
|
+
def parse_additive
|
745
|
+
t1=parse_multiplicative
|
746
|
+
while more? && showNext.is_a?(ADDITIV_OP)
|
747
|
+
op=acceptIt #full token
|
748
|
+
t2=parse_multiplicative
|
749
|
+
t1=Binary.new(t1,op,t2)
|
175
750
|
end
|
176
|
-
return
|
751
|
+
return t1
|
752
|
+
end
|
753
|
+
|
754
|
+
MULTITIV_OP=[:mul,:div,:mod,:and,:shiftr,:shiftl]
|
755
|
+
def parse_multiplicative
|
756
|
+
t1=parse_term
|
757
|
+
while more? && showNext.is_a?(MULTITIV_OP)
|
758
|
+
op=acceptIt
|
759
|
+
t2=parse_term
|
760
|
+
t1=Binary.new(t1,op,t2)
|
761
|
+
end
|
762
|
+
return t1
|
177
763
|
end
|
178
764
|
|
179
765
|
def parse_term
|
180
|
-
if showNext.is_a? [:decimal_literal,:
|
766
|
+
if showNext.is_a? [:ident,:selected_name,:decimal_literal,:char_literal,:string_literal,:bit_string_literal,:lparen,:others,:not,:sub]
|
181
767
|
case showNext.kind
|
768
|
+
when :ident
|
769
|
+
ret=Identifier.new(acceptIt)
|
770
|
+
when :lparen
|
771
|
+
ret=parse_parenth
|
772
|
+
when :not
|
773
|
+
ret=parse_unary
|
182
774
|
when :decimal_literal
|
183
|
-
|
184
|
-
when :
|
185
|
-
|
775
|
+
ret=IntLit.new(acceptIt)
|
776
|
+
when :char_literal
|
777
|
+
ret=acceptIt
|
778
|
+
when :string_literal,:bit_string_literal
|
779
|
+
ret=acceptIt
|
780
|
+
when :selected_name
|
781
|
+
ret=acceptIt
|
782
|
+
when :others
|
783
|
+
ret=acceptIt
|
186
784
|
else
|
187
|
-
puts "cannot parse term"
|
785
|
+
puts "cannot parse term : #{showNext}"
|
786
|
+
end
|
787
|
+
end
|
788
|
+
while showNext && showNext.is_a?([:lbrack,:attribute_literal,:lparen,:ns,:ps,:ms,:after,:ampersand])
|
789
|
+
if par=parenthesized?
|
790
|
+
#par.name=ret
|
791
|
+
ret=par
|
792
|
+
elsif attribute=attributed?
|
793
|
+
#attribute.lhs=ret
|
794
|
+
ret=attribute
|
795
|
+
elsif timed=timed?
|
796
|
+
timed.lhs=ret
|
797
|
+
ret=timed
|
798
|
+
elsif after=after?
|
799
|
+
#after.lhs=ret
|
800
|
+
ret=after
|
801
|
+
elsif concat=concat?
|
802
|
+
ret=concat
|
188
803
|
end
|
189
804
|
end
|
805
|
+
ret
|
190
806
|
end
|
191
807
|
|
192
|
-
|
193
|
-
|
194
|
-
expect :
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
808
|
+
# parenthesized expressions (NOT indexed or funcall)
|
809
|
+
def parse_parenth
|
810
|
+
expect :lparen
|
811
|
+
if showNext.is_a?(:others) # e.g : (others=>'0')
|
812
|
+
acceptIt
|
813
|
+
expect :imply
|
814
|
+
parse_expression
|
815
|
+
else
|
816
|
+
parse_expression
|
817
|
+
end
|
818
|
+
|
819
|
+
while showNext.is_a?(:comma) # aggregate
|
820
|
+
acceptIt
|
821
|
+
parse_expression
|
822
|
+
end
|
823
|
+
expect :rparen
|
824
|
+
end
|
825
|
+
|
826
|
+
def parse_unary
|
827
|
+
if showNext.is_a?([:not,:sub])
|
828
|
+
acceptIt
|
829
|
+
parse_expression
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
833
|
+
def timed?
|
834
|
+
if showNext.is_a? [:ps,:ns,:ms]
|
835
|
+
tok=acceptIt
|
836
|
+
ret=Timed.new(nil,tok)
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
def parenthesized?
|
841
|
+
if showNext.is_a? :lparen
|
842
|
+
acceptIt
|
843
|
+
ret=FuncCall.new
|
844
|
+
args=[]
|
845
|
+
while !showNext.is_a? :rparen
|
846
|
+
args << parse_expression()
|
847
|
+
while showNext.is_a? :comma
|
848
|
+
acceptIt
|
849
|
+
args << parse_expression()
|
850
|
+
end
|
851
|
+
if showNext.is_a? [:downto,:to] #slice !
|
852
|
+
acceptIt
|
853
|
+
parse_expression
|
854
|
+
end
|
855
|
+
end
|
856
|
+
expect :rparen
|
857
|
+
ret.actual_args = args
|
858
|
+
else
|
859
|
+
return false
|
860
|
+
end
|
861
|
+
return ret
|
862
|
+
end
|
863
|
+
|
864
|
+
def initialized?
|
865
|
+
if showNext.is_a?(:vassign)
|
866
|
+
acceptIt
|
867
|
+
parse_expression
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
def after?
|
872
|
+
if showNext.is_a?(:after)
|
873
|
+
acceptIt
|
874
|
+
parse_expression
|
875
|
+
end
|
876
|
+
end
|
877
|
+
|
878
|
+
def concat?
|
879
|
+
if showNext.is_a?(:ampersand)
|
880
|
+
acceptIt
|
881
|
+
parse_expression
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
def attributed?
|
886
|
+
if showNext.is_a?(:attribute_literal)
|
887
|
+
acceptIt
|
888
|
+
end
|
199
889
|
end
|
200
890
|
end
|
201
891
|
end
|
data/lib/runner.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require_relative "compiler"
|
4
|
+
|
5
|
+
module VHDL_TB
|
6
|
+
|
7
|
+
class Runner
|
8
|
+
|
9
|
+
def self.run *arguments
|
10
|
+
new.run(arguments)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run arguments
|
14
|
+
compiler=Compiler.new
|
15
|
+
compiler.options = args = parse_options(arguments)
|
16
|
+
if args[:parse_only]
|
17
|
+
filename=args[:vhdl_file]
|
18
|
+
compiler.parse_2 filename
|
19
|
+
elsif filename=args[:vhdl_file]
|
20
|
+
compiler.compile filename
|
21
|
+
else
|
22
|
+
puts "need a VHDL file : vhdl_tb [options] <file.vhd>"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def header
|
27
|
+
puts "VHDL utilities (#{VERSION})- (c) JC Le Lann 2016-20"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def parse_options(arguments)
|
32
|
+
header
|
33
|
+
|
34
|
+
parser = OptionParser.new
|
35
|
+
|
36
|
+
no_arguments=arguments.empty?
|
37
|
+
|
38
|
+
options = {}
|
39
|
+
|
40
|
+
parser.on("-h", "--help", "Show help message") do
|
41
|
+
puts parser
|
42
|
+
exit(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
parser.on("-p", "--parse", "parse only") do
|
46
|
+
options[:parse_only]=true
|
47
|
+
end
|
48
|
+
|
49
|
+
parser.on("--pp", "pretty print back source code ") do
|
50
|
+
options[:pp] = true
|
51
|
+
end
|
52
|
+
|
53
|
+
parser.on("--ast", "abstract syntax tree (AST)") do
|
54
|
+
options[:ast] = true
|
55
|
+
end
|
56
|
+
|
57
|
+
parser.on("--check", "elaborate and check types") do
|
58
|
+
options[:check] = true
|
59
|
+
end
|
60
|
+
|
61
|
+
parser.on("--draw_ast", "draw abstract syntax tree (AST)") do
|
62
|
+
options[:draw_ast] = true
|
63
|
+
end
|
64
|
+
|
65
|
+
parser.on("--dummy_transform", "dummy ast transform") do
|
66
|
+
options[:dummy_transform] = true
|
67
|
+
end
|
68
|
+
|
69
|
+
parser.on("--vv", "verbose") do
|
70
|
+
options[:verbose] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
parser.on("-v", "--version", "Show version number") do
|
74
|
+
puts VERSION
|
75
|
+
exit(true)
|
76
|
+
end
|
77
|
+
|
78
|
+
parser.parse!(arguments)
|
79
|
+
|
80
|
+
options[:vhdl_file]=arguments.shift #the remaining c file
|
81
|
+
|
82
|
+
if no_arguments
|
83
|
+
puts parser
|
84
|
+
end
|
85
|
+
|
86
|
+
options
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/token.rb
CHANGED
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vhdl_tb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean-Christophe Le Lann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A simple testbench generator for VHDL
|
14
14
|
email: jean-christophe.le_lann@ensta-bretagne.fr
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- lib/generic_parser.rb
|
27
27
|
- lib/lexer.rb
|
28
28
|
- lib/parser.rb
|
29
|
+
- lib/runner.rb
|
29
30
|
- lib/template.tb.vhd
|
30
31
|
- lib/token.rb
|
31
32
|
- lib/version.rb
|