HDLRuby 2.2.13 → 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.
@@ -81,11 +81,19 @@ module HDLRuby::High::Std
81
81
  end
82
82
 
83
83
 
84
- ##
85
- # Module for boxing channel ports.
86
- module ChannelPortBoxing
87
- # Box with +args+ arguments.
88
- def box(*args)
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
95
+ # Wrap with +args+ arguments.
96
+ def wrap(*args)
89
97
  return ChannelPortB.new(self,*args)
90
98
  end
91
99
  end
@@ -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 ChannelPortBoxing
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 ChannelPortBoxing
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 ChannelPortBoxing
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+,
@@ -242,32 +250,61 @@ module HDLRuby::High::Std
242
250
 
243
251
 
244
252
  ##
245
- # Describes port box (wrapper) for fixing arugments.
246
- class ChannelPortB
247
- include ChannelPortBoxing
253
+ # Describes port wrapper (Box) for fixing arugments.
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.
259
+ # +args+ is a list of arguments to apply to all read, write
260
+ # and access procedure, nil values meaning that the corresponding
261
+ # argument is not overwritten.
262
+ # It can also be three lists for seperate read, write and access
263
+ # procedures using named arguments as:
264
+ # read: <read arguments>, write: <write arguments>,
265
+ # access: <access arguments>
251
266
  def initialize(port,*args)
252
267
  # Ensure port is a channel port.
253
268
  unless port.is_a?(ChannelPortR) || port.is_a?(ChannelPortW) ||
254
- port.is_a?(ChannelPortA)
269
+ port.is_a?(ChannelPortA) || port.is_a?(ChannelPortB)
255
270
  raise "Invalid class for a channel port: #{port.class}"
256
271
  end
257
272
  @port = port
258
- @args = args
273
+ # Process the arguments.
274
+ if args.size == 1 && args[0].is_a?(Hash) then
275
+ # Read, write and access are separated.
276
+ @args_read = args[0][:read]
277
+ @args_write = args[0][:write]
278
+ @args_access = args[0][:access]
279
+ else
280
+ @args_read = args
281
+ @args_write = args.clone
282
+ @args_access = args.clone
283
+ end
259
284
  end
260
285
 
261
286
  ## Performs a read on the channel using +args+ and +ruby_block+
262
287
  # as arguments.
263
288
  def read(*args,&ruby_block)
264
- @port.read(*@args,*args)
289
+ # Generate the final arguments: fills the nil with arguments
290
+ # from args
291
+ rargs = @args_read.clone
292
+ rargs.map! { |arg| arg == nil ? args.shift : arg }
293
+ # And add the remaining at the tail.
294
+ rargs += args
295
+ @port.read(*rargs,&ruby_block)
265
296
  end
266
297
 
267
298
  ## Performs a write on the channel using +args+ and +ruby_block+
268
299
  # as arguments.
269
300
  def write(*args,&ruby_block)
270
- @port.write(*@args,*args)
301
+ # Generate the final arguments: fills the nil with arguments
302
+ # from args
303
+ rargs = @args_write.clone
304
+ rargs.map! { |arg| arg == nil ? args.shift : arg }
305
+ # And add the remaining at the tail.
306
+ rargs += args
307
+ @port.write(*rargs,&ruby_block)
271
308
  end
272
309
 
273
310
  ## Performs a reset on the channel using +args+ and +ruby_block+
@@ -571,13 +608,23 @@ module HDLRuby::High::Std
571
608
 
572
609
  # Defines a branch in the channel named +name+ built executing
573
610
  # +ruby_block+.
574
- 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)
575
614
  # Ensure name is a symbol.
576
615
  name = name.to_s unless name.respond_to?(:to_sym)
577
616
  name = name.to_sym
578
- # Create the branch.
579
- 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)
580
626
  @branches[name] = channelI
627
+ return self
581
628
  end
582
629
 
583
630
 
@@ -590,6 +637,7 @@ module HDLRuby::High::Std
590
637
  name = name.to_s unless name.respond_to?(:to_sym)
591
638
  name = name.to_sym
592
639
  # Get the branch.
640
+ channelI = @branches[name]
593
641
  return @branches[name]
594
642
  end
595
643
 
@@ -872,29 +920,81 @@ module HDLRuby::High::Std
872
920
  end
873
921
 
874
922
 
875
- end
876
-
877
-
878
- module HDLRuby::High
923
+ # Wrapper to make an object run like a channel port.
924
+ class ChannelPortObject < ChannelPort
925
+ # Create a new object wrapper for +obj+.
926
+ def initialize(obj)
927
+ @obj = obj
928
+ end
879
929
 
880
- ## Enhance expressions with possibility to act like a reading branch.
881
- module HExpression
882
- ## Transmits the expression to +target+ and execute +ruby_block+ if
883
- # any.
884
- def read(target,&ruby_block)
885
- target <= self
886
- ruby_block.call if ruby_block
930
+ # Port read with arguments +args+ executing +ruby_block+ in
931
+ # case of success.
932
+ def read(*args,&ruby_block)
933
+ # Get the target from the arguments.
934
+ target = args.pop
935
+ # Is there any argument left?
936
+ unless (args.empty?) then
937
+ # There are arguments left, perform an array access.
938
+ target <= @obj[*args]
939
+ else
940
+ # There are no argument left, perform a direct access.
941
+ target <= @obj
942
+ end
943
+ # Execute the ruby_block if any.
944
+ ruby_block.call if ruby_block
945
+ end
946
+
947
+ # Port write with argumnet +Args+ executing +ruby_block+ in
948
+ # case of success.
949
+ def write(*args,&ruby_block)
950
+ # Get the value to write from the arguments.
951
+ value = args.pop
952
+ # Is there any argument left?
953
+ unless (args.empty?) then
954
+ # There are arguments left, perform an array access.
955
+ @obj[*args] <= value
956
+ else
957
+ # There are no argument left, perform a direct access.
958
+ @obj <= value
959
+ end
960
+ # Execute the ruby_block if any.
961
+ ruby_block.call if ruby_block
887
962
  end
963
+
888
964
  end
889
965
 
890
966
 
891
- ## Enhance references with possibility to act like a writing branch.
892
- module HRef
893
- ## Transmits +target+ to the reference and execute +ruby_block+ if
894
- # any.
895
- def write(target,&ruby_block)
896
- self <= target
897
- ruby_block.call if ruby_block
898
- end
967
+ # Wrap object +obj+ to act like a channel port.
968
+ def self.channel_port(obj)
969
+ return obj if obj.is_a?(ChannelPort) # No need to wrap.
970
+ return ChannelPortObject.new(obj)
971
+ end
972
+ def channel_port(obj)
973
+ return HDLRuby::High::Std.channel_port(obj)
899
974
  end
900
975
  end
976
+
977
+
978
+ # module HDLRuby::High
979
+ #
980
+ # ## Enhance expressions with possibility to act like a reading branch.
981
+ # module HExpression
982
+ # ## Transmits the expression to +target+ and execute +ruby_block+ if
983
+ # # any.
984
+ # def read(target,&ruby_block)
985
+ # target <= self
986
+ # ruby_block.call if ruby_block
987
+ # end
988
+ # end
989
+ #
990
+ #
991
+ # ## Enhance references with possibility to act like a writing branch.
992
+ # module HRef
993
+ # ## Transmits +target+ to the reference and execute +ruby_block+ if
994
+ # # any.
995
+ # def write(target,&ruby_block)
996
+ # self <= target
997
+ # ruby_block.call if ruby_block
998
+ # end
999
+ # end
1000
+ # end
@@ -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
@@ -62,6 +63,14 @@ module HDLRuby::High::Std
62
63
  end
63
64
  end
64
65
 
66
+ # Extends the Numeric class for conversion to fixed point litteral.
67
+ class ::Numeric
68
+ # Convert to fixed point value with +dec+ digits after the decimal
69
+ # point.
70
+ def to_fix(dec)
71
+ return (self * (2**dec.to_i)).to_i
72
+ end
73
+ end
65
74
 
66
75
 
67
76
  end
@@ -0,0 +1,317 @@
1
+ module HDLRuby::High::Std
2
+
3
+
4
+ ##
5
+ # Standard HDLRuby::High library: linear algebra functions.
6
+ #
7
+ # NOTE: require channel-like interface.
8
+ #
9
+ ########################################################################
10
+
11
+ # Controller of the linear operator.
12
+ # - +num+: the number of computation cycles.
13
+ # - +ev+: event to synchronize the controller on.
14
+ # - +req+: the request to start the linear computation.
15
+ # - +ack+: the ack signal that is set to 1 when the computation completes.
16
+ # - +ruby_block+: the code of the linear computation kernel, it takes
17
+ # as argument +ev+, and its own req and ack signals
18
+ # (resp. +req_ker+ +ack_ker+).
19
+ function :linearun do |num,ev,req,ack,ruby_block|
20
+ # Ensure ev is really an event.
21
+ ev = ev.posedge unless ev.is_a?(Event)
22
+
23
+ # Creates the kernel.
24
+ inner :req_ker, :ack_ker
25
+
26
+ HDLRuby::High.top_user.instance_exec(ev,req_ker,ack_ker,&ruby_block)
27
+
28
+ # The computation counter.
29
+ [num.width].inner :count
30
+ # Run flag
31
+ inner :run
32
+ par(ev) do
33
+ req_ker <= 0
34
+ ack <= 0
35
+ count <= 1
36
+ run <= 0
37
+ hif(req | run) do
38
+ run <= 1
39
+ req_ker <= 1
40
+ # Is one linear computation completed?
41
+ hif(ack_ker) do
42
+ # Yes.
43
+ count <= count + 1
44
+ end
45
+ # Is the full computation completed?
46
+ hif(count == num) do
47
+ # Yes.
48
+ ack <= 1
49
+ run <= 0
50
+ req_ker <= 0
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ # Delcares a vector product by a scalar value.
58
+ #
59
+ # Can be used for scaling a vector.
60
+ function :scale do |typ,ev,req,ack,left,rights,prods,
61
+ mul = proc { |x,y| x*y }|
62
+ # Ensure ev is really an event.
63
+ ev = ev.posedge unless ev.is_a?(Event)
64
+ # Ensures rights and prods are arrays.
65
+ rights = rights.to_a
66
+ prods = prods.to_a
67
+ # Left value (the scale) and right value.
68
+ typ.inner :lv
69
+ rvs = rights.each_with_index.map { |left,i| typ.inner :"rv#{i}" }
70
+ # lv and rv are valid.
71
+ inner :lvok
72
+ rvoks = rights.each_with_index.map { |left,i| inner :"rvok#{i}" }
73
+ # Run flag
74
+ inner :run
75
+ par(ev) do
76
+ ack <= 0
77
+ run <= 0
78
+ hif(req | run) do
79
+ run <= 1
80
+ # Computation request.
81
+ left.read(lv) { lvok <= 1 }
82
+ rights.each_with_index do |right,i|
83
+ right.read(rvs[i]) { rvoks[i] <= 1 }
84
+ hif(lvok & rvoks[i]) do
85
+ ack <= 1
86
+ run <= 0
87
+ prods[i].write(mul.(lv,rvs[i]))
88
+ end
89
+ end
90
+ end
91
+ helse do
92
+ lvok <= 0
93
+ rights.each_with_index do |right,i|
94
+ rvoks[i] <= 0
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ # Declares a 1-dimension vector adder.
102
+ #
103
+ # Can be used for the sum of two vectors.
104
+ function :add_n do |typ,ev,req,ack,lefts, rights, sums,
105
+ add = proc { |x,y| x+y }|
106
+ # Ensure ev is really an event.
107
+ ev = ev.posedge unless ev.is_a?(Event)
108
+ # Ensures lefts and rights and sums are arrays.
109
+ lefts = lefts.to_a
110
+ rights = rights.to_a
111
+ sums = sums.to_a
112
+ # Left value and right value.
113
+ lvs = lefts.each_with_index.map { |left,i| typ.inner :"lv#{i}" }
114
+ rvs = lefts.each_with_index.map { |left,i| typ.inner :"rv#{i}" }
115
+ # lv and rv are valid.
116
+ lvoks = lefts.each_with_index.map { |left,i| inner :"lvok#{i}" }
117
+ rvoks = lefts.each_with_index.map { |left,i| inner :"rvok#{i}" }
118
+ # Run flag.
119
+ inner :run
120
+ par(ev) do
121
+ ack <= 0
122
+ run <= 0
123
+ hif(req | run) do
124
+ run <= 1
125
+ # Computation request.
126
+ lefts.zip(rights).each_with_index do |(left,right),i|
127
+ left.read(lvs[i]) { lvoks[i] <= 1 }
128
+ right.read(rvs[i]) { rvoks[i] <= 1 }
129
+ hif(lvoks[i] & rvoks[i]) do
130
+ run <= 0
131
+ ack <= 1
132
+ sums[i].write(add.(lvs[i],rvs[i]))
133
+ end
134
+ end
135
+ end
136
+ helse do
137
+ lefts.each_with_index do |left,i|
138
+ lvoks[i] <= 0
139
+ rvoks[i] <= 0
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ # Declares a 1-dimension vector element-wise multiplier.
146
+ function :mul_n do |typ,ev,req,ack,lefts, rights, prods,
147
+ mul = proc { |x,y| x*y }|
148
+ add_n(typ,ev,req,ack,lefts,rights,prods,mul)
149
+ end
150
+
151
+
152
+ # Declares a simple multiplier accumulator.
153
+ #
154
+ # Can be used for the scalar product of two vectors.
155
+ function :mac do |typ,ev,req,ack,left, right, acc,
156
+ mul = proc { |x,y| x*y }, add = proc { |x,y| x+y }|
157
+ # Ensure ev is really an event.
158
+ ev = ev.posedge unless ev.is_a?(Event)
159
+ # Left value, right value and computation temp value.
160
+ typ.inner :lv, :rv, :av
161
+ # lv and rv are valid.
162
+ inner :lvok, :rvok
163
+ # Run flag
164
+ inner :run
165
+ par(ev) do
166
+ ack <= 0
167
+ run <= 0
168
+ hif(req | run) do
169
+ run <= 1
170
+ # Computation request.
171
+ left.read(lv) { lvok <= 1 }
172
+ right.read(rv) { rvok <= 1 }
173
+ hif(lvok & rvok) do
174
+ ack <= 1
175
+ run <= 0
176
+ # acc.write(add.(av,mul.(lv,rv)))
177
+ seq do
178
+ av <= add.(av,mul.(lv,rv))
179
+ acc.write(av)
180
+ end
181
+ end
182
+ end
183
+ helse do
184
+ lvok <= 0
185
+ rvok <= 0
186
+ # acc.write(0)
187
+ av <= 0
188
+ end
189
+ end
190
+ end
191
+
192
+
193
+ # Declares a simple multiple mac with single right data.
194
+ #
195
+ # Can be used for the product of a martix-vector product.
196
+ function :mac_n1 do |typ,ev,req,ack,lefts, right, accs,
197
+ mul = proc { |x,y| x*y }, add = proc { |x,y| x+y }|
198
+ # Ensure ev is really an event.
199
+ ev = ev.posedge unless ev.is_a?(Event)
200
+ # Ensures lefts is an array.
201
+ lefts = lefts.to_a
202
+ # Ensures accs is an array.
203
+ accs = accs.to_a
204
+ # Left value and right value.
205
+ lvs = lefts.each_with_index.map { |left,i| typ.inner :"lv#{i}" }
206
+ # Accumutated values.
207
+ avs = lefts.each_with_index.map { |left,i| typ.inner :"av#{i}" }
208
+ typ.inner :rv
209
+ # lv and rv are valid.
210
+ lvoks = lefts.each_with_index.map { |left,i| inner :"lvok#{i}" }
211
+ inner :rvok
212
+ # Run flag
213
+ inner :run
214
+ par(ev) do
215
+ ack <= 0
216
+ run <= 0
217
+ hif(req | run) do
218
+ run <= 1
219
+ # Computation request.
220
+ right.read(rv) { rvok <= 1 }
221
+ lefts.each_with_index do |left,i|
222
+ left.read(lvs[i]) { lvoks[i] <= 1 }
223
+ # accs[i].read(avs[i])
224
+ hif(lvoks[i] & rvok) do
225
+ ack <= 1
226
+ run <= 0
227
+ # accs[i].write(add.(avs[i],mul.(lvs[i],rv)))
228
+ seq do
229
+ avs[i] <= add.(avs[i],mul.(lvs[i],rv))
230
+ accs[i].write(avs[i])
231
+ end
232
+ end
233
+ end
234
+ end
235
+ helse do
236
+ rvok <= 0
237
+ lefts.each_with_index do |left,i|
238
+ lvoks[i] <= 0
239
+ # accs[i].write(0)
240
+ avs[i] <= 0
241
+ end
242
+ end
243
+ end
244
+ end
245
+
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
+
315
+
316
+
317
+ end