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