HDLRuby 2.2.13 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|