HDLRuby 3.7.8 → 3.7.9
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/README.md +140 -3
- data/lib/HDLRuby/hdr_samples/with_henumerable.rb +366 -0
- data/lib/HDLRuby/std/hruby_enum.rb +924 -0
- data/lib/HDLRuby/std/sequencer.rb +1 -1
- data/lib/HDLRuby/std/sequencer_sw.rb +305 -4
- data/lib/HDLRuby/std/std.rb +1 -0
- data/lib/HDLRuby/version.rb +1 -1
- metadata +3 -1
@@ -0,0 +1,924 @@
|
|
1
|
+
|
2
|
+
module HDLRuby::High::Std
|
3
|
+
|
4
|
+
##
|
5
|
+
# Standard HDLRuby::High library: hardware enumerator generator.
|
6
|
+
# The idea is to be able to have parallel enumerators in HDLRuby.
|
7
|
+
#
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
# Module adding hardware enumerator functionalities to object including
|
13
|
+
# the to_a method.
|
14
|
+
module HEnumerable
|
15
|
+
|
16
|
+
# Iterator on each element.
|
17
|
+
def heach(&ruby_block)
|
18
|
+
return self.to_a.each(&ruby_block)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Iterator on each of the elements in range +rng+.
|
22
|
+
# *NOTE*:
|
23
|
+
# - Stop iteration when the end of the range is reached or when there
|
24
|
+
# are no elements left
|
25
|
+
# - This is not a method from Ruby but one specific for hardware where
|
26
|
+
# creating a array is very expensive.
|
27
|
+
def heach_range(rng,&ruby_block)
|
28
|
+
return self.heach.each_range(rng,&ruby_block)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Tell if all the elements respect a given criterion given either
|
32
|
+
# as +arg+ or as block.
|
33
|
+
def hall?(arg = nil, &ruby_block)
|
34
|
+
if self.hsize < 1 then
|
35
|
+
# Empty, so always true.
|
36
|
+
return 1
|
37
|
+
end
|
38
|
+
comp = []
|
39
|
+
if arg then
|
40
|
+
# Compare each element to arg in parallel.
|
41
|
+
comp = self.hmap do |elem|
|
42
|
+
elem == arg
|
43
|
+
end
|
44
|
+
elsif ruby_block then
|
45
|
+
# Use the ruby block in parallel.
|
46
|
+
comp = self.hmap(&ruby_block)
|
47
|
+
else
|
48
|
+
# Nothing to check.
|
49
|
+
return 1
|
50
|
+
end
|
51
|
+
# Reduce the result.
|
52
|
+
return comp.reduce(&:&)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Tell if any of the elements respects a given criterion given either
|
56
|
+
# as +arg+ or as block.
|
57
|
+
def hany?(arg = nil,&ruby_block)
|
58
|
+
if self.hsize < 1 then
|
59
|
+
# Empty, so always false.
|
60
|
+
return 0
|
61
|
+
end
|
62
|
+
comp = []
|
63
|
+
if arg then
|
64
|
+
# Compare each element to arg in parallel.
|
65
|
+
comp = self.hmap do |elem|
|
66
|
+
elem == arg
|
67
|
+
end
|
68
|
+
elsif ruby_block then
|
69
|
+
# Use the ruby block in parallel.
|
70
|
+
comp = self.hmap(&ruby_block)
|
71
|
+
else
|
72
|
+
# Nothing to check.
|
73
|
+
return 0
|
74
|
+
end
|
75
|
+
# Reduce the result.
|
76
|
+
return comp.reduce(&:|)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns an HEnumerator generated from current enumerable and +arg+
|
80
|
+
def hchain(arg)
|
81
|
+
return self.heach + arg
|
82
|
+
end
|
83
|
+
|
84
|
+
# HW implementation of the Ruby chunk.
|
85
|
+
# NOTE: to do, or may be not.
|
86
|
+
def hchunk(*args,&ruby_block)
|
87
|
+
raise "hchunk is not supported yet."
|
88
|
+
end
|
89
|
+
|
90
|
+
# HW implementation of the Ruby chunk_while.
|
91
|
+
# NOTE: to do, or may be not.
|
92
|
+
def hchunk_while(*args,&ruby_block)
|
93
|
+
raise "hchunk_while is not supported yet."
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns a HEnumerable containing the execution result of the given
|
97
|
+
# block on each element. If no block is given, return an HEnumerator.
|
98
|
+
def hmap(&ruby_block)
|
99
|
+
# No block given? Generate a new wrapper enumerator for smap.
|
100
|
+
if !ruby_block then
|
101
|
+
return HEnumeratorWrapper.new(self,:hmap)
|
102
|
+
end
|
103
|
+
# A block given? Create the result HEnumerable (a Ruby array).
|
104
|
+
return self.heach.map(&ruby_block)
|
105
|
+
end
|
106
|
+
|
107
|
+
# HW implementation of the Ruby flat_map.
|
108
|
+
def hflat_map(&ruby_block)
|
109
|
+
# No block given? Generate a new wrapper enumerator for smap.
|
110
|
+
if !ruby_block then
|
111
|
+
return HEnumeratorWrapper.new(self,:hmap)
|
112
|
+
end
|
113
|
+
# A block given? Create the result HEnumerable (a Ruby array).
|
114
|
+
return self.heach.flat_map(&ruby_block)
|
115
|
+
end
|
116
|
+
|
117
|
+
# HW implementation of the Ruby compact.
|
118
|
+
def hcompact
|
119
|
+
raise "hcompact is not supported yet."
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
# HW implementation of the Ruby count.
|
124
|
+
def hcount(arg = nil, &ruby_block)
|
125
|
+
if self.hsize < 1 then
|
126
|
+
# Empty, so always false.
|
127
|
+
return 0
|
128
|
+
end
|
129
|
+
comp = []
|
130
|
+
if arg then
|
131
|
+
# Compare each element to arg in parallel.
|
132
|
+
comp = self.hmap do |elem|
|
133
|
+
elem == arg
|
134
|
+
end
|
135
|
+
elsif ruby_block then
|
136
|
+
# Use the ruby block in parallel.
|
137
|
+
comp = self.hmap(&ruby_block)
|
138
|
+
else
|
139
|
+
# Nothing to check, return the size.
|
140
|
+
return self.hsize
|
141
|
+
end
|
142
|
+
# Reduce the result.
|
143
|
+
return comp.reduce(&:+)
|
144
|
+
end
|
145
|
+
|
146
|
+
# HW implementation of the Ruby cycle.
|
147
|
+
def hcycle(n = nil,&ruby_block)
|
148
|
+
raise "hcycle is not supported yet."
|
149
|
+
end
|
150
|
+
|
151
|
+
# HW implementation of the Ruby find.
|
152
|
+
# NOTE: contrary to Ruby, by default ifnone is 0 and not nil.
|
153
|
+
def hfind(ifnone = proc { 0 }, &ruby_block)
|
154
|
+
# No block given? Generate a new wrapper enumerator for sfind.
|
155
|
+
if !ruby_block then
|
156
|
+
return HEnumeratorWrapper.new(self,:hfind,ifnone)
|
157
|
+
end
|
158
|
+
if self.hsize < 1 then
|
159
|
+
# Empty, so always not found.
|
160
|
+
return ifnone.call
|
161
|
+
end
|
162
|
+
# Convert to an array.
|
163
|
+
ar = self.to_a
|
164
|
+
# Use the ruby block in parallel.
|
165
|
+
comp = ar.map { |elem| ruby_block.call(elem) }
|
166
|
+
# Generate the look up circuit.
|
167
|
+
res = HDLRuby::High.top_user.mux(comp[-1],ifnone.call,ar[-1])
|
168
|
+
(self.hsize-1).times do |i|
|
169
|
+
res = HDLRuby::High.top_user.mux(comp[-i-2],res,ar[-i-2])
|
170
|
+
end
|
171
|
+
return res
|
172
|
+
end
|
173
|
+
|
174
|
+
# HW implementation of the Ruby drop.
|
175
|
+
def hdrop(n)
|
176
|
+
return self.heach.drop(n)
|
177
|
+
end
|
178
|
+
|
179
|
+
# HW implementation of the Ruby drop_while.
|
180
|
+
def hdrop_while(&ruby_block)
|
181
|
+
raise "hdrop_while is not supported yet."
|
182
|
+
end
|
183
|
+
|
184
|
+
# HW implementation of the Ruby each_cons
|
185
|
+
def heach_cons(n,&ruby_block)
|
186
|
+
# No block given? Generate a new wrapper enumerator for heach_cons.
|
187
|
+
if !ruby_block then
|
188
|
+
return HEnumeratorWrapper.new(self,:heach_cons,n)
|
189
|
+
end
|
190
|
+
return self.heach.each_cons(n,&ruby_block)
|
191
|
+
end
|
192
|
+
|
193
|
+
# HW implementation of the Ruby each_entry.
|
194
|
+
# NOTE: to do, or may be not.
|
195
|
+
def heach_entry(*args,&ruby_block)
|
196
|
+
raise "heach_entry is not supported yet."
|
197
|
+
end
|
198
|
+
|
199
|
+
# HW implementation of the Ruby each_slice
|
200
|
+
def heach_slice(n,&ruby_block)
|
201
|
+
# No block given? Generate a new wrapper enumerator for heach_slice.
|
202
|
+
if !ruby_block then
|
203
|
+
return HEnumeratorWrapper.new(self,:heach_slice,n)
|
204
|
+
end
|
205
|
+
return self.heach.each_slice(n,&ruby_block)
|
206
|
+
end
|
207
|
+
|
208
|
+
# HW implementation of the Ruby each_with_index.
|
209
|
+
def heach_with_index(*args,&ruby_block)
|
210
|
+
# No block given? Generate a new wrapper enumerator for
|
211
|
+
# heach_with_index.
|
212
|
+
if !ruby_block then
|
213
|
+
return HEnumeratorWrapper.new(self,:heach_with_index)
|
214
|
+
end
|
215
|
+
self.heach.each_with_index(*args,&ruby_block)
|
216
|
+
end
|
217
|
+
|
218
|
+
# HW implementation of the Ruby each_with_object.
|
219
|
+
def heach_with_object(obj,&ruby_block)
|
220
|
+
# No block given? Generate a new wrapper enumerator for
|
221
|
+
# heach_with_object.
|
222
|
+
if !ruby_block then
|
223
|
+
return HEnumeratorWrapper.new(self,:heach_with_object)
|
224
|
+
end
|
225
|
+
self.heach.with_object(obj,&ruby_block)
|
226
|
+
end
|
227
|
+
|
228
|
+
# HW implementation of the Ruby to_a.
|
229
|
+
def hto_a
|
230
|
+
return self.heach.to_a
|
231
|
+
end
|
232
|
+
|
233
|
+
# HW implementation of the Ruby select.
|
234
|
+
def hselect(&ruby_block)
|
235
|
+
raise "hselect is not supported yet."
|
236
|
+
end
|
237
|
+
|
238
|
+
# HW implementation of the Ruby find_index.
|
239
|
+
def hfind_index(obj = nil, &ruby_block)
|
240
|
+
# No block given nor obj? Generate a new wrapper enumerator for
|
241
|
+
# hfind.
|
242
|
+
if !ruby_block && !obj then
|
243
|
+
return HEnumeratorWrapper.new(self,:hfind)
|
244
|
+
end
|
245
|
+
if self.hsize < 1 then
|
246
|
+
# Empty, so always not found.
|
247
|
+
return -1
|
248
|
+
end
|
249
|
+
# If there is an objet, look for it.
|
250
|
+
ruby_block = proc { |e| e == obj } if obj
|
251
|
+
# Convert to an array.
|
252
|
+
ar = self.to_a
|
253
|
+
size =ar.size
|
254
|
+
# Use the ruby block in parallel.
|
255
|
+
comp = self.hmap { |elem| ruby_block.call(elem) }
|
256
|
+
# Generate the look up circuit.
|
257
|
+
res = HDLRuby::High.top_user.mux(comp[-1],-1,size-1)
|
258
|
+
(self.hsize-1).times do |i|
|
259
|
+
res = HDLRuby::High.top_user.mux(comp[-i-2],res,size-i-2)
|
260
|
+
end
|
261
|
+
return res
|
262
|
+
end
|
263
|
+
|
264
|
+
# HW implementation of the Ruby first.
|
265
|
+
def hfirst(n=1)
|
266
|
+
return self.heach.first(n)
|
267
|
+
end
|
268
|
+
|
269
|
+
# HW implementation of the Ruby grep.
|
270
|
+
# NOTE: to do, or may be not.
|
271
|
+
def hgrep(*args,&ruby_block)
|
272
|
+
raise "hgrep is not supported yet."
|
273
|
+
end
|
274
|
+
|
275
|
+
# HW implementation of the Ruby grep_v.
|
276
|
+
# NOTE: to do, or may be not.
|
277
|
+
def hgrep_v(*args,&ruby_block)
|
278
|
+
raise "hgrep_v is not supported yet."
|
279
|
+
end
|
280
|
+
|
281
|
+
# HW implementation of the Ruby group_by.
|
282
|
+
# NOTE: to do, or may be not.
|
283
|
+
def hgroup_by(*args,&ruby_block)
|
284
|
+
raise "hgroup_by is not supported yet."
|
285
|
+
end
|
286
|
+
|
287
|
+
# HW implementation of the Ruby include?
|
288
|
+
def hinclude?(obj)
|
289
|
+
return self.hany?(obj)
|
290
|
+
end
|
291
|
+
|
292
|
+
# HW implementation of the Ruby inject.
|
293
|
+
def hinject(*args,&ruby_block)
|
294
|
+
return self.heach.inject(*args,&ruby_block)
|
295
|
+
end
|
296
|
+
|
297
|
+
alias_method :hreduce, :hinject
|
298
|
+
|
299
|
+
# HW implementation of the Ruby lazy.
|
300
|
+
# NOTE: to do, or may be not.
|
301
|
+
def hlazy(*args,&ruby_block)
|
302
|
+
raise "hlazy is not supported yet."
|
303
|
+
end
|
304
|
+
|
305
|
+
# HW implementation of the Ruby max.
|
306
|
+
def hmax(n = nil, &ruby_block)
|
307
|
+
unless n then
|
308
|
+
n = 1
|
309
|
+
scalar = true
|
310
|
+
end
|
311
|
+
if self.hsize < 1 or n < 1 then
|
312
|
+
# Empty, no max.
|
313
|
+
return 0
|
314
|
+
end
|
315
|
+
unless ruby_block then
|
316
|
+
# The default comparator.
|
317
|
+
ruby_block = proc { |a,b| a > b }
|
318
|
+
end
|
319
|
+
# The 2-value max unit.
|
320
|
+
max2 = proc {|a,b| HDLRuby::High.top_user.mux(ruby_block.call(a,b),b,a) }
|
321
|
+
# The single max hearch.
|
322
|
+
m = self.reduce(&max2)
|
323
|
+
res = [m]
|
324
|
+
if n > 1 then
|
325
|
+
raise "hmax not supported for more than one max element."
|
326
|
+
end
|
327
|
+
# # The other max hearch.
|
328
|
+
# ar = self.to_a
|
329
|
+
# sign = self.type.signed?
|
330
|
+
# (n-1).times do
|
331
|
+
# # Exclude the previous max.
|
332
|
+
# ar = ar.map do |a|
|
333
|
+
# if sign then
|
334
|
+
# HDLRuby::High.top_user.mux(a == m, a, HDLRuby::High.cur_system.send("_b1#{"0" * (a.type.width-1)}"))
|
335
|
+
# else
|
336
|
+
# HDLRuby::High.top_user.mux(a == m, a, HDLRuby::High.cur_system.send("_b0#{"0" * (a.type.width-1)}"))
|
337
|
+
# end
|
338
|
+
# end
|
339
|
+
# puts "#2 ar.size=#{ar.size}"
|
340
|
+
# m = ar.reduce(&max2)
|
341
|
+
# puts "#3"
|
342
|
+
# res << m
|
343
|
+
# puts "#4"
|
344
|
+
# end
|
345
|
+
# puts "#5"
|
346
|
+
if scalar then
|
347
|
+
# Scalar result case.
|
348
|
+
return m
|
349
|
+
else
|
350
|
+
# Array result case.
|
351
|
+
return res
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
# HW implementation of the Ruby max_by.
|
356
|
+
def hmax_by(n = nil, &ruby_block)
|
357
|
+
# No block given? Generate a new wrapper enumerator for smax_by.
|
358
|
+
if !ruby_block then
|
359
|
+
return HEnumeratorWrapper.new(self,:hmax_by,n)
|
360
|
+
end
|
361
|
+
# A block is given, use smax with a proc that applies ruby_block
|
362
|
+
# before comparing.
|
363
|
+
# return hmax(n) { |a,b| ruby_block.call(a) <=> ruby_block.call(b) }
|
364
|
+
return hmax(n) { |a,b| ruby_block.call(a) > ruby_block.call(b) }
|
365
|
+
end
|
366
|
+
|
367
|
+
# HW implementation of the Ruby min.
|
368
|
+
def hmin(n = nil, &ruby_block)
|
369
|
+
unless n then
|
370
|
+
n = 1
|
371
|
+
scalar = true
|
372
|
+
end
|
373
|
+
if self.hsize < 1 or n < 1 then
|
374
|
+
# Empty, no min.
|
375
|
+
return 0
|
376
|
+
end
|
377
|
+
if !ruby_block then
|
378
|
+
# The default comparator.
|
379
|
+
ruby_block = proc { |a,b| a > b }
|
380
|
+
end
|
381
|
+
# The 2-value max unit.
|
382
|
+
min2 = proc {|a,b| HDLRuby::High.top_user.mux(ruby_block.call(a,b),a,b) }
|
383
|
+
# The single max hearch.
|
384
|
+
m = self.reduce(&min2)
|
385
|
+
res = [m]
|
386
|
+
if n > 1 then
|
387
|
+
raise "hmin not supported for more than one max element."
|
388
|
+
end
|
389
|
+
# # The other max hearch.
|
390
|
+
# ar = self.to_a
|
391
|
+
# sign = self.type.signed?
|
392
|
+
# (n-1).times do
|
393
|
+
# # Exclude the previous max.
|
394
|
+
# ar = ar.hmap do |a|
|
395
|
+
# if sign then
|
396
|
+
# HDLRuby::High.top_user.mux(a == m, a, HDLRuby::High.cur_system.send("_0#{"1" * (a.type.width-1)}"))
|
397
|
+
# else
|
398
|
+
# HDLRuby::High.top_user.mux(a == m, a, HDLRuby::High.cur_system.send("_1#{"1" * (a.type.width-1)}"))
|
399
|
+
# end
|
400
|
+
# end
|
401
|
+
# m = ar.reduce(&min2)
|
402
|
+
# res << m
|
403
|
+
# end
|
404
|
+
if scalar then
|
405
|
+
# Scalar result case.
|
406
|
+
return m
|
407
|
+
else
|
408
|
+
# Array result case.
|
409
|
+
return res
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# HW implementation of the Ruby min_by.
|
414
|
+
def hmin_by(n = nil, &ruby_block)
|
415
|
+
# No block given? Generate a new wrapper enumerator for smin_by.
|
416
|
+
if !ruby_block then
|
417
|
+
return HEnumeratorWrapper.new(self,:hmin_by,n)
|
418
|
+
end
|
419
|
+
# A block is given, use smin with a proc that applies ruby_block
|
420
|
+
# before comparing.
|
421
|
+
# return hmin(n) { |a,b| ruby_block.call(a) <=> ruby_block.call(b) }
|
422
|
+
return hmin(n) { |a,b| ruby_block.call(a) > ruby_block.call(b) }
|
423
|
+
end
|
424
|
+
|
425
|
+
# HW implementation of the Ruby minmax.
|
426
|
+
def hminmax(&ruby_block)
|
427
|
+
res = []
|
428
|
+
# Computes the min.
|
429
|
+
res[0] = self.hmin(&ruby_block)
|
430
|
+
# Computes the max.
|
431
|
+
res[1] = self.hmax(&ruby_block)
|
432
|
+
# Return the result.
|
433
|
+
return res
|
434
|
+
end
|
435
|
+
|
436
|
+
# HW implementation of the Ruby minmax_by.
|
437
|
+
def hminmax_by(&ruby_block)
|
438
|
+
res = []
|
439
|
+
# Computes the min.
|
440
|
+
res[0] = self.hmin_by(&ruby_block)
|
441
|
+
# Computes the max.
|
442
|
+
res[1] = self.hmax_by(&ruby_block)
|
443
|
+
# Return the result.
|
444
|
+
return res
|
445
|
+
end
|
446
|
+
|
447
|
+
# Tell if none of the elements respects a given criterion given either
|
448
|
+
# as +arg+ or as block.
|
449
|
+
def hnone?(arg = nil, &ruby_block)
|
450
|
+
if self.hsize < 1 then
|
451
|
+
# Empty, so always true.
|
452
|
+
return 1
|
453
|
+
end
|
454
|
+
comp = []
|
455
|
+
if arg then
|
456
|
+
# Compare each element to arg in parallel.
|
457
|
+
comp = self.hmap do |elem|
|
458
|
+
elem == arg
|
459
|
+
end
|
460
|
+
elsif ruby_block then
|
461
|
+
# Use the ruby block in parallel.
|
462
|
+
comp = self.hmap(&ruby_block)
|
463
|
+
else
|
464
|
+
# Nothing to check.
|
465
|
+
return 1
|
466
|
+
end
|
467
|
+
# Reduce the result.
|
468
|
+
return comp.reduce(&:|) != 1
|
469
|
+
end
|
470
|
+
|
471
|
+
# Tell if one and only one of the elements respects a given criterion
|
472
|
+
# given either as +arg+ or as block.
|
473
|
+
def hone?(arg = nil,&ruby_block)
|
474
|
+
if self.hsize < 1 then
|
475
|
+
# Empty, so always false.
|
476
|
+
return 0
|
477
|
+
end
|
478
|
+
# Count the occurences.
|
479
|
+
cnt = self.hcount(arg,&ruby_block)
|
480
|
+
# Check if count is 1.
|
481
|
+
return cnt == 1
|
482
|
+
end
|
483
|
+
|
484
|
+
# HW implementation of the Ruby partition.
|
485
|
+
# NOTE: to do, or may be not.
|
486
|
+
def hpartition(*args,&ruby_block)
|
487
|
+
raise "spartition is not supported yet."
|
488
|
+
end
|
489
|
+
|
490
|
+
# HW implementatiob of the Ruby reject.
|
491
|
+
def hreject(&ruby_block)
|
492
|
+
return hselect {|elem| ~ruby_block.call(elem) }
|
493
|
+
end
|
494
|
+
|
495
|
+
# HW implementatiob of the Ruby reverse_each.
|
496
|
+
def hreverse_each(*args,&ruby_block)
|
497
|
+
# No block given? Generate a new wrapper enumerator for
|
498
|
+
# sreverse_each.
|
499
|
+
if !ruby_block then
|
500
|
+
return HEnumeratorWrapper.new(self,:hreverse_each,*args)
|
501
|
+
end
|
502
|
+
return self.to_a.reverse_each(&ruby_block)
|
503
|
+
end
|
504
|
+
|
505
|
+
# HW implementation of the Ruby slice_after.
|
506
|
+
# NOTE: to do, or may be not.
|
507
|
+
def hslice_after(pattern = nil,&ruby_block)
|
508
|
+
raise "hslice_after is not supported yet."
|
509
|
+
end
|
510
|
+
|
511
|
+
# HW implementation of the Ruby slice_before.
|
512
|
+
# NOTE: to do, or may be not.
|
513
|
+
def hslice_before(*args,&ruby_block)
|
514
|
+
raise "hslice_before is not supported yet."
|
515
|
+
end
|
516
|
+
|
517
|
+
# HW implementation of the Ruby slice_when.
|
518
|
+
# NOTE: to do, or may be not.
|
519
|
+
def hslice_when(*args,&ruby_block)
|
520
|
+
raise "hslice_before is not supported yet."
|
521
|
+
end
|
522
|
+
|
523
|
+
# # HW implementation of the Ruby sort.
|
524
|
+
# def hsort(&ruby_block)
|
525
|
+
# unless ruby_block then
|
526
|
+
# # The default comparator.
|
527
|
+
# ruby_block = proc { |a,b| a < b }
|
528
|
+
# end
|
529
|
+
# if(self.hsize <= 1) then
|
530
|
+
# # Not enough elements: already sorted.
|
531
|
+
# return self
|
532
|
+
# end
|
533
|
+
# # Sort two elements.
|
534
|
+
# sort2 = proc do |a,b|
|
535
|
+
# if b then
|
536
|
+
# HDLRuby::High.top_user.mux(ruby_block.call(a,b), [ b, a] , [a, b])
|
537
|
+
# else
|
538
|
+
# [a]
|
539
|
+
# end
|
540
|
+
# end
|
541
|
+
# # Generate the merge sort.
|
542
|
+
# res = self.hto_a
|
543
|
+
# size = self.hsize
|
544
|
+
# size.width.times do |i|
|
545
|
+
# aux = []
|
546
|
+
# step = 1 << (i+1)
|
547
|
+
# subsize = size/step
|
548
|
+
# # Generate the parts to merge two by two
|
549
|
+
# parts = res.each_slice(subsize).to_a
|
550
|
+
# # Merge.
|
551
|
+
# aux = parts.each_slice(2).map do |(p0,p1)|
|
552
|
+
# p0.zip(p1).map {|a,b| sort2.call(a,b).hto_a }
|
553
|
+
# end.flatten
|
554
|
+
# res = aux
|
555
|
+
# end
|
556
|
+
# return res
|
557
|
+
# end
|
558
|
+
|
559
|
+
# HW implementation of the Ruby sort using the bitonic sort method.
|
560
|
+
# NOTE: dummy is the dummy value used for filling the holes in the
|
561
|
+
# comparison network if the number of elements is not a power of 2.
|
562
|
+
def hsort(dummy = self.type.base.max.as(self.type.base), &ruby_block)
|
563
|
+
# The size to sort
|
564
|
+
size = self.hsize
|
565
|
+
# The type of the base elements
|
566
|
+
typ = self.type.base
|
567
|
+
if(size <= 1) then
|
568
|
+
# Not enough elements: already sorted.
|
569
|
+
return self
|
570
|
+
end
|
571
|
+
# The power of 2 size.
|
572
|
+
size2 = 2 ** ((size-1).width)
|
573
|
+
# Generate the comparator.
|
574
|
+
unless ruby_block then
|
575
|
+
# The default comparator.
|
576
|
+
ruby_block = proc { |a,b| a > b }
|
577
|
+
end
|
578
|
+
# Generate the compare and swap of two elements.
|
579
|
+
compswap = proc do |a,b|
|
580
|
+
if b then
|
581
|
+
HDLRuby::High.top_user.mux(ruby_block.call(a,b), [ b, a] , [a, b])
|
582
|
+
else
|
583
|
+
[a]
|
584
|
+
end
|
585
|
+
end
|
586
|
+
# Create the input stage of the sorter.
|
587
|
+
stages = [self.hto_a + [dummy] * (size2-size) ]
|
588
|
+
# Generate the bitonic sorter.
|
589
|
+
k = 2
|
590
|
+
while(k <= size2) do
|
591
|
+
j = k / 2
|
592
|
+
while(j > 0) do
|
593
|
+
# puts "New stage"
|
594
|
+
# Create the new intermediate stage.
|
595
|
+
stage = size2.times.map {|i| typ.inner(HDLRuby.uniq_name) }
|
596
|
+
stages << stage
|
597
|
+
size2.times do |i|
|
598
|
+
# Determin the swapcomp positions.
|
599
|
+
l = i ^ j
|
600
|
+
# puts "size2=#{size2} i=#{i} j=#{j} l=#{l} k=#{k}"
|
601
|
+
if l > i then
|
602
|
+
if i & k == 0 then
|
603
|
+
# puts "swap #{i} and #{l}"
|
604
|
+
[stages[-1][l],stages[-1][i]] <=
|
605
|
+
compswap.(stages[-2][i],stages[-2][l])
|
606
|
+
else
|
607
|
+
# puts "antiswap #{i} and #{l}"
|
608
|
+
[stages[-1][i],stages[-1][l]] <=
|
609
|
+
compswap.(stages[-2][i],stages[-2][l])
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
j /= 2
|
614
|
+
end
|
615
|
+
k *= 2
|
616
|
+
end
|
617
|
+
# puts "Done"
|
618
|
+
return stages[-1][0..(size-1)]
|
619
|
+
end
|
620
|
+
|
621
|
+
# HW implementation of the Ruby sort.
|
622
|
+
# NOTE: dummy is the dummy value used for filling the holes in the
|
623
|
+
# comparison network if the number of elements is not a power of 2.
|
624
|
+
def hsort_by(dummy = self.type.base.max.as(self.type.base),
|
625
|
+
&ruby_block)
|
626
|
+
# No block given? Generate a new wrapper enumerator for smin_by.
|
627
|
+
if !ruby_block then
|
628
|
+
return SEnumeratorWrapper.new(self,:hsort_by,n)
|
629
|
+
end
|
630
|
+
# A block is given, use smin with a proc that applies ruby_block
|
631
|
+
# before comparing.
|
632
|
+
return hsort(dummy) {|a,b| ruby_block.call(a) > ruby_block.call(b) }
|
633
|
+
end
|
634
|
+
|
635
|
+
# HW implementation of the Ruby sum.
|
636
|
+
def hsum(initial_value = nil,&ruby_block)
|
637
|
+
aux = self
|
638
|
+
# Apply the ruby block of each element if any.
|
639
|
+
aux = aux.hmap(&ruby_block) if ruby_block
|
640
|
+
# Do the sum.
|
641
|
+
if initial_value then
|
642
|
+
return aux.hinject(initial_value,&:+)
|
643
|
+
else
|
644
|
+
return aux.hinject(&:+)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
# The HW implementation of the Ruby take.
|
649
|
+
def htake(n)
|
650
|
+
return self[0..n-1]
|
651
|
+
end
|
652
|
+
|
653
|
+
# The HW implementation of the Ruby take_while.
|
654
|
+
def htake_while(&ruby_block)
|
655
|
+
raise "htake_while is not supported yet."
|
656
|
+
end
|
657
|
+
|
658
|
+
# HW implementation of the Ruby tally.
|
659
|
+
# NOTE: to do, or may be not.
|
660
|
+
def htally(h = nil)
|
661
|
+
raise "htally is not supported yet."
|
662
|
+
end
|
663
|
+
|
664
|
+
# HW implementation of the Ruby to_h.
|
665
|
+
# NOTE: to do, or may be not.
|
666
|
+
def hto_h(h = nil)
|
667
|
+
raise "hto_h is not supported yet."
|
668
|
+
end
|
669
|
+
|
670
|
+
# HW implementation of the Ruby uniq.
|
671
|
+
def huniq(&ruby_block)
|
672
|
+
raise "huniq is not supported yet."
|
673
|
+
end
|
674
|
+
|
675
|
+
# HW implementation of the Ruby zip.
|
676
|
+
# NOTE: for now szip is deactivated untile tuples are properly
|
677
|
+
# handled by HDLRuby.
|
678
|
+
def hzip(obj,&ruby_block)
|
679
|
+
size = self.hsize
|
680
|
+
ar = obj.hto_a
|
681
|
+
if ar.size > 0 then
|
682
|
+
typ = ar[0].type
|
683
|
+
else
|
684
|
+
typ = self.type.base
|
685
|
+
end
|
686
|
+
# Fills the obj array with 0 until its size match self's.
|
687
|
+
ar << 0.to_expr.as(typ) while ar.size < size
|
688
|
+
if ruby_block then
|
689
|
+
# There is a block to apply.
|
690
|
+
return self.hto_a.zip(ar,&ruby_block)
|
691
|
+
else
|
692
|
+
# There is no block to apply generate an two level array.
|
693
|
+
return self.hto_a.zip(ar)
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
# Iterator on the +num+ next elements.
|
698
|
+
# *NOTE*:
|
699
|
+
# - Stop iteration when the end of the range is reached or when there
|
700
|
+
# are no elements left
|
701
|
+
# - This is not a method from Ruby but one specific for hardware where
|
702
|
+
# creating a array is very expensive.
|
703
|
+
def heach_nexts(num,&ruby_block)
|
704
|
+
raise "heach_nexts is not supported yet."
|
705
|
+
end
|
706
|
+
|
707
|
+
end
|
708
|
+
|
709
|
+
|
710
|
+
# Describes hardware enumerator classes that allows to
|
711
|
+
# generate HW iteration over HW or SW objects.
|
712
|
+
|
713
|
+
# This is the abstract Enumerator class.
|
714
|
+
class HEnumerator
|
715
|
+
include HEnumerable
|
716
|
+
|
717
|
+
# The methods that need to be defined.
|
718
|
+
[:size, :type, :clone, :hto_a].each do |name|
|
719
|
+
define_method(:name) do
|
720
|
+
raise "Method '#{name}' must be defined for a valid sequencer enumerator."
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
# Iterate on each element.
|
725
|
+
def heach(&ruby_block)
|
726
|
+
# No block given, returns self.
|
727
|
+
return self unless ruby_block
|
728
|
+
return self.hto_a.each(&ruby_block)
|
729
|
+
end
|
730
|
+
|
731
|
+
# Iterator on each of the elements in range +rng+.
|
732
|
+
# *NOTE*:
|
733
|
+
# - Stop iteration when the end of the range is reached or when there
|
734
|
+
# are no elements left
|
735
|
+
# - This is not a method from Ruby but one specific for hardware where
|
736
|
+
# creating a array is very expensive.
|
737
|
+
def heach_range(rng,&ruby_block)
|
738
|
+
# No block given, returns a new enumerator.
|
739
|
+
return HEnumeratorWrapper.new(self,:heach_range) unless ruby_block
|
740
|
+
return self.to_a.each_range(rng,&ruby_block)
|
741
|
+
end
|
742
|
+
|
743
|
+
# Iterate on each element with arbitrary object +obj+.
|
744
|
+
def heach_with_object(val,&ruby_block)
|
745
|
+
return self.with_object(val,&ruby_block)
|
746
|
+
end
|
747
|
+
|
748
|
+
# Iterates with an index.
|
749
|
+
def with_index(&ruby_block)
|
750
|
+
# No block given, returns a new enumerator.
|
751
|
+
return HEnumeratorWrapper.new(self,:with_index) unless ruby_block
|
752
|
+
# return self.hto_a.each_with_index(&ruby_block)
|
753
|
+
i = 0
|
754
|
+
return self.heach do |e|
|
755
|
+
res = ruby_block.call(e,i)
|
756
|
+
i += 1
|
757
|
+
res
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
# Return a new SEnumerator with an arbitrary arbitrary object +obj+.
|
762
|
+
def with_object(obj)
|
763
|
+
# No block given, returns a new enumerator.
|
764
|
+
return HEnumeratorWrapper.new(self,:with_object) unless ruby_block
|
765
|
+
# return self.hto_a.each_with_object(&ruby_block)
|
766
|
+
return self.heach do |e|
|
767
|
+
ruby_block.call(e,obj)
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
# Return a new HEnumerator going on iteration over enumerable +obj+
|
772
|
+
def +(obj)
|
773
|
+
return self.hto_a + obj.hto_a
|
774
|
+
end
|
775
|
+
end
|
776
|
+
|
777
|
+
|
778
|
+
# This is the wrapper Enumerator over an other one for applying an
|
779
|
+
# other interation method over the first one.
|
780
|
+
class HEnumeratorWrapper < HEnumerator
|
781
|
+
|
782
|
+
# Create a new SEnumerator wrapper over +enum+ with +iter+ iteration
|
783
|
+
# method and +args+ argument.
|
784
|
+
def initialize(enum,iter,*args)
|
785
|
+
if enum.is_a?(HEnumerator) then
|
786
|
+
@enumerator = enum.clone
|
787
|
+
else
|
788
|
+
@enumerator = enum.heach
|
789
|
+
end
|
790
|
+
@iterator = iter.to_sym
|
791
|
+
@arguments = args
|
792
|
+
end
|
793
|
+
|
794
|
+
# The directly delegate methods.
|
795
|
+
def size
|
796
|
+
return @enumertor.size
|
797
|
+
end
|
798
|
+
alias_method :hsize, :size
|
799
|
+
|
800
|
+
def type
|
801
|
+
return @enumerator.type
|
802
|
+
end
|
803
|
+
|
804
|
+
def hto_a
|
805
|
+
res = []
|
806
|
+
self.heach { |e| res << e }
|
807
|
+
return res
|
808
|
+
end
|
809
|
+
|
810
|
+
# Iterator on each of the elements in range +rng+.
|
811
|
+
# *NOTE*:
|
812
|
+
# - Stop iteration when the end of the range is reached or when there
|
813
|
+
# are no elements left
|
814
|
+
# - This is not a method from Ruby but one specific for hardware where
|
815
|
+
# creating a array is very expensive.
|
816
|
+
def heach_range(rng,&ruby_block)
|
817
|
+
return @enumerator.heach_range(rng,&ruby_block)
|
818
|
+
end
|
819
|
+
|
820
|
+
# Clones the enumerator.
|
821
|
+
def clone
|
822
|
+
return HEnumeratorWrapper.new(@enumerator,@iterator,*@arguments)
|
823
|
+
end
|
824
|
+
|
825
|
+
# Iterate over each element.
|
826
|
+
def heach(&ruby_block)
|
827
|
+
# No block given, returns self.
|
828
|
+
return self unless ruby_block
|
829
|
+
# A block is given, iterate.
|
830
|
+
return @enumerator.send(@iterator,*@arguments,&ruby_block)
|
831
|
+
end
|
832
|
+
end
|
833
|
+
|
834
|
+
|
835
|
+
module HDLRuby::High::HRef
|
836
|
+
# Enhance the HRef module with sequencer iteration.
|
837
|
+
# Properties of expressions are also required
|
838
|
+
def self.included(klass)
|
839
|
+
klass.class_eval do
|
840
|
+
include HEnumerable
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
844
|
+
# Convert to an array.
|
845
|
+
alias_method :hto_a, :to_a
|
846
|
+
|
847
|
+
# Size.
|
848
|
+
def hsize
|
849
|
+
self.type.size
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
|
854
|
+
module ::Enumerable
|
855
|
+
# Enhance the Enumerable module with sequencer iteration.
|
856
|
+
|
857
|
+
# Conversion to array.
|
858
|
+
alias_method :hto_a, :to_a
|
859
|
+
|
860
|
+
# Size.
|
861
|
+
def hsize
|
862
|
+
self.to_a.size
|
863
|
+
end
|
864
|
+
|
865
|
+
# Also adds the methods of HEnumerable.
|
866
|
+
HEnumerable.instance_methods.each do |meth|
|
867
|
+
define_method(meth,HEnumerable.instance_method(meth))
|
868
|
+
end
|
869
|
+
end
|
870
|
+
|
871
|
+
|
872
|
+
class ::Range
|
873
|
+
# Enhance the Range class with sequencer iteration.
|
874
|
+
include HEnumerable
|
875
|
+
|
876
|
+
# Conversion to array.
|
877
|
+
def hto_a
|
878
|
+
res = []
|
879
|
+
self.heach { |i| res << i }
|
880
|
+
return res
|
881
|
+
end
|
882
|
+
|
883
|
+
# Redefinition of heach to support also HDLRuby Values.
|
884
|
+
def heach(&ruby_block)
|
885
|
+
if self.first.is_a?(Value) or self.last.is_a?(Value) then
|
886
|
+
# No block given.
|
887
|
+
return self unless ruby_block
|
888
|
+
# A block is given, iterate on each element of the range
|
889
|
+
# converted to values of the right type.
|
890
|
+
if first.is_a?(Value) then
|
891
|
+
typ = self.first.type
|
892
|
+
else
|
893
|
+
typ = self.last.type
|
894
|
+
end
|
895
|
+
first = self.first.to_i
|
896
|
+
last = self.last.to_i
|
897
|
+
(first..last).each do |i|
|
898
|
+
ruby_block.call(i.as(typ))
|
899
|
+
end
|
900
|
+
else
|
901
|
+
return self.each(&ruby_block)
|
902
|
+
end
|
903
|
+
end
|
904
|
+
|
905
|
+
# Size.
|
906
|
+
alias_method :hsize, :size
|
907
|
+
end
|
908
|
+
|
909
|
+
|
910
|
+
|
911
|
+
class ::Integer
|
912
|
+
# Enhance the Integer class with sequencer iterations.
|
913
|
+
|
914
|
+
# HW times iteration.
|
915
|
+
alias_method :htimes, :times
|
916
|
+
|
917
|
+
# HW upto iteration.
|
918
|
+
alias_method :hupto, :upto
|
919
|
+
|
920
|
+
# HW downto iteration.
|
921
|
+
alias_method :hdownto, :downto
|
922
|
+
end
|
923
|
+
|
924
|
+
end
|