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.
@@ -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