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.
- checksums.yaml +4 -4
- data/README.md +14 -8
- data/lib/HDLRuby/hdr_samples/linear_test.rb +235 -0
- data/lib/HDLRuby/hdr_samples/memory_test.rb +272 -0
- data/lib/HDLRuby/hdr_samples/rom.rb +2 -2
- data/lib/HDLRuby/hdr_samples/ruby_fir_hw.rb +96 -0
- data/lib/HDLRuby/hdr_samples/with_fixpoint.rb +3 -2
- data/lib/HDLRuby/hdr_samples/with_linear.rb +166 -0
- data/lib/HDLRuby/hdr_samples/with_loop.rb +69 -0
- data/lib/HDLRuby/hdr_samples/with_memory.rb +13 -3
- data/lib/HDLRuby/hdrcc.rb +1 -1
- data/lib/HDLRuby/hruby_high.rb +12 -4
- data/lib/HDLRuby/hruby_low.rb +25 -28
- data/lib/HDLRuby/hruby_low2c.rb +10 -5
- data/lib/HDLRuby/hruby_low2high.rb +1 -1
- data/lib/HDLRuby/hruby_low2vhd.rb +63 -48
- data/lib/HDLRuby/hruby_low_fix_types.rb +4 -2
- data/lib/HDLRuby/hruby_low_mutable.rb +2 -1
- data/lib/HDLRuby/hruby_low_resolve.rb +7 -4
- data/lib/HDLRuby/hruby_low_without_concat.rb +8 -4
- data/lib/HDLRuby/hruby_types.rb +82 -72
- data/lib/HDLRuby/hruby_verilog.rb +9 -1
- data/lib/HDLRuby/sim/hruby_sim.h +21 -0
- data/lib/HDLRuby/sim/hruby_sim_calc.c +254 -18
- data/lib/HDLRuby/std/channel.rb +140 -40
- data/lib/HDLRuby/std/fixpoint.rb +15 -6
- data/lib/HDLRuby/std/linear.rb +317 -0
- data/lib/HDLRuby/std/loop.rb +101 -0
- data/lib/HDLRuby/std/memory.rb +1159 -45
- data/lib/HDLRuby/std/task.rb +850 -0
- data/lib/HDLRuby/version.rb +1 -1
- metadata +10 -2
data/lib/HDLRuby/std/channel.rb
CHANGED
@@ -81,11 +81,19 @@ module HDLRuby::High::Std
|
|
81
81
|
end
|
82
82
|
|
83
83
|
|
84
|
-
##
|
85
|
-
# Module for
|
86
|
-
module
|
87
|
-
|
88
|
-
|
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
|
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
|
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
|
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
|
246
|
-
class ChannelPortB
|
247
|
-
include
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
579
|
-
channelI
|
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
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
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
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
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
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
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
|
data/lib/HDLRuby/std/fixpoint.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|