HDLRuby 2.2.17 → 2.3.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.
@@ -157,6 +157,13 @@ extern Value mul_value(Value src0, Value src1, Value dst);
157
157
  * @return dst */
158
158
  extern Value div_value(Value src0, Value src1, Value dst);
159
159
 
160
+ /** Computes the modulo of two general values.
161
+ * @param src0 the first source value of the addition
162
+ * @param src1 the second source value of the addition
163
+ * @param dst the destination value
164
+ * @return dst */
165
+ extern Value mod_value(Value src0, Value src1, Value dst);
166
+
160
167
  /** Computes the not of a value.
161
168
  * @param src the source value of the not
162
169
  * @param dst the destination value
@@ -397,6 +397,9 @@ static Value set_undefined_bitstring(Value dst) {
397
397
 
398
398
  /* set the type and size of the destination. */
399
399
  dst->numeric = 0;
400
+ /* Ensures the buffer of dst has the write size (in cas it was a fromer
401
+ * numeric for example). */
402
+ resize_value(dst,width);
400
403
 
401
404
  /* Get access to the destination data. */
402
405
  char* dst_data = dst->data_str;
@@ -604,7 +607,7 @@ static Value mul_value_defined_bitstring(Value src0, Value src1, Value dst) {
604
607
  dst->type = src0->type;
605
608
  dst->numeric = 1;
606
609
 
607
- /* Perform the addition. */
610
+ /* Perform the multiplication. */
608
611
  dst->data_int = value2integer(src0) * value2integer(src1);
609
612
  return dst;
610
613
  }
@@ -620,12 +623,29 @@ static Value div_value_defined_bitstring(Value src0, Value src1, Value dst) {
620
623
  dst->type = src0->type;
621
624
  dst->numeric = 1;
622
625
 
623
- /* Perform the addition. */
626
+ /* Perform the division. */
624
627
  dst->data_int = value2integer(src0) / value2integer(src1);
625
628
  return dst;
626
629
  }
627
630
 
628
631
 
632
+ /** Computes the modulo of two defined bitstring values.
633
+ * @param src0 the first source value of the addition
634
+ * @param src1 the second source value of the addition
635
+ * @param dst the destination value
636
+ * @return dst */
637
+ static Value mod_value_defined_bitstring(Value src0, Value src1, Value dst) {
638
+ /* Sets state of the destination using the first source. */
639
+ dst->type = src0->type;
640
+ dst->numeric = 1;
641
+
642
+ /* Perform the modulo. */
643
+ // printf("modulo with src0=%lld src1=%lld, result=%lld\n",value2integer(src0),value2integer(src1),value2integer(src0) % value2integer(src1));
644
+ dst->data_int = value2integer(src0) % value2integer(src1);
645
+ return dst;
646
+ }
647
+
648
+
629
649
  /** Computes the lesser comparision of two defined bitstring values.
630
650
  * @param src0 the first source value of the addition
631
651
  * @param src1 the second source value of the addition
@@ -1415,7 +1435,10 @@ fix_numeric_type(Type type, unsigned long long val) {
1415
1435
  /* Get the width of the type. */
1416
1436
  int width = type_width(type);
1417
1437
  /* Compute the base mask. */
1418
- unsigned long long mask = ((unsigned long long)(-1)) << width;
1438
+ // unsigned long long mask = ((unsigned long long)(-1)) << width;
1439
+ /* NOTE: (ull)-1 << 64 becomes (ull)-1 on Intel processors, this is
1440
+ * totally not what I expected (I expected 0). */
1441
+ unsigned long long mask = width == 64 ? 0 : ((unsigned long long)(-1)) << width;
1419
1442
  // printf("width=%i val=%llu mask=%llx\n",width,val,mask);
1420
1443
 
1421
1444
  /* Is the type signed? */
@@ -1516,6 +1539,23 @@ static Value div_value_numeric(Value src0, Value src1, Value dst) {
1516
1539
  }
1517
1540
 
1518
1541
 
1542
+ /** Computes the modulo of two numeric values.
1543
+ * @param src0 the first source value of the addition
1544
+ * @param src1 the second source value of the addition
1545
+ * @param dst the destination value
1546
+ * @return dst */
1547
+ static Value mod_value_numeric(Value src0, Value src1, Value dst) {
1548
+ /* Sets state of the destination using the first source. */
1549
+ dst->type = src0->type;
1550
+ dst->numeric = 1;
1551
+
1552
+ /* Perform the division. */
1553
+ // printf("modulo numeric with src0=%lld src1=%lld, result=%lld\n",src0->data_int, src1->data_int,src0->data_int % src1->data_int);
1554
+ dst->data_int = fix_numeric_type(dst->type, src0->data_int % src1->data_int);
1555
+ return dst;
1556
+ }
1557
+
1558
+
1519
1559
  /** Computes the NOT of a numeric value.
1520
1560
  * @param src the source value of the not
1521
1561
  * @param dst the destination value
@@ -1690,7 +1730,7 @@ static Value concat_value_numeric_array(int num, int dir,
1690
1730
  unsigned int i,pos;
1691
1731
  /* Compute the bit width of the destination. */
1692
1732
  unsigned int width = 0;
1693
- // printf("concat_value_numeric with dir=%d\n",dir);
1733
+ // printf("concat_value_numeric with dir=%d and width=%llu\n",dir,type_width(args[0]->type));
1694
1734
  for(i=0; i<num; ++i) width += type_width(args[i]->type);
1695
1735
 
1696
1736
  /* Sets state of the destination using the bit width. */
@@ -1714,6 +1754,7 @@ static Value concat_value_numeric_array(int num, int dir,
1714
1754
  pos += arg_width;
1715
1755
  }
1716
1756
  /* Return the destination. */
1757
+ // printf("Result is dst=%llx\n",dst->data_int);
1717
1758
  return dst;
1718
1759
  }
1719
1760
 
@@ -1724,6 +1765,7 @@ static Value concat_value_numeric_array(int num, int dir,
1724
1765
  * @param dst the destination value
1725
1766
  * @return dst */
1726
1767
  static Value cast_value_numeric(Value src, Type type, Value dst) {
1768
+ // printf("cast_value_numeric with src=%llx",src->data_int);
1727
1769
  /* Copy the source to the destination. */
1728
1770
  dst->data_int = src->data_int;
1729
1771
  /* Update the destination type to the cast. */
@@ -1783,6 +1825,7 @@ static int same_content_value_range_numeric(Value value0,
1783
1825
  * @return dst */
1784
1826
  Value read_range_numeric(Value value, long long first, long long last,
1785
1827
  Type base, Value dst) {
1828
+ /* printf("read_range_numeric with value=%llx and first=%llu and last=%llu\n",value->data_int,first,last); */
1786
1829
  /* Ensure first is the smaller. */
1787
1830
  if (first > last) {
1788
1831
  long long tmp = last;
@@ -1795,15 +1838,18 @@ Value read_range_numeric(Value value, long long first, long long last,
1795
1838
  unsigned long long bw = type_width(base);
1796
1839
  /* Scale the range according to the base type. */
1797
1840
  first *= bw;
1841
+ last *= bw;
1798
1842
  length *= bw;
1799
- // printf("first=%lld last=%lld bw=%llu length=%lld\n",first,last,bw,length);
1843
+ /* printf("first=%lld last=%lld bw=%llu length=%lld\n",first,last,bw,length); */
1800
1844
 
1801
1845
  /* Set the type and size of the destination from the type of the source.*/
1802
1846
  dst->type = make_type_vector(get_type_bit(),length);
1803
1847
  dst->numeric = 1;
1804
1848
 
1805
1849
  /* Compute the read mask. */
1806
- unsigned long long mask = ((-1LL) << first) & (~((-1LL) << (last+1)));
1850
+ // unsigned long long mask = ((-1LL) << first) & (~((-1LL) << (last+1)));
1851
+ /* NOTE: once again, << 64 does not work like expected. */
1852
+ unsigned long long mask = mask+bw < 64 ? (~((-1LL) << (last+bw))) : -1LL;
1807
1853
  /* Performs the read. */
1808
1854
  unsigned long long data = (value->data_int & mask) >> first;
1809
1855
  /* Write it to the destination. */
@@ -1999,6 +2045,33 @@ Value div_value(Value src0, Value src1, Value dst) {
1999
2045
  }
2000
2046
 
2001
2047
 
2048
+ /** Computes the modulo of two general values.
2049
+ * @param src0 the first source value of the addition
2050
+ * @param src1 the second source value of the addition
2051
+ * @param dst the destination value
2052
+ * @return dst */
2053
+ Value mod_value(Value src0, Value src1, Value dst) {
2054
+ /* Might allocate a new value so save the current pool state. */
2055
+ unsigned int pos = get_value_pos();
2056
+ /* Do a numeric computation if possible, otherwise fallback to bitstring
2057
+ * computation. */
2058
+ if (src0->numeric && src1->numeric) {
2059
+ /* Both sources are numeric. */
2060
+ return mod_value_numeric(src0,src1,dst);
2061
+ } else if (is_defined_value(src0) && is_defined_value(src1)) {
2062
+ /* Both sources can be converted to numeric values. */
2063
+ return mod_value_defined_bitstring(src0,src1,dst);
2064
+ } else {
2065
+ /* Cannot compute (for now), simply undefines the destination. */
2066
+ /* First ensure dst has the right shape. */
2067
+ copy_value(src0,dst);
2068
+ /* Then make it undefined. */
2069
+ set_undefined_bitstring(dst);
2070
+ }
2071
+ return dst;
2072
+ }
2073
+
2074
+
2002
2075
  /** Computes the NOT of a general value.
2003
2076
  * @param src the source value of the not
2004
2077
  * @param dst the destination value
@@ -81,9 +81,17 @@ module HDLRuby::High::Std
81
81
  end
82
82
 
83
83
 
84
- ##
85
- # Module for wrapping channel ports.
86
- module ChannelPortWrapping
84
+ # ##
85
+ # # Module for wrapping channel ports.
86
+ # module ChannelPortWrapping
87
+ # # Wrap with +args+ arguments.
88
+ # def wrap(*args)
89
+ # return ChannelPortB.new(self,*args)
90
+ # end
91
+ # end
92
+
93
+ ## Describes a channel port.
94
+ class ChannelPort
87
95
  # Wrap with +args+ arguments.
88
96
  def wrap(*args)
89
97
  return ChannelPortB.new(self,*args)
@@ -93,8 +101,8 @@ module HDLRuby::High::Std
93
101
 
94
102
  ##
95
103
  # Describes a read port to a channel.
96
- class ChannelPortR
97
- include ChannelPortWrapping
104
+ class ChannelPortR < ChannelPort
105
+ # include ChannelPortWrapping
98
106
 
99
107
  # Creates a new channel reader running in +namespace+ and
100
108
  # reading using +reader_proc+ and reseting using +reseter_proc+.
@@ -137,8 +145,8 @@ module HDLRuby::High::Std
137
145
 
138
146
  ##
139
147
  # Describes a writer port to a channel.
140
- class ChannelPortW
141
- include ChannelPortWrapping
148
+ class ChannelPortW < ChannelPort
149
+ # include ChannelPortWrapping
142
150
 
143
151
  # Creates a new channel writer running in +namespace+ and
144
152
  # writing using +writer_proc+ and reseting using +reseter_proc+.
@@ -181,8 +189,8 @@ module HDLRuby::High::Std
181
189
 
182
190
  ##
183
191
  # Describes an access port to a channel.
184
- class ChannelPortA
185
- include ChannelPortWrapping
192
+ class ChannelPortA < ChannelPort
193
+ # include ChannelPortWrapping
186
194
 
187
195
  # Creates a new channel accesser running in +namespace+
188
196
  # and reading using +reader_proc+, writing using +writer_proc+,
@@ -243,8 +251,8 @@ module HDLRuby::High::Std
243
251
 
244
252
  ##
245
253
  # Describes port wrapper (Box) for fixing arugments.
246
- class ChannelPortB
247
- include ChannelPortWrapping
254
+ class ChannelPortB < ChannelPort
255
+ # include ChannelPortWrapping
248
256
 
249
257
  # Creates a new channel box over channel port +port+ fixing +args+
250
258
  # as arguments.
@@ -600,13 +608,23 @@ module HDLRuby::High::Std
600
608
 
601
609
  # Defines a branch in the channel named +name+ built executing
602
610
  # +ruby_block+.
603
- def brancher(name,&ruby_block)
611
+ # Alternatively, a ready channel instance can be passed as argument
612
+ # as +channelI+.
613
+ def brancher(name,channelI = nil,&ruby_block)
604
614
  # Ensure name is a symbol.
605
615
  name = name.to_s unless name.respond_to?(:to_sym)
606
616
  name = name.to_sym
607
- # Create the branch.
608
- channelI = HDLRuby::High.channel_instance(name, &ruby_block)
617
+ # Is there a ready channel instance.
618
+ if channelI then
619
+ # Yes, use it directly.
620
+ @branches[name] = channelI
621
+ return self
622
+ end
623
+ # No, create the branch.
624
+ # channelI = HDLRuby::High.channel_instance(name, &ruby_block)
625
+ channelI = HDLRuby::High::Std.channel_instance(name, &ruby_block)
609
626
  @branches[name] = channelI
627
+ return self
610
628
  end
611
629
 
612
630
 
@@ -619,6 +637,7 @@ module HDLRuby::High::Std
619
637
  name = name.to_s unless name.respond_to?(:to_sym)
620
638
  name = name.to_sym
621
639
  # Get the branch.
640
+ channelI = @branches[name]
622
641
  return @branches[name]
623
642
  end
624
643
 
@@ -902,7 +921,7 @@ module HDLRuby::High::Std
902
921
 
903
922
 
904
923
  # Wrapper to make an object run like a channel port.
905
- class ChannelPortObject
924
+ class ChannelPortObject < ChannelPort
906
925
  # Create a new object wrapper for +obj+.
907
926
  def initialize(obj)
908
927
  @obj = obj
@@ -946,9 +965,13 @@ module HDLRuby::High::Std
946
965
 
947
966
 
948
967
  # Wrap object +obj+ to act like a channel port.
949
- def channel_port(obj)
968
+ def self.channel_port(obj)
969
+ return obj if obj.is_a?(ChannelPort) # No need to wrap.
950
970
  return ChannelPortObject.new(obj)
951
971
  end
972
+ def channel_port(obj)
973
+ return HDLRuby::High::Std.channel_port(obj)
974
+ end
952
975
  end
953
976
 
954
977
 
@@ -26,17 +26,18 @@ module HDLRuby::High::Std
26
26
  if args.size == 1 then
27
27
  return self.send(:"_[]_fixpoint",*args)
28
28
  else
29
- # Handle the arguments.
29
+ # Handle the arguments and compute the fix point sizes.
30
30
  arg0,arg1 = *args
31
31
  if arg0.respond_to?(:to_i) then
32
- arg0 = (arg0.to_i.abs-1)..0
32
+ isize = arg0
33
+ else
34
+ isize = (arg0.first-arg0.last).abs+1
33
35
  end
34
36
  if arg1.respond_to?(:to_i) then
35
- arg1 = (arg1.to_i.abs-1)..0
37
+ fsize = arg1
38
+ else
39
+ fsize = (arg1.first-arg1.last).abs+1
36
40
  end
37
- # Compute the fix point sizes.
38
- isize = (arg0.first-arg0.last).abs+1
39
- fsize = (arg1.first-arg1.last).abs+1
40
41
  # Build the type.
41
42
  case(self.name)
42
43
  when :bit
@@ -244,6 +244,74 @@ module HDLRuby::High::Std
244
244
  end
245
245
 
246
246
 
247
+ # Declares a simple pipelined multiple mac with single right data.
248
+ #
249
+ # Can be used for the product of a martix-vector product.
250
+ function :mac_np do |typ,ev,req,ack,lefts, rights, last,
251
+ mul = proc { |x,y| x*y }, add = proc { |x,y| x+y }|
252
+ # Ensure ev is really an event.
253
+ ev = ev.posedge unless ev.is_a?(Event)
254
+ # Ensures lefts is an array.
255
+ lefts = lefts.to_a
256
+ # Ensures rights is an array.
257
+ rights = rights.to_a
258
+ # Get the size of the pipeline and ensure lefts and rights have the
259
+ # same.
260
+ size = lefts.size
261
+ if (rights.size != size) then
262
+ raise "Incompatible lefts and rights sizes: lefts size is #{size} and rights size is #{rights.size}"
263
+ end
264
+ # Declares the accumulators.
265
+ accs = size.times.map { |i| typ.inner :"acc#{i}" }
266
+ # Left value and right value.
267
+ lvs = lefts.each_with_index.map { |left,i| typ.inner :"lv#{i}" }
268
+ rvs = rights.each_with_index.map { |right,i| typ.inner :"rv#{i}" }
269
+ # typ.inner :rv
270
+ # lv and rv are valid.
271
+ lvoks = lefts.each_with_index.map { |left,i| inner :"lvok#{i}" }
272
+ # inner :rvok
273
+ rvoks = rights.each_with_index.map { |right,i| inner :"rvok#{i}" }
274
+ # Run flag
275
+ inner :run
276
+ par(ev) do
277
+ ack <= 0
278
+ run <= 0
279
+ hif(req | run) do
280
+ run <= 1
281
+ # Computation request.
282
+ lefts.zip(rights).each_with_index do |(left,right),i|
283
+ left.read(lvs[i]) { lvoks[i] <= 1 }
284
+ right.read(rvs[i]) { rvoks[i] <= 1 }
285
+ hif(lvoks[i] & rvoks[i]) do
286
+ ack <= 1
287
+ run <= 0
288
+ if (i < lefts.size-1) then
289
+ if (i>0) then
290
+ accs[i] <= add.(accs[i],mul.(lvs[i],rvs[i])) +
291
+ accs[i-1]
292
+ else
293
+ accs[i] <= add.(accs[i],mul.(lvs[i],rvs[i]))
294
+ end
295
+ else
296
+ # The last is reached
297
+ seq do
298
+ accs[i] <= add.(accs[i],mul.(lvs[i],rvs[i]))
299
+ last.write(accs[i])
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end
305
+ helse do
306
+ lefts.each_with_index do |left,i|
307
+ lvoks[i] <= 0
308
+ rvoks[i] <= 0
309
+ accs[i] <= 0
310
+ end
311
+ end
312
+ end
313
+ end
314
+
247
315
 
248
316
 
249
317
  end
@@ -0,0 +1,101 @@
1
+ require 'std/task.rb'
2
+
3
+
4
+
5
+ ##
6
+ # Standard HDLRuby::High library: loops encapsulated in tasks.
7
+ #
8
+ ########################################################################
9
+
10
+ ## While loop: loops until +condition+ is met execution +ruby_block+.
11
+ # The loop is synchronized on +clk_e+ and initialized by +init+.
12
+ # If +condition+ is nil, then +init+ is used as +condition+.
13
+ HDLRuby::High::Std.task(:while_task) do |clk_e, init, condition, ruby_block|
14
+ # Ensure clk_e is an event, if not set it to a positive edge.
15
+ clk_e = clk_e.posedge unless clk_e.is_a?(Event)
16
+
17
+ # Ensures there is a condition.
18
+ unless condition then
19
+ condition = init
20
+ init = nil
21
+ end
22
+
23
+ # Transform condition into a proc if it is not the case.
24
+ unless condition.is_a?(Proc) then
25
+ condition_expr = condition
26
+ condition = proc { condition_expr }
27
+ end
28
+
29
+ # Ensures init to be a proc if not nil
30
+ init = init.to_proc unless init == nil
31
+
32
+ # Declares the signals for controlling the loop.
33
+ inner :req # Signal to set to 1 for running the loop.
34
+
35
+ # Declares the runner signals.
36
+ runner_output :req
37
+
38
+ par(clk_e) do
39
+ # Performs the loop.
40
+ hif(req) do
41
+ # By default the loop is not finished.
42
+ # If the condition is still met go on looping.
43
+ hif(condition.call,&ruby_block)
44
+ end
45
+ # # if (init) then
46
+ # # # There is an initialization, do it when there is no req.
47
+ # # helse do
48
+ # # init.call
49
+ # # end
50
+ # # end
51
+ end
52
+
53
+ # The code for reseting the task.
54
+ if (init) then
55
+ # reseter(&init)
56
+ reseter do
57
+ req <= 0
58
+ init.call
59
+ end
60
+ end
61
+
62
+ # The code for running the task.
63
+ runner do
64
+ # top_block.unshift { req <= 0 }
65
+ req <= 1
66
+ end
67
+
68
+ # The code for checking the end of execution.
69
+ finisher do |blk|
70
+ hif(~condition.call,&blk)
71
+ end
72
+
73
+ end
74
+
75
+
76
+
77
+ ## A simplified loop: loops until +condition+ is met execution +ruby_block+.
78
+ # The loop is synchronized on +clk_e+ and initialized by +init+.
79
+ # If +condition+ is nil, then +init+ is used as +condition+.
80
+ def while_loop(clk_e, init, condition = nil, &ruby_block)
81
+ # Create the loop task.
82
+ tsk = while_task(clk_e,init,condition,ruby_block).(HDLRuby.uniq_name)
83
+ # Create the inner access port.
84
+ prt = tsk.inner HDLRuby.uniq_name
85
+ # Return the access port.
86
+ return prt
87
+ end
88
+
89
+ ## Loop +num+ times executing +ruby_block+.
90
+ # The loop is synchronized on +clk_e+.
91
+ def times_loop(clk_e, num, &ruby_block)
92
+ # Compute the width of the counter.
93
+ width = num.respond_to?(:width) ? num.width : num.type.width
94
+ # Declares the counter.
95
+ cnt = [width].inner(HDLRuby.uniq_name)
96
+ # Create the loop.
97
+ return while_loop(clk_e, proc{cnt<=0}, cnt<num) do
98
+ cnt <= cnt + 1
99
+ ruby_block.call
100
+ end
101
+ end