HDLRuby 3.3.4 → 3.5.0
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/HDLRuby.gemspec +1 -0
- data/README.md +78 -7
- data/exe/v2hdr +3 -0
- data/ext/hruby_sim/hruby_rcsim_build.c +1 -0
- data/lib/HDLRuby/hdr_samples/adder8.v +6 -0
- data/lib/HDLRuby/hdr_samples/hard_to_route.rb +30 -0
- data/lib/HDLRuby/hdr_samples/sw_encrypt_bench.rb +2 -0
- data/lib/HDLRuby/hdr_samples/sw_encrypt_cpu_bench.rb +2 -0
- data/lib/HDLRuby/hdr_samples/sw_encrypt_cpusim_bench.rb +2 -0
- data/lib/HDLRuby/hdr_samples/verilog_parser_bench.rb +36 -0
- data/lib/HDLRuby/hdr_samples/with_generic_in_generic.rb +31 -0
- data/lib/HDLRuby/hdr_samples/with_handshake.rb +2 -0
- data/lib/HDLRuby/hdr_samples/with_memory.rb +2 -0
- data/lib/HDLRuby/hdr_samples/with_nand_board.rb +1 -1
- data/lib/HDLRuby/hdr_samples/with_reconf.rb +1 -0
- data/lib/HDLRuby/hdr_samples/with_seq_case.rb +28 -0
- data/lib/HDLRuby/hdr_samples/with_seq_if.rb +25 -0
- data/lib/HDLRuby/hdr_samples/with_seq_if_succ.rb +27 -0
- data/lib/HDLRuby/hdr_samples/with_verilog.rb +24 -0
- data/lib/HDLRuby/hdrcc.rb +84 -27
- data/lib/HDLRuby/hruby_bstr.rb +2 -2
- data/lib/HDLRuby/hruby_high.rb +80 -24
- data/lib/HDLRuby/hruby_low.rb +4 -0
- data/lib/HDLRuby/hruby_tools.rb +0 -1
- data/lib/HDLRuby/hruby_viz.rb +5060 -0
- data/lib/HDLRuby/std/sequencer.rb +28 -13
- data/lib/HDLRuby/v2hdr.rb +39 -0
- data/lib/HDLRuby/verilog_hruby.rb +1153 -0
- data/lib/HDLRuby/verilog_parser.rb +7293 -0
- data/lib/HDLRuby/version.rb +1 -1
- data/tuto/tutorial_sw.html +2772 -4079
- data/tuto/tutorial_sw.md +89 -5
- metadata +17 -6
@@ -0,0 +1,1153 @@
|
|
1
|
+
require "HDLRuby/verilog_parser"
|
2
|
+
|
3
|
+
# Generate HDLRuby code from a Verilog HDL AST (produced from
|
4
|
+
# verilog_parser.rb)
|
5
|
+
|
6
|
+
module VerilogTools
|
7
|
+
|
8
|
+
# The possible levels in HDLRuby generation.
|
9
|
+
HDLRubyLevels = [ :top, :system, :hdef, :<=, :seq, :par, :timed, :expr ]
|
10
|
+
NoEventLevels = [ :hdef, :<=, :seq, :par, :timed ]
|
11
|
+
NoTimeLevels = [ :hdef, :<=, :seq, :par ]
|
12
|
+
|
13
|
+
# HDLRuby generation state.
|
14
|
+
class HDLRubyState
|
15
|
+
# String to add at new line for indent.
|
16
|
+
attr_reader :indent
|
17
|
+
|
18
|
+
# The current level in HDLRuby generation.
|
19
|
+
attr_reader :level
|
20
|
+
|
21
|
+
# The names of the ports of the current module.
|
22
|
+
attr_reader :port_names
|
23
|
+
|
24
|
+
# The default state.
|
25
|
+
DEFAULT = HDLRubyState.new
|
26
|
+
|
27
|
+
# Create a new state.
|
28
|
+
def initialize
|
29
|
+
@indent = "" # String to add at new line for indent.
|
30
|
+
@level = :top # Current level in HDLRuby generation.
|
31
|
+
@port_names = [] # The names of the ports of the current module.
|
32
|
+
end
|
33
|
+
|
34
|
+
# Set the indent string.
|
35
|
+
def indent=(str)
|
36
|
+
@indent = str.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set the level in HDLRuby generation
|
40
|
+
def level=(level)
|
41
|
+
unless HDLRubyLevels.include?(level)
|
42
|
+
raise "Internal error, unknown generation level #{level}"
|
43
|
+
end
|
44
|
+
@level = level
|
45
|
+
end
|
46
|
+
|
47
|
+
# Sets the port names.
|
48
|
+
def port_names=(port_names)
|
49
|
+
@port_names = port_names.to_a
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Tool for gathering the names of ports.
|
55
|
+
def self.get_port_names(ports)
|
56
|
+
return [] unless ports
|
57
|
+
return [] if ports.is_a?(AST) and ports.type == :property
|
58
|
+
if ports.respond_to?(:map) then
|
59
|
+
return ports.map {|p| VerilogTools.get_port_names(p) }.flatten
|
60
|
+
else
|
61
|
+
if ports.is_a?(String) then
|
62
|
+
return [ ports ]
|
63
|
+
else
|
64
|
+
return []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Tool for checking if a statement is to be seq or par in HDLRuby
|
71
|
+
def self.get_seq_par(statement)
|
72
|
+
case statement.type
|
73
|
+
when :blocking_asignment
|
74
|
+
return :seq
|
75
|
+
when :non_blocking_assignment
|
76
|
+
return :par
|
77
|
+
when :statement
|
78
|
+
statement.each do |child|
|
79
|
+
next unless child.is_a?(AST)
|
80
|
+
seq_par = VerilogTools.get_seq_par(child)
|
81
|
+
return seq_par if seq_par
|
82
|
+
end
|
83
|
+
return nil
|
84
|
+
else
|
85
|
+
return nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Tool for getting the name of a statement if any.
|
90
|
+
def self.get_name(statement)
|
91
|
+
case statement.type
|
92
|
+
when :seq_block, :par_block
|
93
|
+
name = statement[0]
|
94
|
+
name_txt = name ? name.to_HDLRuby(HDLRubyState::DEFAULT) : ""
|
95
|
+
return name_txt
|
96
|
+
when :statement
|
97
|
+
statement.each do |child|
|
98
|
+
next unless child.is_a?(AST)
|
99
|
+
seq_par = VerilogTools.get_name(child)
|
100
|
+
return seq_par if seq_par
|
101
|
+
end
|
102
|
+
else
|
103
|
+
return ""
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# Converts a Verilog HDL name to a HDLRuby one.
|
109
|
+
def self.name_to_HDLRuby(name)
|
110
|
+
if name[0] =~ /[_$A-Z]/ then
|
111
|
+
# HDLRuby names cannot start with a $ or a capital letter.
|
112
|
+
# To fix that add an "_", but then to avoid confusion, also
|
113
|
+
# convert starting "_" to "__" if any.
|
114
|
+
return "_" + name
|
115
|
+
else
|
116
|
+
return name
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Converts a Verilog HDL system task to a HDLRuby one.
|
121
|
+
def self.system_to_HDLRuby(name,args)
|
122
|
+
case name
|
123
|
+
when "$signed"
|
124
|
+
return "(#{args}).as(signed[(#{args}).type.width])"
|
125
|
+
when "$display"
|
126
|
+
return "hprint(#{args})"
|
127
|
+
when "$finish"
|
128
|
+
return "terminate"
|
129
|
+
else
|
130
|
+
raise "Internal error: unsupported system task #{name} yet."
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Converts a Verilog HDL operator to a HDLRuby one.
|
136
|
+
def self.operator_to_HDLRuby(op)
|
137
|
+
case op
|
138
|
+
when "!"
|
139
|
+
return "~"
|
140
|
+
when "&&"
|
141
|
+
return "&"
|
142
|
+
when "||"
|
143
|
+
return "|"
|
144
|
+
when "~&"
|
145
|
+
return ".send(:~) | ~"
|
146
|
+
when "~|"
|
147
|
+
return ".send(:~) & ~"
|
148
|
+
when "~^"
|
149
|
+
return "^~"
|
150
|
+
when "^|"
|
151
|
+
return "^"
|
152
|
+
else
|
153
|
+
return op
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# The class describing generation errors.
|
159
|
+
class GenerateError < StandardError
|
160
|
+
|
161
|
+
# Create a new parse error with message +msg+, faulty line number
|
162
|
+
# +lpos+, and possibly file name +filename+.
|
163
|
+
def initialize(msg,lpos,filename)
|
164
|
+
@msg = msg.to_s
|
165
|
+
@lpos = lpos.to_i
|
166
|
+
@filename = filename.to_s if filename
|
167
|
+
super(self.make_message)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Generate the error message.
|
171
|
+
# NOTE: if you want to translate the error message, please
|
172
|
+
# redefine the function.
|
173
|
+
def make_message
|
174
|
+
if @filename then
|
175
|
+
head = "Generation error for file '#{@filename}' "
|
176
|
+
else
|
177
|
+
head = "Generation error "
|
178
|
+
end
|
179
|
+
return head + "line #{@lpos}: " + @msg + "."
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
class AST
|
185
|
+
|
186
|
+
# Generate HDLRuby text from the current AST node.
|
187
|
+
# +state+ is the HDLRuby generation state.
|
188
|
+
def to_HDLRuby(state = HDLRubyState.new)
|
189
|
+
# Execute the generation procedure corresponding to the type.
|
190
|
+
return TO_HDLRuby[self.type].(self,state)
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
# Generate a generation error with message indicated by +msg+.
|
195
|
+
def generate_error(msg)
|
196
|
+
property = self[-1]
|
197
|
+
lpos = property[:lpos]
|
198
|
+
filename = property[:filename]
|
199
|
+
# Raise an exception containing an error message made of msg,
|
200
|
+
# the adjusted line number, its number, and the column where error
|
201
|
+
# happended.
|
202
|
+
raise GenerateError.new(msg,lpos,filename)
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
# The types of ports declaration in module ports and items.
|
207
|
+
PORT_DECLS = [ :input_declaration, :output_declaration,
|
208
|
+
:inout_declaration ]
|
209
|
+
|
210
|
+
# The generation procedures.
|
211
|
+
TO_HDLRuby = Hash.new( lambda do |ast,state|
|
212
|
+
# By default, recurse on the children.
|
213
|
+
return ast.map do |child|
|
214
|
+
if child.is_a?(Array) then
|
215
|
+
child.map do |sub|
|
216
|
+
sub.is_a?(AST) ? sub.to_HDLRuby(state) : sub.to_s
|
217
|
+
end.join
|
218
|
+
elsif child.is_a?(AST) then
|
219
|
+
child.to_HDLRuby(state)
|
220
|
+
else
|
221
|
+
child
|
222
|
+
end
|
223
|
+
end.join
|
224
|
+
end)
|
225
|
+
|
226
|
+
|
227
|
+
# Properties should not produce anything.
|
228
|
+
TO_HDLRuby[:property] = lambda { |ast, state| return "" }
|
229
|
+
|
230
|
+
|
231
|
+
TO_HDLRuby[:module] = lambda do |ast,state|
|
232
|
+
# Save and update the state.
|
233
|
+
indent = state.indent
|
234
|
+
level = state.level
|
235
|
+
state.indent += " "
|
236
|
+
state.level = :system
|
237
|
+
# Generate the name.
|
238
|
+
name = ast[0].to_HDLRuby
|
239
|
+
# Generate the generic parameters if any.
|
240
|
+
parameters = ast[1]
|
241
|
+
parameters = parameters ? parameters.to_HDLRuby(state) : ""
|
242
|
+
# Generate the ports.
|
243
|
+
# From the port declaration.
|
244
|
+
ports = ast[2]
|
245
|
+
ports = ports ? ports[0].map {|p| p.to_HDLRuby(state) } : []
|
246
|
+
# Remove the empty ports.
|
247
|
+
ports.select! {|p| !p.empty? }
|
248
|
+
# From the items, for that separate port declarations from others.
|
249
|
+
pitems, items = ast[3].partition {|i| PORT_DECLS.include?(i.type) }
|
250
|
+
ports += pitems.map {|p| p.to_HDLRuby(state) }
|
251
|
+
# Gather the port names to skip the redeclarations.
|
252
|
+
state.port_names = VerilogTools.get_port_names(pitems)
|
253
|
+
# Generate the items.
|
254
|
+
items = items.map do |i|
|
255
|
+
res = i.to_HDLRuby(state)
|
256
|
+
res
|
257
|
+
end
|
258
|
+
# Generate the module text.
|
259
|
+
res = indent + "system :" + name + " do " + parameters + "\n" +
|
260
|
+
ports.join + items.join + indent + "end\n"
|
261
|
+
# Restores the state.
|
262
|
+
state.indent = indent
|
263
|
+
state.level = level
|
264
|
+
state.port_names = []
|
265
|
+
# Returns the resulting string.
|
266
|
+
return res
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
TO_HDLRuby[:pre_parameter_declaration] = lambda do |ast,state|
|
271
|
+
return "|" + ast[0].to_HDLRuby(state) + "|"
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
TO_HDLRuby[:list_of_param_assignments] = lambda do |ast,state|
|
276
|
+
return ast[0].map {|p| p.to_HDLRuby(state) }.join(", ")
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
TO_HDLRuby[:param_assignment] = lambda do |ast,state|
|
281
|
+
return ast[0].to_HDLRuby(state) + "=" + ast[1].to_HDLRuby(state)
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
TO_HDLRuby[:list_of_ports] = lambda do |ast,state|
|
286
|
+
return ast.map { |p| p.to_HDLRuby(state) }.join("\n")
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
TO_HDLRuby[:port] = lambda do |ast,state|
|
291
|
+
p = ast[0]
|
292
|
+
return "" unless p
|
293
|
+
if p.type == :port_expression then
|
294
|
+
return p.to_HDLRuby(state)
|
295
|
+
else
|
296
|
+
v = ast[1]
|
297
|
+
return p.to_HDLRuby(state) + ": " + v ? v.to_HDLRuby(state) : ""
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
|
302
|
+
TO_HDLRuby[:port_expression] = lambda do |ast,state|
|
303
|
+
port = ast[0]
|
304
|
+
if port.is_a?(Array) then
|
305
|
+
return port.map {|p| p.to_HDLRuby(state) }.join("\n")
|
306
|
+
else
|
307
|
+
return port.to_HDLRuby(state)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
TO_HDLRuby[:input_port_declaration] = lambda do |ast,state|
|
313
|
+
# Ignore the INPUTTYPE not used in HDLRuby
|
314
|
+
# Get the sign if any.
|
315
|
+
sign = ast[1]
|
316
|
+
sign = "" unless sign
|
317
|
+
# Get the range.
|
318
|
+
range = ast[2]
|
319
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
320
|
+
# Get the name.
|
321
|
+
name = ast[3].to_HDLRuby(state)
|
322
|
+
# Genereate the resulting declaration.
|
323
|
+
return state.indent + sign + range +"input :" + name + "\n"
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
TO_HDLRuby[:output_port_declaration] = lambda do |ast,state|
|
328
|
+
# Ignore the OUTPUTTYPE not used in HDLRuby
|
329
|
+
# Get the sign if any.
|
330
|
+
sign = ast[1]
|
331
|
+
sign = "" unless sign
|
332
|
+
# Get the range.
|
333
|
+
range = ast[2]
|
334
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
335
|
+
# Get the name.
|
336
|
+
name = ast[3].to_HDLRuby(state)
|
337
|
+
# Genereate the resulting declaration.
|
338
|
+
return state.indent + sign + range +"output :" + name + "\n"
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
TO_HDLRuby[:inout_port_declaration] = lambda do |ast,state|
|
343
|
+
# Ignore the INOUTTYPE not used in HDLRuby
|
344
|
+
# Get the sign if any.
|
345
|
+
sign = ast[1]
|
346
|
+
sign = "" unless sign
|
347
|
+
# Get the range.
|
348
|
+
range = ast[2]
|
349
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
350
|
+
# Get the name.
|
351
|
+
name = ast[3].to_HDLRuby(state)
|
352
|
+
# Genereate the resulting declaration.
|
353
|
+
return state.indent + sign + range +"inout :" + name + "\n"
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
TO_HDLRuby[:port_reference] = lambda do |ast,state|
|
358
|
+
# Port reference are actually ignored since they are redeclared
|
359
|
+
# afterward (or are they?).
|
360
|
+
return ""
|
361
|
+
end
|
362
|
+
|
363
|
+
|
364
|
+
TO_HDLRuby[:task] = lambda do |ast,state|
|
365
|
+
# Save and update the state.
|
366
|
+
indent = state.indent
|
367
|
+
level = state.level
|
368
|
+
state.indent += " "
|
369
|
+
state.level = :hdef
|
370
|
+
# Generate the task text (function defintion in HDLRuby).
|
371
|
+
res = indent + "hdef :" + ast[0].to_HDLRuby +
|
372
|
+
" do |" + ast[1].to_HDLRuby + "|\n" +
|
373
|
+
state.indent + ast[2].to_HDLRuby(state.indent) + indent + "end\n"
|
374
|
+
# Restores the state.
|
375
|
+
state.indent = indent
|
376
|
+
state.level = level
|
377
|
+
# Returns the resulting string.
|
378
|
+
return res
|
379
|
+
end
|
380
|
+
|
381
|
+
|
382
|
+
TO_HDLRuby[:function] = lambda do |ast,state|
|
383
|
+
# Save and update the state.
|
384
|
+
indent = state.indent
|
385
|
+
level = state.level
|
386
|
+
state.indent += " "
|
387
|
+
state.level = :hdef
|
388
|
+
# Generate the function text.
|
389
|
+
# The return type is ignored for HDLRuby.
|
390
|
+
res = indent + "hdef :" + ast[1].to_HDLRuby(state) +
|
391
|
+
" do |" + ast[2].map{|p| p.to_HDLRuby(state)}.join(",") + "|\n" +
|
392
|
+
state.indent + ast[3].to_HDLRuby(state) + indent + "end\n"
|
393
|
+
# Restores the state.
|
394
|
+
state.indent = indent
|
395
|
+
state.level = level
|
396
|
+
# Returns the resulting string.
|
397
|
+
return res
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
TO_HDLRuby[:list_of_param_assignments] = lambda do |ast,state|
|
402
|
+
return ast[0].map {|p| p.to_HDLRuby(state) }.join
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
TO_HDLRuby[:param_assignment] = lambda do |ast,state|
|
407
|
+
return state.indent + ast[0].to_HDLRuby(state) + " = " +
|
408
|
+
ast[1].to_HDLRuby(state) + "\n"
|
409
|
+
end
|
410
|
+
|
411
|
+
|
412
|
+
TO_HDLRuby[:input_declaration] = lambda do |ast,state|
|
413
|
+
# Ignore the INPUTTYPE not used in HDLRuby
|
414
|
+
# Get the sign if any.
|
415
|
+
sign = ast[1]
|
416
|
+
sign = "" unless sign
|
417
|
+
# Get the range.
|
418
|
+
range = ast[2]
|
419
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
420
|
+
# Get the names.
|
421
|
+
names = ast[3].to_HDLRuby(state)
|
422
|
+
# Genereate the resulting declaration.
|
423
|
+
if state.level == :hdef then
|
424
|
+
# Specific case of function argument: ignore the types, and
|
425
|
+
# do not add new line no indent.
|
426
|
+
return names.gsub(":","")
|
427
|
+
else
|
428
|
+
# General case
|
429
|
+
return state.indent + sign + range +"input " + names + "\n"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
|
434
|
+
TO_HDLRuby[:output_declaration] = lambda do |ast,state|
|
435
|
+
# Ignore the OUTPUTTYPE not used in HDLRuby
|
436
|
+
# Get the sign if any.
|
437
|
+
sign = ast[1]
|
438
|
+
sign = "" unless sign
|
439
|
+
# Get the range.
|
440
|
+
range = ast[2]
|
441
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
442
|
+
# Get the names.
|
443
|
+
names = ast[3].to_HDLRuby(state)
|
444
|
+
# Genereate the resulting declaration.
|
445
|
+
return state.indent + sign + range +"output " + names + "\n"
|
446
|
+
end
|
447
|
+
|
448
|
+
|
449
|
+
TO_HDLRuby[:inout_declaration] = lambda do |ast,state|
|
450
|
+
# Ignore the INOUTTYPE not used in HDLRuby
|
451
|
+
# Get the sign if any.
|
452
|
+
sign = ast[1]
|
453
|
+
sign = "" unless sign
|
454
|
+
# Get the range.
|
455
|
+
range = ast[2]
|
456
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
457
|
+
# Get the names.
|
458
|
+
names = ast[3].to_HDLRuby(state)
|
459
|
+
# Generate the resulting declaration.
|
460
|
+
return state.indent + sign + range + "inout " + names + "\n"
|
461
|
+
end
|
462
|
+
|
463
|
+
|
464
|
+
TO_HDLRuby[:net_declaration] = lambda do |ast,state|
|
465
|
+
# Ignore the NETTYPE which is not required in HDLRuby.
|
466
|
+
# Get the sign if any.
|
467
|
+
sign = ast[1]
|
468
|
+
sign = "" unless sign
|
469
|
+
# Get the expandrange if any.
|
470
|
+
expandrange = ast[2]
|
471
|
+
expandrange = expandrange ? expandrange.to_HDLRuby(state) + "." : ""
|
472
|
+
# Get the delay.
|
473
|
+
delay = delay ? ast[3].to_HDLRuby(state) : ""
|
474
|
+
if delay[0] then
|
475
|
+
raise "Internal error: delay in wire declaration not supported yet."
|
476
|
+
end
|
477
|
+
# Get the names.
|
478
|
+
names = ast[4].to_HDLRuby(state)
|
479
|
+
if names.empty? then
|
480
|
+
# There is actually no new inner.
|
481
|
+
return ""
|
482
|
+
end
|
483
|
+
# Generate the resulting declaration.
|
484
|
+
return state.indent + sign + expandrange + "inner " + names + "\n"
|
485
|
+
end
|
486
|
+
|
487
|
+
|
488
|
+
TO_HDLRuby[:reg_declaration] = lambda do |ast,state|
|
489
|
+
# Get the sign if any.
|
490
|
+
sign = ast[0]
|
491
|
+
sign = "" unless sign
|
492
|
+
# Get the range.
|
493
|
+
range = ast[1]
|
494
|
+
range = range ? range.to_HDLRuby(state) + "." : ""
|
495
|
+
# # Get the name.
|
496
|
+
# names = ast[2].to_HDLRuby(state)
|
497
|
+
# if names.empty? then
|
498
|
+
# # There is actually no new inner.
|
499
|
+
# return ""
|
500
|
+
# end
|
501
|
+
# Registers can also be memory, so treat each name independantly.
|
502
|
+
# # Genereate the resulting declaration.
|
503
|
+
# return state.indent + sign + range +"inner " + names + "\n"
|
504
|
+
res_txt = ""
|
505
|
+
ast[2][0].each do |reg|
|
506
|
+
if reg[0].type == :name_of_memory then
|
507
|
+
# It is a memory, it must be declared.
|
508
|
+
sign = "bit" if sign.empty?
|
509
|
+
res_txt += state.indent + sign + range[0..-2] +
|
510
|
+
"[" + reg[1].to_HDLRuby(state) + ".." +
|
511
|
+
reg[2].to_HDLRuby(state) + "].inner :" +
|
512
|
+
reg[0].to_HDLRuby(state) + "\n"
|
513
|
+
else
|
514
|
+
# It is a standard register, it may override a previous
|
515
|
+
# declaration and in such case can be omitted in HDLRuby.
|
516
|
+
n = reg[0].to_HDLRuby(state)
|
517
|
+
unless state.port_names.include?(n) then
|
518
|
+
res_txt += state.indent + sign + range + "inner :" + n + "\n"
|
519
|
+
end
|
520
|
+
end
|
521
|
+
end
|
522
|
+
return res_txt
|
523
|
+
end
|
524
|
+
|
525
|
+
|
526
|
+
TO_HDLRuby[:continuous_assignment] = lambda do |ast,state|
|
527
|
+
if ast[0] != "assign" then
|
528
|
+
raise "Internal error: unsupported continous assignment: #{ast[0]}"
|
529
|
+
end
|
530
|
+
if ast[1] then
|
531
|
+
raise "Internal error: drive strength not support yet #{ast[1]}"
|
532
|
+
end
|
533
|
+
if ast[2] then
|
534
|
+
raise "Internal error: expandrange in continous assignment not support yet #{ast[2]}"
|
535
|
+
end
|
536
|
+
if ast[3] then
|
537
|
+
raise "Internal error: delay in continous assignment not support yet #{ast[3]}"
|
538
|
+
end
|
539
|
+
return ast[4].to_HDLRuby(state)
|
540
|
+
end
|
541
|
+
|
542
|
+
|
543
|
+
# TO_HDLRuby[:list_of_variables] = lambda do |ast,state|
|
544
|
+
# return ast[0].map {|n| ":#{n.to_HDLRuby(state)}" }.join(", ")
|
545
|
+
# end
|
546
|
+
|
547
|
+
|
548
|
+
TO_HDLRuby[:list_of_variables] = lambda do |ast,state|
|
549
|
+
# Auth: variables that have already been declared are ignored
|
550
|
+
# since in HDLRuby all variables are identical.
|
551
|
+
return ast[0].map do |n|
|
552
|
+
n = n.to_HDLRuby(state)
|
553
|
+
if state.port_names.include?(n) then
|
554
|
+
nil
|
555
|
+
else
|
556
|
+
":#{n}"
|
557
|
+
end
|
558
|
+
end.compact.join(", ")
|
559
|
+
end
|
560
|
+
|
561
|
+
|
562
|
+
TO_HDLRuby[:list_of_register_variables] = TO_HDLRuby[:list_of_variables]
|
563
|
+
|
564
|
+
|
565
|
+
TO_HDLRuby[:initial_statement] = lambda do |ast,state|
|
566
|
+
# Translated to a timed block.
|
567
|
+
head_txt = state.indent + "timed do\n"
|
568
|
+
# Save and update the state.
|
569
|
+
indent = state.indent
|
570
|
+
level = state.level
|
571
|
+
state.indent += " "
|
572
|
+
state.level = :timed
|
573
|
+
# Generate the content.
|
574
|
+
content_txt = ast[0].to_HDLRuby(state)
|
575
|
+
# Restore the state and generate the final result.
|
576
|
+
state.indent = indent
|
577
|
+
state.level = level
|
578
|
+
return head_txt + content_txt + state.indent + "end\n"
|
579
|
+
end
|
580
|
+
|
581
|
+
|
582
|
+
TO_HDLRuby[:always_statement] = lambda do |ast,state|
|
583
|
+
# Get the head statement.
|
584
|
+
head = ast[0]
|
585
|
+
head = head[0] while head[0].is_a?(AST) and head[0].type == :statement
|
586
|
+
# Get its synchronization if any.
|
587
|
+
event_txt = ""
|
588
|
+
delay_txt = ""
|
589
|
+
# Check if there is a delay or an event control,
|
590
|
+
# and generate the corresponding text if possible in the
|
591
|
+
# current generation state.
|
592
|
+
if head[0].type == :delay_or_event_control then
|
593
|
+
delay_or_event_control = head[0]
|
594
|
+
# There is a delay or an event, process it, and
|
595
|
+
# update the current statement (i.e. ast) to its second child.
|
596
|
+
delay_or_event_control = delay_or_event_control[0]
|
597
|
+
# For event.
|
598
|
+
if delay_or_event_control.type == :event_control then
|
599
|
+
if NoEventLevels.include?(state.level) then
|
600
|
+
ast.generate_error("there should not be an event here")
|
601
|
+
end
|
602
|
+
# Support, generate the event control text.
|
603
|
+
event_txt = delay_or_event_control.to_HDLRuby(state)
|
604
|
+
# For delay.
|
605
|
+
elsif delay_or_event_control.type == :delay_control then
|
606
|
+
# if NoTimeLevels.include?(state.level) then
|
607
|
+
# ast.generate_error("there should not be a delay here")
|
608
|
+
# end
|
609
|
+
# Supported, generate the delay control text.
|
610
|
+
delay_txt = delay_or_event_control.to_HDLRuby(state)
|
611
|
+
end
|
612
|
+
# Update the head statement.
|
613
|
+
head = head[1]
|
614
|
+
end
|
615
|
+
# Get the name if any.
|
616
|
+
name_txt = VerilogTools.get_name(head)
|
617
|
+
if delay_txt[0] then
|
618
|
+
# It will become a timed process with an infinite loop.
|
619
|
+
decl_txt = state.indent + "timed do\n" +
|
620
|
+
state.indent + " repeat(-1) do\n" +
|
621
|
+
" " + delay_txt
|
622
|
+
end_txt = state.indent + " end\n" + state.indent + "end\n"
|
623
|
+
# Now going to generate the content of the process.
|
624
|
+
# For that, save and update the state.
|
625
|
+
indent = state.indent
|
626
|
+
level = state.level
|
627
|
+
state.indent += " "
|
628
|
+
state.level = :timed
|
629
|
+
# Now generate the content.
|
630
|
+
content_txt = head.to_HDLRuby(state)
|
631
|
+
# Restore the state and generate the result.
|
632
|
+
state.indent = indent
|
633
|
+
state.level = level
|
634
|
+
return decl_txt + content_txt + end_txt
|
635
|
+
else
|
636
|
+
# It is a normal process.
|
637
|
+
# Generate the declaration of the process.
|
638
|
+
decl_txt = ""
|
639
|
+
unless delay_txt.empty? then
|
640
|
+
raise "Process with delay is not supported yet."
|
641
|
+
end
|
642
|
+
unless event_txt.empty? and name_txt.empty? then
|
643
|
+
# There are arguments to the process.
|
644
|
+
decl_txt += "(" + event_txt
|
645
|
+
decl_txt += ", " if event_txt[0] and name_txt[0]
|
646
|
+
decl_txt += "name: #{name_txt}" if name_txt[0]
|
647
|
+
decl_txt +=")"
|
648
|
+
end
|
649
|
+
decl_txt += " do\n"
|
650
|
+
# Generate its content.
|
651
|
+
# First check if it is a seq or par process at first.
|
652
|
+
seq_par = VerilogTools.get_seq_par(head)
|
653
|
+
seq_par = :par unless seq_par
|
654
|
+
# Now going to generate the content of the process.
|
655
|
+
# For that, save and update the state.
|
656
|
+
indent = state.indent
|
657
|
+
level = state.level
|
658
|
+
state.indent += " "
|
659
|
+
state.level = seq_par
|
660
|
+
# Now generate the content.
|
661
|
+
content_txt = head.to_HDLRuby(state)
|
662
|
+
# Restore the state and generate the result.
|
663
|
+
state.indent = indent
|
664
|
+
state.level = level
|
665
|
+
res = indent + seq_par.to_s + decl_txt
|
666
|
+
res += content_txt + indent + "end\n"
|
667
|
+
return res
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
TO_HDLRuby[:expandrange] = lambda do |ast,state|
|
672
|
+
# Auth: for now the type of expand range is ignored, maybe it
|
673
|
+
# is not necessary in HDLRuby.
|
674
|
+
return ast[1].to_HDLRuby(state)
|
675
|
+
end
|
676
|
+
|
677
|
+
|
678
|
+
TO_HDLRuby[:range] = lambda do |ast,state|
|
679
|
+
return "[" + ast[0].to_HDLRuby(state) + ".." +
|
680
|
+
ast[1].to_HDLRuby(state) + "]"
|
681
|
+
end
|
682
|
+
|
683
|
+
|
684
|
+
TO_HDLRuby[:module_instantiation] = lambda do |ast,state|
|
685
|
+
# Generate each element.
|
686
|
+
module_txt = ast[0].to_HDLRuby(state)
|
687
|
+
parameters_txt = ast[1] ? "(" + ast[1].to_HDLRuby(state) + ")." : ""
|
688
|
+
instance_txts = ast[2].map {|i| i.to_HDLRuby(state) }
|
689
|
+
# Generate the final state.
|
690
|
+
# Auth: in HDLRuby there is one such statement per module instance.
|
691
|
+
return instance_txts.map do |i|
|
692
|
+
state.indent + module_txt + parameters_txt + i + "\n"
|
693
|
+
end.join
|
694
|
+
end
|
695
|
+
|
696
|
+
|
697
|
+
TO_HDLRuby[:parameter_value_assignment] = lambda do |ast,state|
|
698
|
+
return ast[0].map {|p| p.to_HDLRuby(state) }.join(",")
|
699
|
+
end
|
700
|
+
|
701
|
+
|
702
|
+
TO_HDLRuby[:module_instance] = lambda do |ast,state|
|
703
|
+
instance_txt = "(:" + ast[0].to_HDLRuby(state) + ")"
|
704
|
+
if ast[1] then
|
705
|
+
return instance_txt + ".(" + ast[1].to_HDLRuby(state) + ")"
|
706
|
+
else
|
707
|
+
return instance_txt
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
|
712
|
+
TO_HDLRuby[:name_of_instance] = lambda do |ast,state|
|
713
|
+
name_txt = ast[0].to_HDLRuby(state)
|
714
|
+
range_txt = ast[1] ? ast[1].to_HDLRuby(state) : ""
|
715
|
+
if range_txt[0] then
|
716
|
+
# Auth: I do not know what to do with range here.
|
717
|
+
raise "Internal error: range in module instance name not supported yet."
|
718
|
+
end
|
719
|
+
return name_txt
|
720
|
+
end
|
721
|
+
|
722
|
+
|
723
|
+
TO_HDLRuby[:list_of_module_connections] = lambda do |ast,state|
|
724
|
+
return ast[0].map { |c| c.to_HDLRuby(state) }.join(",")
|
725
|
+
end
|
726
|
+
|
727
|
+
|
728
|
+
TO_HDLRuby[:module_port_connection] = lambda do |ast,state|
|
729
|
+
return ast[0].to_HDLRuby(state)
|
730
|
+
end
|
731
|
+
|
732
|
+
|
733
|
+
TO_HDLRuby[:named_port_connection] = lambda do |ast,state|
|
734
|
+
return ast[0].to_HDLRuby(state) + ":" + ast[1].to_HDLRuby(state)
|
735
|
+
end
|
736
|
+
|
737
|
+
|
738
|
+
TO_HDLRuby[:statement_or_null] = lambda do |ast,state|
|
739
|
+
if ast[0] then
|
740
|
+
return ast[0].to_HDLRuby(state)
|
741
|
+
else
|
742
|
+
return ""
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
|
747
|
+
TO_HDLRuby[:statement] = lambda do |ast,state|
|
748
|
+
# Check if it is a block, and generate the corresponding code.
|
749
|
+
block_txt = ""
|
750
|
+
type = ast[0].is_a?(AST) ? ast[0].type : ast[0].to_sym
|
751
|
+
case type
|
752
|
+
when :seq_block
|
753
|
+
seq_block = ast[0]
|
754
|
+
# Get the name if any.
|
755
|
+
# Auth: in this case, what to do with the name?
|
756
|
+
name_txt = VerilogTools.get_name(seq_block)
|
757
|
+
# Generate the declarations if any.
|
758
|
+
decls = seq_block[1]
|
759
|
+
decls_txt = decls ? decls.map {|d| d.to_HDLRuby(state)}.join : ""
|
760
|
+
# Saves the state.
|
761
|
+
indent = state.indent
|
762
|
+
level = state.level
|
763
|
+
# Generate the content.
|
764
|
+
seq_par_txt = [ [state.level, ""] ] # The list of seq and par block contents.
|
765
|
+
content = seq_block[2]
|
766
|
+
content_txt = ""
|
767
|
+
content.each do |statement|
|
768
|
+
seq_par = VerilogTools.get_seq_par(statement)
|
769
|
+
# Check if the blocking/non blocking mode changed.
|
770
|
+
if seq_par != seq_par_txt[-1][0] then
|
771
|
+
if !content_txt.empty? then
|
772
|
+
# There is a content, add it to the list.
|
773
|
+
seq_par_txt[-1][1] = content_txt
|
774
|
+
content_txt == ""
|
775
|
+
end
|
776
|
+
# Add a new block.
|
777
|
+
seq_par_txt << [seq_par, ""]
|
778
|
+
end
|
779
|
+
# Update the content.
|
780
|
+
state.level = seq_par if seq_par
|
781
|
+
content_txt += statement.to_HDLRuby(state)
|
782
|
+
end
|
783
|
+
# Update the final seq_par_txt block.
|
784
|
+
seq_par_txt[-1][1] = content_txt
|
785
|
+
# Restores the state and generate the final text.
|
786
|
+
state.indent = indent
|
787
|
+
state.level = level
|
788
|
+
# Get the base seq or par state of the process
|
789
|
+
base = seq_par_txt[0][0]
|
790
|
+
# Generate the body text.
|
791
|
+
body_txt = decls_txt.empty? ? "" : decls_txt + "\n"
|
792
|
+
seq_par_txt.each do |seq_par, txt|
|
793
|
+
if seq_par and seq_par != base then
|
794
|
+
body_txt += state.indent + " " + seq_par.to_s + " do\n" +
|
795
|
+
txt + state.indent + " " + "end\n"
|
796
|
+
else
|
797
|
+
body_txt += txt
|
798
|
+
end
|
799
|
+
end
|
800
|
+
# Return the result.
|
801
|
+
return body_txt
|
802
|
+
when :system_task_enable
|
803
|
+
sys = ast[0]
|
804
|
+
name_txt = sys[0].to_HDLRuby(state)
|
805
|
+
arg_txt = sys[1] ? sys[1].map{|a|a.to_HDLRuby(state)}.join(",") : ""
|
806
|
+
return state.indent +
|
807
|
+
VerilogTools.system_to_HDLRuby(name_txt,arg_txt) + "\n"
|
808
|
+
when :if
|
809
|
+
# Saves the state.
|
810
|
+
indent = state.indent
|
811
|
+
level = state.level
|
812
|
+
# Generate the hif.
|
813
|
+
state.indent += " "
|
814
|
+
if_txt = indent + "hif(" + ast[1].to_HDLRuby(state) + ") do\n"
|
815
|
+
if_txt += ast[2].to_HDLRuby(state) + indent + "end\n"
|
816
|
+
if ast[3] then
|
817
|
+
if_txt += indent + "helse do\n"
|
818
|
+
if_txt += ast[3].to_HDLRuby(state) + indent + "end\n"
|
819
|
+
end
|
820
|
+
# Restore the state and return the result.
|
821
|
+
state.indent = indent
|
822
|
+
state.level = level
|
823
|
+
return if_txt
|
824
|
+
when :case
|
825
|
+
# Saves the state.
|
826
|
+
indent = state.indent
|
827
|
+
level = state.level
|
828
|
+
# Generate the hcase.
|
829
|
+
state.indent += " "
|
830
|
+
case_txt = indent + "hcase(" + ast[1].to_HDLRuby(state) + ")\n"
|
831
|
+
# Generate the case items.
|
832
|
+
case_txt += ast[2].map do |item|
|
833
|
+
res_txt = ""
|
834
|
+
if item[0] then
|
835
|
+
# hwhen case.
|
836
|
+
res_txt += indent + "hwhen("
|
837
|
+
res_txt += item[0].map {|e| e.to_HDLRuby(state) }.join(",")
|
838
|
+
res_txt += ") do\n"
|
839
|
+
res_txt += item[1].to_HDLRuby(state)
|
840
|
+
res_txt += indent + "end\n"
|
841
|
+
else
|
842
|
+
# helse case.
|
843
|
+
res_txt += indent + "helse do\n"
|
844
|
+
res_txt += item[1].to_HDLRuby(state) + indent + "end\n"
|
845
|
+
end
|
846
|
+
res_txt
|
847
|
+
end.join
|
848
|
+
# Restore the state and return the result.
|
849
|
+
state.indent = indent
|
850
|
+
state.level = level
|
851
|
+
return case_txt
|
852
|
+
when :blocking_assignment, :non_blocking_assignment
|
853
|
+
return ast[0].to_HDLRuby(state)
|
854
|
+
when :statement
|
855
|
+
# Simply recurse, but first restores the indent.
|
856
|
+
state.indent = indent
|
857
|
+
return ast[0].to_HDLRuby(state)
|
858
|
+
when :delay_or_event_control
|
859
|
+
delay = ast[0][0]
|
860
|
+
if delay.type != :delay_control then
|
861
|
+
raise "Event not supported within statements yet."
|
862
|
+
end
|
863
|
+
return delay.to_HDLRuby(state) + ast[1].to_HDLRuby(state)
|
864
|
+
else
|
865
|
+
raise "Unsupported statement type: #{type}"
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
|
870
|
+
TO_HDLRuby[:assignment] = lambda do |ast,state|
|
871
|
+
return state.indent + ast[0].to_HDLRuby(state) + " <= " +
|
872
|
+
ast[1].to_HDLRuby(state) + "\n"
|
873
|
+
end
|
874
|
+
|
875
|
+
|
876
|
+
# Blocking and non blocking assignments have the same resulting
|
877
|
+
# code in HDLruby, however they are included in different kind of
|
878
|
+
# blocks, but this is processed elsewhere.
|
879
|
+
TO_HDLRuby[:blocking_assignment] = lambda do |ast,state|
|
880
|
+
if ast[1] then
|
881
|
+
raise "Internal error: unsupported delay or event in assingment yet."
|
882
|
+
end
|
883
|
+
return state.indent + ast[0].to_HDLRuby(state) + " <= " +
|
884
|
+
ast[2].to_HDLRuby(state) + "\n"
|
885
|
+
end
|
886
|
+
|
887
|
+
TO_HDLRuby[:non_blocking_assignment] = TO_HDLRuby[:blocking_assignment]
|
888
|
+
|
889
|
+
|
890
|
+
TO_HDLRuby[:lvalue] = lambda do |ast, state|
|
891
|
+
# Get the base of the primary: number or identifier.
|
892
|
+
base = ast[0]
|
893
|
+
base_txt = base.to_HDLRuby(state)
|
894
|
+
expr1 = ast[1]
|
895
|
+
expr2 = ast[2]
|
896
|
+
if expr1 then
|
897
|
+
# Array access type.
|
898
|
+
if expr2 then
|
899
|
+
# Range access.
|
900
|
+
return base_txt + "[" +
|
901
|
+
expr1.to_HDLRuby(state) + ".." + expr2.to_HDLRuby(state) +
|
902
|
+
"]"
|
903
|
+
else
|
904
|
+
# Index access.
|
905
|
+
return base_txt + "[" + expr1.to_HDLRuby(state) + "]"
|
906
|
+
end
|
907
|
+
else
|
908
|
+
# Default access.
|
909
|
+
return base_txt
|
910
|
+
end
|
911
|
+
end
|
912
|
+
|
913
|
+
|
914
|
+
TO_HDLRuby[:expression] = lambda do |ast,state|
|
915
|
+
# Depending on the child.
|
916
|
+
child = ast[0]
|
917
|
+
# Is it a conditional expression?
|
918
|
+
if child.is_a?(Array) then
|
919
|
+
# Go inside an expression so save and update the state.
|
920
|
+
level = state.level
|
921
|
+
state.level = :expr
|
922
|
+
# Yes, generate the conditional.
|
923
|
+
res_txt = ""
|
924
|
+
depth = 0
|
925
|
+
elems = child.reverse
|
926
|
+
while elems.any? do
|
927
|
+
expr_txt = elems.pop.to_HDLRuby(state)
|
928
|
+
case(elems.pop)
|
929
|
+
when "?"
|
930
|
+
res_txt += "mux(~" + expr_txt + ","
|
931
|
+
depth += 1
|
932
|
+
when ":" then
|
933
|
+
res_txt += expr_txt + ","
|
934
|
+
when nil then
|
935
|
+
res_txt += expr_txt + ")" * depth
|
936
|
+
depth = 0
|
937
|
+
end
|
938
|
+
end
|
939
|
+
# Restores the state and return the result.
|
940
|
+
state.level = level
|
941
|
+
else
|
942
|
+
# No, just return the generation result for the child
|
943
|
+
res_txt = child.to_HDLRuby(state)
|
944
|
+
end
|
945
|
+
return res_txt
|
946
|
+
end
|
947
|
+
|
948
|
+
# All the expression AST have the same structure until the primary.
|
949
|
+
|
950
|
+
TO_HDLRuby[:condition_term] = lambda do |ast,state|
|
951
|
+
# Save the state (may change after).
|
952
|
+
level = state.level
|
953
|
+
if ast[0].size > 1 then
|
954
|
+
# Go inside the expression, so update the level.
|
955
|
+
state.level = :expr
|
956
|
+
end
|
957
|
+
res_txt = ast[0].map do |elem|
|
958
|
+
elem.is_a?(String) ? VerilogTools.operator_to_HDLRuby(elem) :
|
959
|
+
elem.to_HDLRuby(state)
|
960
|
+
end.join
|
961
|
+
# Restores the state.
|
962
|
+
state.level = level
|
963
|
+
if state.level != :expr or ast[0].size < 3 then
|
964
|
+
# Single node, unary or not within expression cases:
|
965
|
+
# no parenthesis required.
|
966
|
+
return res_txt
|
967
|
+
else
|
968
|
+
# Otherwise they are required to avoid priority problems.
|
969
|
+
return "(" + res_txt + ")"
|
970
|
+
end
|
971
|
+
end
|
972
|
+
|
973
|
+
TO_HDLRuby[:logic_or_term] = TO_HDLRuby[:condition_term]
|
974
|
+
|
975
|
+
TO_HDLRuby[:logic_and_term] = TO_HDLRuby[:condition_term]
|
976
|
+
|
977
|
+
TO_HDLRuby[:bit_or_term] = TO_HDLRuby[:condition_term]
|
978
|
+
|
979
|
+
TO_HDLRuby[:bit_xor_term] = TO_HDLRuby[:condition_term]
|
980
|
+
|
981
|
+
TO_HDLRuby[:bit_and_term] = TO_HDLRuby[:condition_term]
|
982
|
+
|
983
|
+
TO_HDLRuby[:equal_term] = TO_HDLRuby[:condition_term]
|
984
|
+
|
985
|
+
TO_HDLRuby[:comparison_term] = TO_HDLRuby[:condition_term]
|
986
|
+
|
987
|
+
TO_HDLRuby[:shift_term] = TO_HDLRuby[:condition_term]
|
988
|
+
|
989
|
+
TO_HDLRuby[:add_term] = TO_HDLRuby[:condition_term]
|
990
|
+
|
991
|
+
TO_HDLRuby[:mul_term] = lambda do |ast,state|
|
992
|
+
primary_txt = ast[0][-1].to_HDLRuby(state)
|
993
|
+
if ast[0].size == 1 then
|
994
|
+
# There is no operator, just return the priary text.
|
995
|
+
return primary_txt
|
996
|
+
else
|
997
|
+
# There is an operator, depending on it.
|
998
|
+
op = ast[0][0]
|
999
|
+
case(op)
|
1000
|
+
when "+", "-", "~", "!"
|
1001
|
+
return VerilogTools.operator_to_HDLRuby(op) + primary_txt
|
1002
|
+
when "&", "|", "^", "^|"
|
1003
|
+
return primary_txt +
|
1004
|
+
".each.reduce(:" + VerilogTools.operator_to_HDLRuby(op) + ")"
|
1005
|
+
when "~&", "~|", "~^"
|
1006
|
+
return "~" + primary_txt +
|
1007
|
+
".each.reduce(:" + VerilogTools.operator_to_HDLRuby(op[1]) +")"
|
1008
|
+
else
|
1009
|
+
raise "Internal error: unknown unary operator #{op}"
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
|
1015
|
+
TO_HDLRuby[:primary] = lambda do |ast,state|
|
1016
|
+
# Get the base of the primary: number or identifier.
|
1017
|
+
base = ast[0]
|
1018
|
+
base_txt = base.to_HDLRuby(state)
|
1019
|
+
# Depending on the base.
|
1020
|
+
if base.type == :mintypmax_expression then
|
1021
|
+
# Parenthesis case.
|
1022
|
+
# Auth: but can be ommitted since automatically
|
1023
|
+
# set for ensuring order of operations.
|
1024
|
+
# return "(" + base_txt + ")"
|
1025
|
+
return base_txt
|
1026
|
+
else
|
1027
|
+
expr1 = ast[1]
|
1028
|
+
expr2 = ast[2]
|
1029
|
+
if expr1 then
|
1030
|
+
# Array access type.
|
1031
|
+
if expr2 then
|
1032
|
+
# Range access.
|
1033
|
+
return base_txt + "[" +
|
1034
|
+
expr1.to_HDLRuby(state) + ".." + expr2.to_HDLRuby(state) +
|
1035
|
+
"]"
|
1036
|
+
else
|
1037
|
+
# Index access.
|
1038
|
+
return base_txt + "[" + expr1.to_HDLRuby(state) + "]"
|
1039
|
+
end
|
1040
|
+
else
|
1041
|
+
# Default access.
|
1042
|
+
return base_txt
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
|
1048
|
+
TO_HDLRuby[:number] = lambda do |ast,state|
|
1049
|
+
# Get the first number if any.
|
1050
|
+
number0 = ast[0] ? ast[0].to_HDLRuby(state) : ""
|
1051
|
+
# Get the base if any.
|
1052
|
+
base = ast[1] ? ast[1].to_HDLRuby(state) : ""
|
1053
|
+
# Get the second number if any.
|
1054
|
+
number1 = ast[2] ? ast[2].to_HDLRuby(state) : ""
|
1055
|
+
# Depending on the base.
|
1056
|
+
case base
|
1057
|
+
when "'b"
|
1058
|
+
# Binary encoding.
|
1059
|
+
return "_#{number0}b#{number1}"
|
1060
|
+
when "'o"
|
1061
|
+
# Octal encoding.
|
1062
|
+
return "_#{number0}o#{number1}"
|
1063
|
+
when "'d"
|
1064
|
+
# Decimal encoding.
|
1065
|
+
return "_#{number0}d#{number1}"
|
1066
|
+
when "'h"
|
1067
|
+
# Hexadecimal encoding.
|
1068
|
+
return "_#{number0}h#{number1}"
|
1069
|
+
when ""
|
1070
|
+
# Simple number.
|
1071
|
+
return number0
|
1072
|
+
else
|
1073
|
+
ast.generate_error("Invalid number base: #{base}")
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
|
1078
|
+
TO_HDLRuby[:concatenation] = lambda do |ast,state|
|
1079
|
+
return "[ " + ast[0].map {|e| e.to_HDLRuby(state) }.join(", ") + " ]"
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
|
1083
|
+
TO_HDLRuby[:multiple_concatenation] = lambda do |ast,state|
|
1084
|
+
return "[" + ast[1].map {|e| e.to_HDLRuby(state) }.join(", ") +
|
1085
|
+
" ].to_expr.as(bit[" + ast[0].to_HDLRuby(state) + "])"
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
|
1089
|
+
TO_HDLRuby[:function_call] = lambda do |ast,state|
|
1090
|
+
# Get the name of the function.
|
1091
|
+
name_txt = ast[0].to_HDLRuby
|
1092
|
+
# Get the arguments if any.
|
1093
|
+
args_txt = ast[1] ? ast[1].map {|a|a.to_HDLRuby(state)}.join(",") : ""
|
1094
|
+
# Is it a system function call?
|
1095
|
+
if (ast[0].type == :name_of_system_function) then
|
1096
|
+
# Yes, specific process.
|
1097
|
+
return VerilogTools.system_to_HDLRuby(name_txt,args_txt)
|
1098
|
+
else
|
1099
|
+
# No, standard function call.
|
1100
|
+
return name_txt + "(" + args_txt + ")"
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
|
1105
|
+
|
1106
|
+
TO_HDLRuby[:event_expression] = lambda do |ast,state|
|
1107
|
+
return ast[0].map {|ev| ev.to_HDLRuby(state) }.join(",")
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
|
1111
|
+
TO_HDLRuby[:event_primary] = lambda do |ast,state|
|
1112
|
+
edge = ast[0]
|
1113
|
+
case edge
|
1114
|
+
when "posedge"
|
1115
|
+
return ast[1].to_HDLRuby + ".posedge"
|
1116
|
+
when "negedge"
|
1117
|
+
return ast[1].to_HDLRuby + ".negedge"
|
1118
|
+
when "*"
|
1119
|
+
# Activated on all.
|
1120
|
+
return ""
|
1121
|
+
else
|
1122
|
+
# Actually it is not an edge.
|
1123
|
+
return edge.to_HDLRuby(state)
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
|
1128
|
+
TO_HDLRuby[:_IDENTIFIER] = lambda do |ast,state|
|
1129
|
+
VerilogTools.name_to_HDLRuby(ast[0])
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
|
1133
|
+
TO_HDLRuby[:delay_control] = lambda do |ast,state|
|
1134
|
+
# Generate the delay.
|
1135
|
+
head_txt = state.indent + "!"
|
1136
|
+
delay_txt = ast[0].to_HDLRuby(state)
|
1137
|
+
# Compute the time scale.
|
1138
|
+
timescale = ast[-1][0][:timescale]
|
1139
|
+
if timescale then
|
1140
|
+
mult = timescale[0]
|
1141
|
+
if mult != 1 then
|
1142
|
+
return head_txt + "(" + delay_txt + "*#{mult}).fs\n"
|
1143
|
+
else
|
1144
|
+
return head_txt + delay_txt + ".fs\n"
|
1145
|
+
end
|
1146
|
+
else
|
1147
|
+
# By default use nanoseconds
|
1148
|
+
return delay_txt + ".ns\n"
|
1149
|
+
end
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
end
|
1153
|
+
end
|