HDLRuby 2.11.11 → 3.0.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.html +3274 -0
- data/README.md +608 -99
- data/ext/hruby_sim/hruby_rcsim_build.c +27 -0
- data/ext/hruby_sim/hruby_sim.h +3 -0
- data/ext/hruby_sim/hruby_sim_calc.c +2 -0
- data/ext/hruby_sim/hruby_sim_core.c +17 -5
- data/ext/hruby_sim/hruby_sim_stack_calc.c +1 -1
- data/ext/hruby_sim/hruby_sim_tree_calc.c +8 -1
- data/ext/hruby_sim/hruby_sim_vcd.c +24 -7
- data/ext/hruby_sim/hruby_sim_vizualize.c +9 -1
- data/lib/HDLRuby/backend/hruby_allocator.rb +2 -2
- data/lib/HDLRuby/backend/hruby_c_allocator.rb +7 -7
- data/lib/HDLRuby/hdr_samples/constant_in_function.rb +3 -1
- data/lib/HDLRuby/hdr_samples/counter_dff_bench.rb +3 -1
- data/lib/HDLRuby/hdr_samples/huge_rom.rb +1 -1
- data/lib/HDLRuby/hdr_samples/mei8.rb +11 -11
- data/lib/HDLRuby/hdr_samples/mei8_bench.rb +12 -12
- data/lib/HDLRuby/hdr_samples/neg_arith_bench.rb +4 -4
- data/lib/HDLRuby/hdr_samples/rom_nest.rb +1 -1
- data/lib/HDLRuby/hdr_samples/ruby_fir_hw.rb +4 -4
- data/lib/HDLRuby/hdr_samples/struct.rb +44 -10
- data/lib/HDLRuby/hdr_samples/with_bram.rb +45 -0
- data/lib/HDLRuby/hdr_samples/with_bram_frame_stack.rb +105 -0
- data/lib/HDLRuby/hdr_samples/with_bram_stack.rb +69 -0
- data/lib/HDLRuby/hdr_samples/with_casts.rb +3 -3
- data/lib/HDLRuby/hdr_samples/with_concat.rb +6 -6
- data/lib/HDLRuby/hdr_samples/with_connector_memory.rb +2 -2
- data/lib/HDLRuby/hdr_samples/with_def.rb +10 -3
- data/lib/HDLRuby/hdr_samples/with_define_operator.rb +44 -0
- data/lib/HDLRuby/hdr_samples/with_fixpoint.rb +12 -12
- data/lib/HDLRuby/hdr_samples/with_init.rb +3 -3
- data/lib/HDLRuby/hdr_samples/with_leftright.rb +21 -0
- data/lib/HDLRuby/hdr_samples/with_reduce.rb +13 -13
- data/lib/HDLRuby/hdr_samples/with_ref_array.rb +6 -6
- data/lib/HDLRuby/hdr_samples/with_register_stack.rb +150 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer.rb +190 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_deep.rb +91 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_enumerable.rb +405 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_enumerator.rb +89 -0
- data/lib/HDLRuby/hdr_samples/with_sequencer_sync.rb +120 -0
- data/lib/HDLRuby/hdr_samples/with_subsums.rb +3 -3
- data/lib/HDLRuby/hdr_samples/with_terminate.rb +3 -3
- data/lib/HDLRuby/hdr_samples/with_to_a.rb +10 -10
- data/lib/HDLRuby/hdr_samples/with_values.rb +3 -3
- data/lib/HDLRuby/hdrcc.rb +29 -3
- data/lib/HDLRuby/hdrlib.rb +1 -1
- data/lib/HDLRuby/hruby_bstr.rb +10 -5
- data/lib/HDLRuby/hruby_db.rb +2 -2
- data/lib/HDLRuby/hruby_high.rb +152 -47
- data/lib/HDLRuby/hruby_high_fullname.rb +3 -1
- data/lib/HDLRuby/hruby_low.rb +189 -18
- data/lib/HDLRuby/hruby_low2c.rb +129 -54
- data/lib/HDLRuby/hruby_low2hdr.rb +66 -40
- data/lib/HDLRuby/hruby_low2high.rb +86 -44
- data/lib/HDLRuby/hruby_low2seq.rb +26 -18
- data/lib/HDLRuby/hruby_low2sym.rb +14 -13
- data/lib/HDLRuby/hruby_low2vhd.rb +80 -44
- data/lib/HDLRuby/hruby_low_bool2select.rb +61 -46
- data/lib/HDLRuby/hruby_low_casts_without_expression.rb +56 -44
- data/lib/HDLRuby/hruby_low_cleanup.rb +18 -16
- data/lib/HDLRuby/hruby_low_fix_types.rb +65 -32
- data/lib/HDLRuby/hruby_low_mutable.rb +83 -119
- data/lib/HDLRuby/hruby_low_resolve.rb +38 -30
- data/lib/HDLRuby/hruby_low_with_bool.rb +33 -16
- data/lib/HDLRuby/hruby_low_with_port.rb +3 -3
- data/lib/HDLRuby/hruby_low_with_var.rb +23 -9
- data/lib/HDLRuby/hruby_low_without_concat.rb +45 -19
- data/lib/HDLRuby/hruby_low_without_namespace.rb +47 -32
- data/lib/HDLRuby/hruby_low_without_parinseq.rb +32 -16
- data/lib/HDLRuby/hruby_low_without_select.rb +37 -24
- data/lib/HDLRuby/hruby_low_without_subsignals.rb +280 -0
- data/lib/HDLRuby/hruby_rcsim.rb +158 -134
- data/lib/HDLRuby/hruby_rsim.rb +194 -20
- data/lib/HDLRuby/hruby_rsim_mute.rb +2 -3
- data/lib/HDLRuby/hruby_rsim_vcd.rb +125 -50
- data/lib/HDLRuby/hruby_values.rb +48 -33
- data/lib/HDLRuby/hruby_verilog.rb +90 -48
- data/lib/HDLRuby/soft/stacks.rb +219 -0
- data/lib/HDLRuby/std/bram.rb +26 -0
- data/lib/HDLRuby/std/clocks.rb +1 -1
- data/lib/HDLRuby/std/fixpoint.rb +2 -2
- data/lib/HDLRuby/std/fsm.rb +48 -11
- data/lib/HDLRuby/std/function_generator.rb +2 -2
- data/lib/HDLRuby/std/sequencer.rb +1857 -0
- data/lib/HDLRuby/std/sequencer_sync.rb +400 -0
- data/lib/HDLRuby/std/std.rb +12 -0
- data/lib/HDLRuby/version.rb +1 -1
- data/tuto/adder_sat_flags_vcd.png +0 -0
- data/tuto/addsub_vcd.png +0 -0
- data/tuto/alu_vcd.png +0 -0
- data/tuto/bit_pong_vcd.png +0 -0
- data/tuto/checksum_vcd.png +0 -0
- data/tuto/circuit_hdr.odg +0 -0
- data/tuto/circuit_hdr.png +0 -0
- data/tuto/circuit_hie.odg +0 -0
- data/tuto/circuit_hie.png +0 -0
- data/tuto/circuit_view.odg +0 -0
- data/tuto/circuit_view.png +0 -0
- data/tuto/clock_counter_vcd.png +0 -0
- data/tuto/counter_ext_vcd.png +0 -0
- data/tuto/fact_vcd.png +0 -0
- data/tuto/hw_flow.odg +0 -0
- data/tuto/hw_flow.png +0 -0
- data/tuto/maxxer_vcd.png +0 -0
- data/tuto/pingpong0_vcd.png +0 -0
- data/tuto/pingpong1_vcd.png +0 -0
- data/tuto/pingpong2_vcd.png +0 -0
- data/tuto/ram_vcd.png +0 -0
- data/tuto/serializer_vcd.png +0 -0
- data/tuto/sw_flow.odg +0 -0
- data/tuto/sw_flow.png +0 -0
- data/tuto/the_counter_vcd.png +0 -0
- data/tuto/tutorial_sw.html +2359 -0
- data/tuto/tutorial_sw.md +2684 -0
- data/tuto/tutorial_sw.pdf +0 -0
- data/tuto/tutorial_sw_jp.md +417 -0
- metadata +49 -3
- data/lib/HDLRuby/hdr_samples/sumprod.rb +0 -29
@@ -0,0 +1,1857 @@
|
|
1
|
+
require 'std/fsm'
|
2
|
+
|
3
|
+
module HDLRuby::High::Std
|
4
|
+
|
5
|
+
##
|
6
|
+
# Standard HDLRuby::High library: sequencer generator.
|
7
|
+
# The idea is to be able to write sw-like sequential code.
|
8
|
+
#
|
9
|
+
########################################################################
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
# Describes a sequencer block.
|
14
|
+
class SequencerT
|
15
|
+
@@current = nil # The current sequencer.
|
16
|
+
|
17
|
+
# Get the sequencer currently processing.
|
18
|
+
def self.current
|
19
|
+
@@current
|
20
|
+
end
|
21
|
+
|
22
|
+
# The start and end states values.
|
23
|
+
attr_reader :start_state_value, :end_state_value
|
24
|
+
|
25
|
+
# Create a new sequencer block synchronized on +ev+ and starting
|
26
|
+
# on +start+
|
27
|
+
def initialize(ev,start,&ruby_block)
|
28
|
+
this = self
|
29
|
+
# Process the arguments.
|
30
|
+
ev = ev.posedge unless ev.is_a?(Event)
|
31
|
+
if start.is_a?(Event) then
|
32
|
+
start = start.type == :posedge ? start.ref : ~start.ref
|
33
|
+
end
|
34
|
+
# Create the fsm from the block.
|
35
|
+
@fsm = fsm(ev,start,:seq)
|
36
|
+
# On reset (start) tell to go to the first state.
|
37
|
+
run = HDLRuby::High.cur_system.inner(HDLRuby.uniq_name(:run) => 0)
|
38
|
+
@fsm.reset do
|
39
|
+
# HDLRuby::High.top_user.instance_exec do
|
40
|
+
# next_state_sig <= this.start_state_value
|
41
|
+
# end
|
42
|
+
run <= 1
|
43
|
+
end
|
44
|
+
|
45
|
+
# The status stack of the sequencer.
|
46
|
+
@status = [ {} ]
|
47
|
+
# Creates the namespace to execute the sequencer deescription
|
48
|
+
# block in.
|
49
|
+
@namespace = Namespace.new(self)
|
50
|
+
|
51
|
+
# The end state is actually 0, allows to sequencer to be stable
|
52
|
+
# by default.
|
53
|
+
@fsm.default { run <= 0 }
|
54
|
+
@end_state = @fsm.state { }
|
55
|
+
@end_state.gotos << proc do
|
56
|
+
HDLRuby::High.top_user.instance_exec do
|
57
|
+
hif(run) { next_state_sig <= this.start_state_value }
|
58
|
+
helse { next_state_sig <= this.end_state_value }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
# Record the start and end state values.
|
62
|
+
# For now, the start state is the one just following the end state.
|
63
|
+
@end_state_value = @end_state.value
|
64
|
+
@start_state_value = @end_state_value + 1
|
65
|
+
# puts "end_state_value=#{@end_state_value}"
|
66
|
+
|
67
|
+
# Process the ruby_block.
|
68
|
+
@@current = self
|
69
|
+
HDLRuby::High.space_push(@namespace)
|
70
|
+
blk = HDLRuby::High::Block.new(:seq,&ruby_block)
|
71
|
+
HDLRuby::High.space_pop
|
72
|
+
|
73
|
+
# If the block is not empty, add it as last state.
|
74
|
+
this = self
|
75
|
+
if blk.each_statement.any? then
|
76
|
+
st = @fsm.state do
|
77
|
+
this.fill_top_user(blk)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# # Ends the fsm with an infinite loop state.
|
81
|
+
# st = @fsm.state {}
|
82
|
+
# st.gotos << proc do
|
83
|
+
# HDLRuby::High.top_user.instance_exec do
|
84
|
+
# # next_state_sig <= st.value
|
85
|
+
# next_state_sig <= EndStateValue
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
|
89
|
+
# Build the fsm.
|
90
|
+
@fsm.build
|
91
|
+
end
|
92
|
+
|
93
|
+
# Get the closest loop status in the status stack.
|
94
|
+
# NOTE: raises an exception if there are not swhile state.
|
95
|
+
def loop_status
|
96
|
+
i = @status.size-1
|
97
|
+
begin
|
98
|
+
status = @status[i -= 1]
|
99
|
+
raise "No loop for sbreak." unless status
|
100
|
+
end while(!status[:loop])
|
101
|
+
return status
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
# Mark a step.
|
107
|
+
def step
|
108
|
+
# Create a new block from all the statements in the previous block.
|
109
|
+
blk = HDLRuby::High::Block.new(:seq) {}
|
110
|
+
# Get all the statements of the builder block.
|
111
|
+
stmnts = HDLRuby::High.cur_block.instance_variable_get(:@statements)
|
112
|
+
# Add all the statements to blk.
|
113
|
+
stmnts.each { |stmnt| stmnt.parent = nil; blk.add_statement(stmnt) }
|
114
|
+
# Remove them from the builder block.
|
115
|
+
stmnts.clear
|
116
|
+
|
117
|
+
# Create a state for this block.
|
118
|
+
this = self
|
119
|
+
st = @fsm.state { this.fill_top_user(blk) }
|
120
|
+
# # Set the previous step in sequence.
|
121
|
+
# @status.last[:state] = st
|
122
|
+
return st
|
123
|
+
end
|
124
|
+
|
125
|
+
# Breaks current iteration.
|
126
|
+
def sbreak
|
127
|
+
# Mark a step.
|
128
|
+
st = self.step
|
129
|
+
# Tell there is a break to process.
|
130
|
+
# Do that in the first loop status met.
|
131
|
+
status = self.loop_status
|
132
|
+
status[:sbreaks] ||= []
|
133
|
+
status[:sbreaks] << st
|
134
|
+
return st
|
135
|
+
end
|
136
|
+
|
137
|
+
# Continues current iteration.
|
138
|
+
def scontinue
|
139
|
+
# Mark a step.
|
140
|
+
st = self.step
|
141
|
+
# Go to the begining of the iteration, i.e., the first loop
|
142
|
+
# status met.
|
143
|
+
status = self.loop_status
|
144
|
+
st.gotos << proc do
|
145
|
+
HDLRuby::High.top_user.instance_exec do
|
146
|
+
next_state_sig <= status[:loop]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
return st
|
150
|
+
end
|
151
|
+
|
152
|
+
# Terminates the sequencer.
|
153
|
+
def sterminate
|
154
|
+
# Mark a step.
|
155
|
+
st = self.step
|
156
|
+
# Adds a goto the ending state.
|
157
|
+
this = self
|
158
|
+
st.gotos << proc do
|
159
|
+
HDLRuby::High.top_user.instance_exec do
|
160
|
+
next_state_sig <= this.end_state_value
|
161
|
+
end
|
162
|
+
end
|
163
|
+
return st
|
164
|
+
end
|
165
|
+
|
166
|
+
# Create a sequential if statement on +cond+.
|
167
|
+
def sif(cond, &ruby_block)
|
168
|
+
# Mark a step.
|
169
|
+
st = self.step
|
170
|
+
# Remember the condition.
|
171
|
+
@status.last[:condition] = cond
|
172
|
+
# Create a state to be executed if the condition is met.
|
173
|
+
@status.push({})
|
174
|
+
yes_name = HDLRuby.uniq_name("yes")
|
175
|
+
yes_blk = HDLRuby::High::Block.new(:seq,&ruby_block)
|
176
|
+
@status.pop
|
177
|
+
this = self
|
178
|
+
yes = @fsm.state(yes_name) { this.fill_top_user(yes_blk) }
|
179
|
+
# Add a goto to the previous state.
|
180
|
+
st.gotos << proc do
|
181
|
+
HDLRuby::High.top_user.instance_exec do
|
182
|
+
hif(cond) { next_state_sig <= st.value + 1 }
|
183
|
+
helse { next_state_sig <= yes.value + 1 }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
# Remeber the if yes state for being able to add else afterward.
|
187
|
+
@status.last[:sif_yes] = yes
|
188
|
+
return st
|
189
|
+
end
|
190
|
+
|
191
|
+
# Create a sequential else statement.
|
192
|
+
def selse(&ruby_block)
|
193
|
+
# Create a state to be executed if the previous condition is
|
194
|
+
# not met.
|
195
|
+
@status.push({})
|
196
|
+
no_name = HDLRuby.uniq_name("no")
|
197
|
+
no_blk = HDLRuby::High::Block.new(:seq,&ruby_block)
|
198
|
+
@status.pop
|
199
|
+
this = self
|
200
|
+
no = @fsm.state(no_name) { this.fill_top_user(no_blk) }
|
201
|
+
# Adds a goto to the previous if yes state for jumping the no state.
|
202
|
+
yes = @status.last[:sif_yes]
|
203
|
+
raise "Cannot use selse here." unless yes
|
204
|
+
cond = @status.last[:condition]
|
205
|
+
yes.gotos << proc do
|
206
|
+
HDLRuby::High.top_user.instance_exec do
|
207
|
+
next_state_sig <= no.value + 1
|
208
|
+
end
|
209
|
+
end
|
210
|
+
return no
|
211
|
+
end
|
212
|
+
|
213
|
+
# Wait a given condition.
|
214
|
+
def swait(cond)
|
215
|
+
return self.swhile(~cond)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Create a sequential while statement on +cond+.
|
219
|
+
def swhile(cond,&ruby_block)
|
220
|
+
# Ensures there is a ruby block. This allows to use empty while
|
221
|
+
# statement.
|
222
|
+
ruby_block = proc { } unless ruby_block
|
223
|
+
# Mark a step.
|
224
|
+
st = self.step
|
225
|
+
|
226
|
+
# Tell we are building a while and remember the state number.
|
227
|
+
@status.last[:loop] = st.value + 1
|
228
|
+
|
229
|
+
# Create a state to be executed if the condition is met.
|
230
|
+
@status.push({})
|
231
|
+
# Build the loop sub sequence.
|
232
|
+
yes_name = HDLRuby.uniq_name("yes")
|
233
|
+
yes_blk = HDLRuby::High::Block.new(:seq,&ruby_block)
|
234
|
+
@status.pop
|
235
|
+
|
236
|
+
this = self
|
237
|
+
yes = @fsm.state(yes_name) { this.fill_top_user(yes_blk) }
|
238
|
+
# Add a goto to the previous state.
|
239
|
+
st.gotos << proc do
|
240
|
+
HDLRuby::High.top_user.instance_exec do
|
241
|
+
if cond then
|
242
|
+
# There is a condition, it is a real while loop.
|
243
|
+
hif(cond) { next_state_sig <= st.value + 1 }
|
244
|
+
helse { next_state_sig <= yes.value + 1 }
|
245
|
+
# puts("Here st: st.value+1=#{st.value+1} yes.value+1=#{yes.value+1}\n")
|
246
|
+
else
|
247
|
+
# There is no ending condition, this is an infinite loop.
|
248
|
+
next_state_sig <= st.value + 1
|
249
|
+
# puts("There st: st.value+1=#{st.value+1}\n")
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
# And to the yes state.
|
254
|
+
yes.gotos << proc do
|
255
|
+
HDLRuby::High.top_user.instance_exec do
|
256
|
+
if cond then
|
257
|
+
# There is a condition, it is a real while loop
|
258
|
+
hif(cond) { next_state_sig <= st.value + 1 }
|
259
|
+
helse { next_state_sig <= yes.value + 1 }
|
260
|
+
# puts("Here yes: st.value+1=#{st.value+1} yes.value+1=#{yes.value+1}\n")
|
261
|
+
else
|
262
|
+
# There is no ending condition, this is an infinite loop.
|
263
|
+
next_state_sig <= st.value + 1
|
264
|
+
# puts("There yes: st.value+1=#{st.value+1}\n")
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
# puts "st_value=#{st.value} yes_value=#{yes.value}"
|
269
|
+
|
270
|
+
# Where there any break?
|
271
|
+
if @status.last[:sbreaks] then
|
272
|
+
# Yes, adds them the right goto since the end of loop state
|
273
|
+
# is now defined.
|
274
|
+
@status.last[:sbreaks].each do |st_brk|
|
275
|
+
st_brk.gotos << proc do
|
276
|
+
HDLRuby::High.top_user.instance_exec do
|
277
|
+
next_state_sig <= yes.value + 1
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
# And remove them from the status to avoid reprocessing them,
|
282
|
+
@status.last.clear
|
283
|
+
end
|
284
|
+
|
285
|
+
return st
|
286
|
+
end
|
287
|
+
|
288
|
+
# Create a sequential infinite loop statement.
|
289
|
+
def sloop(&ruby_block)
|
290
|
+
self.swhile(nil,&ruby_block)
|
291
|
+
end
|
292
|
+
|
293
|
+
# Create a sequential for statement iterating over the elements
|
294
|
+
# of +expr+.
|
295
|
+
def sfor(expr,&ruby_block)
|
296
|
+
# Ensures there is a ruby block to avoid returning an enumerator
|
297
|
+
# (returning an enumerator would be confusing for a for statement).
|
298
|
+
ruby_block = proc {} unless ruby_block
|
299
|
+
expr.seach.with_index(&ruby_block)
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
# Fills the top user with the content of block +blk+.
|
304
|
+
def fill_top_user(blk)
|
305
|
+
# Fill the current block with blk content.
|
306
|
+
blk.each_statement do |stmnt|
|
307
|
+
stmnt.parent = nil
|
308
|
+
HDLRuby::High.top_user.add_statement(stmnt)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
|
314
|
+
# Module adding functionalities to object including the +seach+ method.
|
315
|
+
module SEnumerable
|
316
|
+
|
317
|
+
# Tell if all the elements respect a given criterion given either
|
318
|
+
# as +arg+ or as block.
|
319
|
+
def sall?(arg = nil,&ruby_block)
|
320
|
+
# Declare the result signal.
|
321
|
+
res = nil
|
322
|
+
HDLRuby::High.cur_system.open do
|
323
|
+
res = bit.inner(HDLRuby.uniq_name(:"all_cond"))
|
324
|
+
end
|
325
|
+
# Initialize the result.
|
326
|
+
res <= 1
|
327
|
+
# Performs the computation.
|
328
|
+
if arg then
|
329
|
+
# Compare elements to arg.
|
330
|
+
self.seach do |elem|
|
331
|
+
res <= res & (elem == arg)
|
332
|
+
end
|
333
|
+
elsif ruby_block then
|
334
|
+
# Use the ruby block.
|
335
|
+
self.seach do |elem|
|
336
|
+
res <= res & ruby_block.call(elem)
|
337
|
+
end
|
338
|
+
else
|
339
|
+
raise "Ruby nil does not have any meaning in HW."
|
340
|
+
end
|
341
|
+
res
|
342
|
+
end
|
343
|
+
|
344
|
+
# Tell if any of the elements respects a given criterion given either
|
345
|
+
# as +arg+ or as block.
|
346
|
+
def sany?(arg = nil,&ruby_block)
|
347
|
+
# Declare the result signal.
|
348
|
+
res = nil
|
349
|
+
HDLRuby::High.cur_system.open do
|
350
|
+
res = bit.inner(HDLRuby.uniq_name(:"any_cond"))
|
351
|
+
end
|
352
|
+
# Initialize the result.
|
353
|
+
res <= 0
|
354
|
+
# Performs the computation.
|
355
|
+
if arg then
|
356
|
+
# Compare elements to arg.
|
357
|
+
self.seach do |elem|
|
358
|
+
res <= res | (elem == arg)
|
359
|
+
end
|
360
|
+
elsif ruby_block then
|
361
|
+
# Use the ruby block.
|
362
|
+
self.seach do |elem|
|
363
|
+
res <= res | ruby_block.call(elem)
|
364
|
+
end
|
365
|
+
else
|
366
|
+
raise "Ruby nil does not have any meaning in HW."
|
367
|
+
end
|
368
|
+
res
|
369
|
+
end
|
370
|
+
|
371
|
+
# Returns an SEnumerator generated from current enumerable and +arg+
|
372
|
+
def schain(arg)
|
373
|
+
return self.seach + arg
|
374
|
+
end
|
375
|
+
|
376
|
+
# HW implementation of the Ruby chunk.
|
377
|
+
# NOTE: to do, or may be not.
|
378
|
+
def schunk(*args,&ruby_block)
|
379
|
+
raise "schunk is not supported yet."
|
380
|
+
end
|
381
|
+
|
382
|
+
# HW implementation of the Ruby chunk_while.
|
383
|
+
# NOTE: to do, or may be not.
|
384
|
+
def schunk_while(*args,&ruby_block)
|
385
|
+
raise "schunk_while is not supported yet."
|
386
|
+
end
|
387
|
+
|
388
|
+
# Returns a vector containing the execution result of the given block
|
389
|
+
# on each element. If no block is given, return an SEnumerator.
|
390
|
+
# NOTE: be carful that the resulting vector can become huge if there
|
391
|
+
# are many element.
|
392
|
+
def smap(&ruby_block)
|
393
|
+
# No block given? Generate a new wrapper enumerator for smap.
|
394
|
+
if !ruby_block then
|
395
|
+
return SEnumeratorWrapper.new(self,:smap)
|
396
|
+
end
|
397
|
+
# A block given? Fill the vector it with the computation result.
|
398
|
+
# Generate the vector to put the result in.
|
399
|
+
# The declares the resulting vector.
|
400
|
+
res = nil
|
401
|
+
enum = self.seach
|
402
|
+
HDLRuby::High.cur_system.open do
|
403
|
+
res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"map_vec"))
|
404
|
+
end
|
405
|
+
# And do the iteration.
|
406
|
+
enum.with_index do |elem,idx|
|
407
|
+
res[idx] <= ruby_block.call(elem)
|
408
|
+
end
|
409
|
+
# Return the resulting vector.
|
410
|
+
return res
|
411
|
+
end
|
412
|
+
|
413
|
+
# HW implementation of the Ruby flat_map.
|
414
|
+
# NOTE: actually due to the way HDLRuby handles vectors, should work
|
415
|
+
# like smap
|
416
|
+
def sflat_map(&ruby_block)
|
417
|
+
return smap(&ruby_block)
|
418
|
+
end
|
419
|
+
|
420
|
+
# HW implementation of the Ruby compact, but remove 0 values instead
|
421
|
+
# on nil (since nil that does not have any meaning in HW).
|
422
|
+
def scompact
|
423
|
+
# Generate the vector to put the result in.
|
424
|
+
# The declares the resulting vector and index.
|
425
|
+
res = nil
|
426
|
+
idx = nil
|
427
|
+
enum = self.seach
|
428
|
+
HDLRuby::High.cur_system.open do
|
429
|
+
res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"compact_vec"))
|
430
|
+
idx = [enum.size.width].inner(HDLRuby.uniq_name(:"compact_idx"))
|
431
|
+
end
|
432
|
+
# And do the iteration.
|
433
|
+
idx <= 0
|
434
|
+
enum.seach do |elem|
|
435
|
+
HDLRuby::High.top_user.hif(elem != 0) do
|
436
|
+
res[idx] <= elem
|
437
|
+
idx <= idx + 1
|
438
|
+
end
|
439
|
+
end
|
440
|
+
SequencerT.current.swhile(idx < enum.size) do
|
441
|
+
res[idx] <= 0
|
442
|
+
idx <= idx + 1
|
443
|
+
end
|
444
|
+
# Return the resulting vector.
|
445
|
+
return res
|
446
|
+
end
|
447
|
+
|
448
|
+
|
449
|
+
# WH implementation of the Ruby count.
|
450
|
+
def scount(obj = nil, &ruby_block)
|
451
|
+
# Generate the counter result signal.
|
452
|
+
cnt = nil
|
453
|
+
enum = self.seach
|
454
|
+
HDLRuby::High.cur_system.open do
|
455
|
+
cnt = [enum.size.width].inner(HDLRuby.uniq_name(:"count_idx"))
|
456
|
+
end
|
457
|
+
# Do the counting.
|
458
|
+
cnt <= 0
|
459
|
+
# Is obj present?
|
460
|
+
if obj then
|
461
|
+
# Yes, count the occurences of obj.
|
462
|
+
enum.seach do |elem|
|
463
|
+
HDLRuby::High.top_user.hif(obj == elem) { cnt <= cnt + 1 }
|
464
|
+
end
|
465
|
+
elsif ruby_block
|
466
|
+
# No, but there is a ruby block, use its result for counting.
|
467
|
+
enum.seach do |elem|
|
468
|
+
HDLRuby::High.top_user.hif(ruby_block.call(elem)) do
|
469
|
+
cnt <= cnt + 1
|
470
|
+
end
|
471
|
+
end
|
472
|
+
else
|
473
|
+
# No, the result is simply the number of elements.
|
474
|
+
cnt <= enum.size
|
475
|
+
end
|
476
|
+
return cnt
|
477
|
+
end
|
478
|
+
|
479
|
+
# HW implementation of the Ruby cycle.
|
480
|
+
def scycle(n = nil,&ruby_block)
|
481
|
+
# No block given? Generate a new wrapper enumerator for scycle.
|
482
|
+
if !ruby_block then
|
483
|
+
return SEnumeratorWrapper.new(self,:scycle,n)
|
484
|
+
end
|
485
|
+
this = self
|
486
|
+
# Is n nil?
|
487
|
+
if n == nil then
|
488
|
+
# Yes, infinite loop.
|
489
|
+
SequencerT.current.sloop do
|
490
|
+
this.seach(&ruby_block)
|
491
|
+
end
|
492
|
+
else
|
493
|
+
# Finite loop.
|
494
|
+
(0..(n-1)).seach do
|
495
|
+
this.seach(&ruby_block)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
# HW implementation of the Ruby find.
|
501
|
+
# NOTE: contrary to Ruby, if_none_proc is mandatory since there is no
|
502
|
+
# nil in HW. Moreover, the argument can also be a value.
|
503
|
+
def sfind(if_none_proc, &ruby_block)
|
504
|
+
# No block given? Generate a new wrapper enumerator for sfind.
|
505
|
+
if !ruby_block then
|
506
|
+
return SEnumeratorWrapper.new(self,:sfind,if_none_proc)
|
507
|
+
end
|
508
|
+
# Generate the found result signal and flag signals.
|
509
|
+
found = nil
|
510
|
+
flag = nil
|
511
|
+
enum = self.seach
|
512
|
+
HDLRuby::High.cur_system.open do
|
513
|
+
found = enum.type.inner(HDLRuby.uniq_name(:"find_found"))
|
514
|
+
flag = bit.inner(HDLRuby.uniq_name(:"find_flag"))
|
515
|
+
end
|
516
|
+
# Look for the element.
|
517
|
+
flag <= 0
|
518
|
+
enum.srewind
|
519
|
+
SequencerT.current.swhile((flag == 0) & (enum.snext?)) do
|
520
|
+
found <= enum.snext
|
521
|
+
hif(ruby_block.call(found)) do
|
522
|
+
# Found, save the element and raise the flag.
|
523
|
+
flag <= 1
|
524
|
+
end
|
525
|
+
end
|
526
|
+
HDLRuby::High.top_user.hif(~flag) do
|
527
|
+
# Not found, execute the none block.
|
528
|
+
if if_none_proc.respond_to?(:call) then
|
529
|
+
found <= f_none_proc.call
|
530
|
+
else
|
531
|
+
found <= if_none_proc
|
532
|
+
end
|
533
|
+
end
|
534
|
+
found
|
535
|
+
end
|
536
|
+
|
537
|
+
# HW implementation of the Ruby drop.
|
538
|
+
def sdrop(n)
|
539
|
+
# Generate the vector to put the result in.
|
540
|
+
# The declares the resulting vector and index.
|
541
|
+
res = nil
|
542
|
+
idx = nil
|
543
|
+
enum = self.seach
|
544
|
+
HDLRuby::High.cur_system.open do
|
545
|
+
# res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"drop_vec"))
|
546
|
+
res = enum.type[-enum.size+n].inner(HDLRuby.uniq_name(:"drop_vec"))
|
547
|
+
# idx = [enum.size.width].inner(HDLRuby.uniq_name(:"drop_idx"))
|
548
|
+
end
|
549
|
+
# And do the iteration.
|
550
|
+
# idx <= 0
|
551
|
+
# enum.seach.with_index do |elem,i|
|
552
|
+
# HDLRuby::High.top_user.hif(i >= n) do
|
553
|
+
# res[idx] <= elem
|
554
|
+
# idx <= idx + 1
|
555
|
+
# end
|
556
|
+
# end
|
557
|
+
# SequencerT.current.swhile(idx < enum.size) do
|
558
|
+
# res[idx] <= 0
|
559
|
+
# idx <= idx + 1
|
560
|
+
# end
|
561
|
+
(enum.size-n).stimes do |i|
|
562
|
+
res[i] <= enum.access(i+n)
|
563
|
+
end
|
564
|
+
# Return the resulting vector.
|
565
|
+
return res
|
566
|
+
end
|
567
|
+
|
568
|
+
# HW implementation of the Ruby drop_while.
|
569
|
+
def sdrop_while(&ruby_block)
|
570
|
+
# No block given? Generate a new wrapper enumerator for sdrop_while.
|
571
|
+
if !ruby_block then
|
572
|
+
return SEnumeratorWrapper.new(self,:sdrop_while)
|
573
|
+
end
|
574
|
+
# A block is given.
|
575
|
+
# Generate the vector to put the result in.
|
576
|
+
# The declares the resulting vector, index and drop flag.
|
577
|
+
res = nil
|
578
|
+
idx = nil
|
579
|
+
flg = nil
|
580
|
+
enum = self.seach
|
581
|
+
HDLRuby::High.cur_system.open do
|
582
|
+
res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"drop_vec"))
|
583
|
+
idx = [enum.size.width].inner(HDLRuby.uniq_name(:"drop_idx"))
|
584
|
+
flg = bit.inner(HDLRuby.uniq_name(:"drop_flg"))
|
585
|
+
end
|
586
|
+
# And do the iteration.
|
587
|
+
# First drop and fill from current enumerable elements.
|
588
|
+
idx <= 0
|
589
|
+
flg <= 1
|
590
|
+
enum.seach.with_index do |elem,i|
|
591
|
+
HDLRuby::High.top_user.hif(flg == 1) do
|
592
|
+
HDLRuby::High.top_user.hif(ruby_block.call(elem) == 0) do
|
593
|
+
flg <= 0
|
594
|
+
end
|
595
|
+
end
|
596
|
+
HDLRuby::High.top_user.hif(flg == 0) do
|
597
|
+
res[idx] <= elem
|
598
|
+
idx <= idx + 1
|
599
|
+
end
|
600
|
+
end
|
601
|
+
# Finally, end with zeros.
|
602
|
+
SequencerT.current.swhile(idx < enum.size) do
|
603
|
+
res[idx] <= 0
|
604
|
+
idx <= idx + 1
|
605
|
+
end
|
606
|
+
# Return the resulting vector.
|
607
|
+
return res
|
608
|
+
end
|
609
|
+
|
610
|
+
# HW implementation of the Ruby each_cons
|
611
|
+
def seach_cons(n,&ruby_block)
|
612
|
+
# No block given? Generate a new wrapper enumerator for seach_cons.
|
613
|
+
if !ruby_block then
|
614
|
+
return SEnumeratorWrapper.new(self,:seach_cons)
|
615
|
+
end
|
616
|
+
# A block is given.
|
617
|
+
# Declares the indexes and the buffer for cosecutive elements.
|
618
|
+
enum = self.seach
|
619
|
+
idx = nil
|
620
|
+
buf = nil
|
621
|
+
HDLRuby::High.cur_system.open do
|
622
|
+
idx = [enum.size.width].inner(HDLRuby.uniq_name(:"each_cons_idx"))
|
623
|
+
buf = n.times.map do |i|
|
624
|
+
[enum.type].inner(HDLRuby.uniq_name(:"each_cons_buf#{i}"))
|
625
|
+
end
|
626
|
+
end
|
627
|
+
# And do the iteration.
|
628
|
+
this = self
|
629
|
+
# Initialize the buffer.
|
630
|
+
n.times do |i|
|
631
|
+
buf[i] <= enum.access(i)
|
632
|
+
SequencerT.current.step
|
633
|
+
end
|
634
|
+
# Do the first iteration.
|
635
|
+
ruby_block.call(*buf)
|
636
|
+
# Do the remaining iteration.
|
637
|
+
idx <= n
|
638
|
+
SequencerT.current.swhile(idx < enum.size) do
|
639
|
+
# Shifts the buffer (in parallel)
|
640
|
+
buf.each_cons(2) { |a0,a1| a0 <= a1 }
|
641
|
+
# Adds the new element.
|
642
|
+
buf[-1] <= enum.access(idx)
|
643
|
+
idx <= idx + 1
|
644
|
+
# Executes the block.
|
645
|
+
ruby_block.call(*buf)
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
# HW implementation of the Ruby each_entry.
|
650
|
+
# NOTE: to do, or may be not.
|
651
|
+
def seach_entry(*args,&ruby_block)
|
652
|
+
raise "seach_entry is not supported yet."
|
653
|
+
end
|
654
|
+
|
655
|
+
# HW implementation of the Ruby each_slice
|
656
|
+
def seach_slice(n,&ruby_block)
|
657
|
+
# No block given? Generate a new wrapper enumerator for seach_slice.
|
658
|
+
if !ruby_block then
|
659
|
+
return SEnumeratorWrapper.new(self,:seach_slice)
|
660
|
+
end
|
661
|
+
# A block is given.
|
662
|
+
# Declares the indexes and the buffer for consecutive elements.
|
663
|
+
enum = self.seach
|
664
|
+
idx = nil
|
665
|
+
buf = nil
|
666
|
+
HDLRuby::High.cur_system.open do
|
667
|
+
idx = [(enum.size+n).width].inner(HDLRuby.uniq_name(:"each_slice_idx"))
|
668
|
+
buf = n.times.map do |i|
|
669
|
+
[enum.type].inner(HDLRuby.uniq_name(:"each_slice_buf#{i}"))
|
670
|
+
end
|
671
|
+
end
|
672
|
+
# And do the iteration.
|
673
|
+
this = self
|
674
|
+
# Adjust n if too large.
|
675
|
+
n = enum.size if n > enum.size
|
676
|
+
# Initialize the buffer.
|
677
|
+
n.times do |i|
|
678
|
+
buf[i] <= enum.access(i)
|
679
|
+
SequencerT.current.step
|
680
|
+
end
|
681
|
+
# Do the first iteration.
|
682
|
+
ruby_block.call(*buf)
|
683
|
+
# Do the remaining iteration.
|
684
|
+
idx <= n
|
685
|
+
SequencerT.current.swhile(idx < enum.size) do
|
686
|
+
# Gets the new element.
|
687
|
+
n.times do |i|
|
688
|
+
sif(idx+i < enum.size) do
|
689
|
+
buf[i] <= enum.access(idx+i)
|
690
|
+
end
|
691
|
+
selse do
|
692
|
+
buf[i] <= 0
|
693
|
+
end
|
694
|
+
end
|
695
|
+
idx <= idx + n
|
696
|
+
# Executes the block.
|
697
|
+
ruby_block.call(*buf)
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
# HW implementation of the Ruby each_with_index.
|
702
|
+
def seach_with_index(*args,&ruby_block)
|
703
|
+
self.seach.with_index(*args,&ruby_block)
|
704
|
+
end
|
705
|
+
|
706
|
+
# HW implementation of the Ruby each_with_object.
|
707
|
+
def seach_with_object(obj,&ruby_block)
|
708
|
+
self.seach.with_object(obj,&ruby_block)
|
709
|
+
end
|
710
|
+
|
711
|
+
# HW implementation of the Ruby to_a.
|
712
|
+
def sto_a
|
713
|
+
# Declares the resulting vector.
|
714
|
+
enum = self.seach
|
715
|
+
res = nil
|
716
|
+
HDLRuby::High.cur_system.open do
|
717
|
+
res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"to_a_res"))
|
718
|
+
end
|
719
|
+
# Fills it.
|
720
|
+
self.seach_with_index do |elem,i|
|
721
|
+
res[i] <= elem
|
722
|
+
end
|
723
|
+
return res
|
724
|
+
end
|
725
|
+
|
726
|
+
# HW implementation of the Ruby select.
|
727
|
+
def sselect(&ruby_block)
|
728
|
+
# No block given? Generate a new wrapper enumerator for sselect.
|
729
|
+
if !ruby_block then
|
730
|
+
return SEnumeratorWrapper.new(self,:sselect)
|
731
|
+
end
|
732
|
+
# A block is given.
|
733
|
+
# Generate the vector to put the result in.
|
734
|
+
# The declares the resulting vector and index.
|
735
|
+
res = nil
|
736
|
+
idx = nil
|
737
|
+
enum = self.seach
|
738
|
+
HDLRuby::High.cur_system.open do
|
739
|
+
res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"select_vec"))
|
740
|
+
idx = [enum.size.width].inner(HDLRuby.uniq_name(:"select_idx"))
|
741
|
+
end
|
742
|
+
# And do the iteration.
|
743
|
+
# First select and fill from current enumerable elements.
|
744
|
+
idx <= 0
|
745
|
+
enum.seach do |elem|
|
746
|
+
HDLRuby::High.top_user.hif(ruby_block.call(elem) == 1) do
|
747
|
+
res[idx] <= elem
|
748
|
+
idx <= idx + 1
|
749
|
+
end
|
750
|
+
end
|
751
|
+
# Finally, end with zeros.
|
752
|
+
SequencerT.current.swhile(idx < enum.size) do
|
753
|
+
res[idx] <= 0
|
754
|
+
idx <= idx + 1
|
755
|
+
end
|
756
|
+
# Return the resulting vector.
|
757
|
+
return res
|
758
|
+
end
|
759
|
+
|
760
|
+
# HW implementation of the Ruby find_index.
|
761
|
+
def sfind_index(obj = nil, &ruby_block)
|
762
|
+
# No block given nor obj? Generate a new wrapper enumerator for
|
763
|
+
# sfind.
|
764
|
+
if !ruby_block && !obj then
|
765
|
+
return SEnumeratorWrapper.new(self,:sfind,if_none_proc)
|
766
|
+
end
|
767
|
+
# Generate the index result signal and flag signals.
|
768
|
+
idx = nil
|
769
|
+
flag = nil
|
770
|
+
enum = self.seach
|
771
|
+
HDLRuby::High.cur_system.open do
|
772
|
+
idx = signed[enum.size.width+1].inner(HDLRuby.uniq_name(:"find_idx"))
|
773
|
+
flag = bit.inner(HDLRuby.uniq_name(:"find_flag"))
|
774
|
+
end
|
775
|
+
# Look for the element.
|
776
|
+
flag <= 0
|
777
|
+
idx <= 0
|
778
|
+
enum.srewind
|
779
|
+
SequencerT.current.swhile((flag == 0) & (enum.snext?)) do
|
780
|
+
if (obj) then
|
781
|
+
# There is obj case.
|
782
|
+
HDLRuby::High.top_user.hif(enum.snext == obj) do
|
783
|
+
# Found, save the element and raise the flag.
|
784
|
+
flag <= 1
|
785
|
+
end
|
786
|
+
else
|
787
|
+
# There is a block case.
|
788
|
+
HDLRuby::High.top_user.hif(ruby_block.call(enum.snext)) do
|
789
|
+
# Found, save the element and raise the flag.
|
790
|
+
flag <= 1
|
791
|
+
end
|
792
|
+
end
|
793
|
+
HDLRuby::High.top_user.helse do
|
794
|
+
idx <= idx + 1
|
795
|
+
end
|
796
|
+
end
|
797
|
+
HDLRuby::High.top_user.hif(flag ==0) { idx <= -1 }
|
798
|
+
return idx
|
799
|
+
end
|
800
|
+
|
801
|
+
# HW implementation of the Ruby first.
|
802
|
+
def sfirst(n=1)
|
803
|
+
# Generate the vector to put the result in.
|
804
|
+
# The declares the resulting vector and index.
|
805
|
+
res = nil
|
806
|
+
enum = self.seach
|
807
|
+
HDLRuby::High.cur_system.open do
|
808
|
+
res = enum.type[-n].inner(HDLRuby.uniq_name(:"first_vec"))
|
809
|
+
end
|
810
|
+
# And do the iteration.
|
811
|
+
n.stimes do |i|
|
812
|
+
res[i] <= enum.access(i)
|
813
|
+
end
|
814
|
+
# Return the resulting vector.
|
815
|
+
return res
|
816
|
+
end
|
817
|
+
|
818
|
+
# HW implementation of the Ruby grep.
|
819
|
+
# NOTE: to do, or may be not.
|
820
|
+
def sgrep(*args,&ruby_block)
|
821
|
+
raise "sgrep is not supported yet."
|
822
|
+
end
|
823
|
+
|
824
|
+
# HW implementation of the Ruby grep_v.
|
825
|
+
# NOTE: to do, or may be not.
|
826
|
+
def sgrep_v(*args,&ruby_block)
|
827
|
+
raise "sgrep_v is not supported yet."
|
828
|
+
end
|
829
|
+
|
830
|
+
# HW implementation of the Ruby group_by.
|
831
|
+
# NOTE: to do, or may be not.
|
832
|
+
def sgroup_by(*args,&ruby_block)
|
833
|
+
raise "sgroup_by is not supported yet."
|
834
|
+
end
|
835
|
+
|
836
|
+
# HW implementation of the Ruby include?
|
837
|
+
def sinclude?(obj)
|
838
|
+
# Generate the result signal.
|
839
|
+
res = nil
|
840
|
+
enum = self.seach
|
841
|
+
HDLRuby::High.cur_system.open do
|
842
|
+
res = bit.inner(HDLRuby.uniq_name(:"include_res"))
|
843
|
+
end
|
844
|
+
# Look for the element.
|
845
|
+
res <= 0
|
846
|
+
enum.srewind
|
847
|
+
SequencerT.current.swhile((res == 0) & (enum.snext?)) do
|
848
|
+
# There is obj case.
|
849
|
+
HDLRuby::High.top_user.hif(enum.snext == obj) do
|
850
|
+
# Found, save the element and raise the flag.
|
851
|
+
res <= 1
|
852
|
+
end
|
853
|
+
end
|
854
|
+
return res
|
855
|
+
end
|
856
|
+
|
857
|
+
# HW implementation of the Ruby inject.
|
858
|
+
def sinject(*args,&ruby_block)
|
859
|
+
init = nil
|
860
|
+
symbol = nil
|
861
|
+
# Process the arguments.
|
862
|
+
if args.size > 2 then
|
863
|
+
raise ArgumentError.new("wrong number of arguments (given #{args.size} expected 0..2)")
|
864
|
+
elsif args.size == 2 then
|
865
|
+
# Initial value and symbol given case.
|
866
|
+
init, symbol = args
|
867
|
+
elsif args.size == 1 && ruby_block then
|
868
|
+
# Initial value and block given case.
|
869
|
+
init = args[0]
|
870
|
+
elsif args.size == 1 then
|
871
|
+
# Symbol given case.
|
872
|
+
symbol = args[0]
|
873
|
+
end
|
874
|
+
enum = self.seach
|
875
|
+
# Define the computation type: from the initial value if any,
|
876
|
+
# otherwise from the enum.
|
877
|
+
typ = init ? init.to_expr.type : enum.type
|
878
|
+
# Generate the result signal.
|
879
|
+
res = nil
|
880
|
+
HDLRuby::High.cur_system.open do
|
881
|
+
res = typ.inner(HDLRuby.uniq_name(:"inject_res"))
|
882
|
+
end
|
883
|
+
# Start the initialization
|
884
|
+
enum.srewind
|
885
|
+
# Is there an initial value?
|
886
|
+
if (init) then
|
887
|
+
# Yes, start with it.
|
888
|
+
res <= init
|
889
|
+
else
|
890
|
+
# No, start with the first element of the enumerator.
|
891
|
+
res <= 0
|
892
|
+
SequencerT.current.sif(!enum.snext?) { res <= enum.snext }
|
893
|
+
end
|
894
|
+
SequencerT.current.swhile(enum.snext?) do
|
895
|
+
# Do the accumulation.
|
896
|
+
if (symbol) then
|
897
|
+
res <= res.send(symbol,enum.snext)
|
898
|
+
else
|
899
|
+
res <= ruby_block.call(res,enum.snext)
|
900
|
+
end
|
901
|
+
end
|
902
|
+
return res
|
903
|
+
end
|
904
|
+
|
905
|
+
alias_method :sreduce, :sinject
|
906
|
+
|
907
|
+
# HW implementation of the Ruby lazy.
|
908
|
+
# NOTE: to do, or may be not.
|
909
|
+
def slazy(*args,&ruby_block)
|
910
|
+
raise "slazy is not supported yet."
|
911
|
+
end
|
912
|
+
|
913
|
+
# HW implementation of the Ruby max.
|
914
|
+
def smax(n = nil, &ruby_block)
|
915
|
+
# Process the arguments.
|
916
|
+
n = 1 unless n
|
917
|
+
enum = self.seach
|
918
|
+
# Declare the result signal the flag and the result array size index
|
919
|
+
# used for implementing the algorithm (shift-based sorting) in
|
920
|
+
# case of multiple max.
|
921
|
+
res = nil
|
922
|
+
flg = nil
|
923
|
+
idx = nil
|
924
|
+
HDLRuby::High.cur_system.open do
|
925
|
+
if n == 1 then
|
926
|
+
res = enum.type.inner(HDLRuby.uniq_name(:"max_res"))
|
927
|
+
# No flg nor idx!
|
928
|
+
else
|
929
|
+
res = enum.type[-n].inner(HDLRuby.uniq_name(:"max_res"))
|
930
|
+
flg = bit.inner(HDLRuby.uniq_name(:"max_flg"))
|
931
|
+
idx = bit[n.width].inner(HDLRuby.uniq_name(:"max_idx"))
|
932
|
+
end
|
933
|
+
end
|
934
|
+
enum.srewind
|
935
|
+
if n == 1 then
|
936
|
+
# Single max case, initialize res with the first element(s)
|
937
|
+
res <= enum.type.min
|
938
|
+
SequencerT.current.sif(enum.snext?) { res <= enum.snext }
|
939
|
+
else
|
940
|
+
# Multiple max case, initialize the resulting array size index.
|
941
|
+
idx <= 0
|
942
|
+
end
|
943
|
+
# Do the iteration.
|
944
|
+
SequencerT.current.swhile(enum.snext?) do
|
945
|
+
if n == 1 then
|
946
|
+
# Single max case.
|
947
|
+
elem = enum.snext
|
948
|
+
if ruby_block then
|
949
|
+
hif(ruby_block.call(res,elem) < 0) { res <= elem }
|
950
|
+
else
|
951
|
+
hif(res < elem) { res <= elem }
|
952
|
+
end
|
953
|
+
else
|
954
|
+
# Multiple max case.
|
955
|
+
SequencerT.current.sif(enum.snext?) do
|
956
|
+
elem = enum.snext
|
957
|
+
flg <= 1
|
958
|
+
n.times do |i|
|
959
|
+
# Compute the comparison between the result element
|
960
|
+
# at i and the enum element.
|
961
|
+
if ruby_block then
|
962
|
+
cond = ruby_block.call(res[i],elem) < 0
|
963
|
+
else
|
964
|
+
cond = res[i] < elem
|
965
|
+
end
|
966
|
+
# If flg is 0, elem is already set as max, skip.
|
967
|
+
# If the result array size index is equal to i, then
|
968
|
+
# put the element whatever the comparison is since
|
969
|
+
# the place is still empty.
|
970
|
+
hif(flg & (cond | (idx == i))) do
|
971
|
+
# A new max is found, shift res from i.
|
972
|
+
((i+1)..(n-1)).reverse_each { |j| res[j] <= res[j-1] }
|
973
|
+
# An set the new max in current position.
|
974
|
+
res[i] <= elem
|
975
|
+
# For now skip.
|
976
|
+
flg <= 0
|
977
|
+
end
|
978
|
+
end
|
979
|
+
# Note: when idx >= n, the resulting array is full
|
980
|
+
hif(idx < n) { idx <= idx + 1 }
|
981
|
+
end
|
982
|
+
end
|
983
|
+
end
|
984
|
+
return res
|
985
|
+
end
|
986
|
+
|
987
|
+
# HW implementation of the Ruby max_by.
|
988
|
+
def smax_by(n = nil, &ruby_block)
|
989
|
+
# No block given? Generate a new wrapper enumerator for smax_by.
|
990
|
+
if !ruby_block then
|
991
|
+
return SEnumeratorWrapper.new(self,:smax_by,n)
|
992
|
+
end
|
993
|
+
# A block is given, use smax with a proc that applies ruby_block
|
994
|
+
# before comparing.
|
995
|
+
return smax(n) { |a,b| ruby_block.call(a) <=> ruby_block.call(b) }
|
996
|
+
end
|
997
|
+
|
998
|
+
# HW implementation of the Ruby min.
|
999
|
+
def smin(n = nil, &ruby_block)
|
1000
|
+
# Process the arguments.
|
1001
|
+
n = 1 unless n
|
1002
|
+
enum = self.seach
|
1003
|
+
# Declare the result signal the flag and the result array size index
|
1004
|
+
# used for implementing the algorithm (shift-based sorting) in
|
1005
|
+
# case of multiple min.
|
1006
|
+
res = nil
|
1007
|
+
flg = nil
|
1008
|
+
idx = nil
|
1009
|
+
HDLRuby::High.cur_system.open do
|
1010
|
+
if n == 1 then
|
1011
|
+
res = enum.type.inner(HDLRuby.uniq_name(:"min_res"))
|
1012
|
+
# No flg nor idx!
|
1013
|
+
else
|
1014
|
+
res = enum.type[-n].inner(HDLRuby.uniq_name(:"min_res"))
|
1015
|
+
flg = bit.inner(HDLRuby.uniq_name(:"min_flg"))
|
1016
|
+
idx = bit[n.width].inner(HDLRuby.uniq_name(:"min_idx"))
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
enum.srewind
|
1020
|
+
if n == 1 then
|
1021
|
+
# Single min case, initialize res with the first element(s)
|
1022
|
+
res <= enum.type.max
|
1023
|
+
SequencerT.current.sif(enum.snext?) { res <= enum.snext }
|
1024
|
+
else
|
1025
|
+
# Multiple min case, initialize the resulting array size index.
|
1026
|
+
idx <= 0
|
1027
|
+
end
|
1028
|
+
# Do the iteration.
|
1029
|
+
SequencerT.current.swhile(enum.snext?) do
|
1030
|
+
if n == 1 then
|
1031
|
+
# Single min case.
|
1032
|
+
elem = enum.snext
|
1033
|
+
if ruby_block then
|
1034
|
+
hif(ruby_block.call(res,elem) > 0) { res <= elem }
|
1035
|
+
else
|
1036
|
+
hif(res > elem) { res <= elem }
|
1037
|
+
end
|
1038
|
+
else
|
1039
|
+
# Multiple min case.
|
1040
|
+
SequencerT.current.sif(enum.snext?) do
|
1041
|
+
elem = enum.snext
|
1042
|
+
flg <= 1
|
1043
|
+
n.times do |i|
|
1044
|
+
# Compute the comparison between the result element
|
1045
|
+
# at i and the enum element.
|
1046
|
+
if ruby_block then
|
1047
|
+
cond = ruby_block.call(res[i],elem) > 0
|
1048
|
+
else
|
1049
|
+
cond = res[i] > elem
|
1050
|
+
end
|
1051
|
+
# If flg is 0, elem is already set as min, skip.
|
1052
|
+
# If the result array size index is equal to i, then
|
1053
|
+
# put the element whatever the comparison is since
|
1054
|
+
# the place is still empty.
|
1055
|
+
hif(flg & (cond | (idx == i))) do
|
1056
|
+
# A new min is found, shift res from i.
|
1057
|
+
((i+1)..(n-1)).reverse_each { |j| res[j] <= res[j-1] }
|
1058
|
+
# An set the new min in current position.
|
1059
|
+
res[i] <= elem
|
1060
|
+
# For now skip.
|
1061
|
+
flg <= 0
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
# Note: when idx >= n, the resulting array is full
|
1065
|
+
hif(idx < n) { idx <= idx + 1 }
|
1066
|
+
end
|
1067
|
+
end
|
1068
|
+
end
|
1069
|
+
return res
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
# HW implementation of the Ruby min_by.
|
1073
|
+
def smin_by(n = nil, &ruby_block)
|
1074
|
+
# No block given? Generate a new wrapper enumerator for smin_by.
|
1075
|
+
if !ruby_block then
|
1076
|
+
return SEnumeratorWrapper.new(self,:smin_by,n)
|
1077
|
+
end
|
1078
|
+
# A block is given, use smin with a proc that applies ruby_block
|
1079
|
+
# before comparing.
|
1080
|
+
return smin(n) { |a,b| ruby_block.call(a) <=> ruby_block.call(b) }
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
# HW implementation of the Ruby minmax.
|
1084
|
+
def sminmax(&ruby_block)
|
1085
|
+
# Generate the result signal.
|
1086
|
+
res = nil
|
1087
|
+
enum = self.seach
|
1088
|
+
HDLRuby::High.cur_system.open do
|
1089
|
+
res = enum.type[2].inner(HDLRuby.uniq_name(:"minmax_res"))
|
1090
|
+
end
|
1091
|
+
# Computes the min.
|
1092
|
+
res[0] <= enum.smin(&ruby_block)
|
1093
|
+
# Computes the max.
|
1094
|
+
res[1] <= enum.smax(&ruby_block)
|
1095
|
+
# Return the result.
|
1096
|
+
return res
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
# HW implementation of the Ruby minmax_by.
|
1100
|
+
def sminmax_by(&ruby_block)
|
1101
|
+
# Generate the result signal.
|
1102
|
+
res = nil
|
1103
|
+
enum = self.seach
|
1104
|
+
HDLRuby::High.cur_system.open do
|
1105
|
+
res = enum.type[2].inner(HDLRuby.uniq_name(:"minmax_res"))
|
1106
|
+
end
|
1107
|
+
# Computes the min.
|
1108
|
+
res[0] <= enum.smin_by(&ruby_block)
|
1109
|
+
# Computes the max.
|
1110
|
+
res[1] <= enum.smax_by(&ruby_block)
|
1111
|
+
# Return the result.
|
1112
|
+
return res
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
# Tell if none of the elements respects a given criterion given either
|
1116
|
+
# as +arg+ or as block.
|
1117
|
+
def snone?(arg = nil,&ruby_block)
|
1118
|
+
# Declare the result signal.
|
1119
|
+
res = nil
|
1120
|
+
HDLRuby::High.cur_system.open do
|
1121
|
+
res = bit.inner(HDLRuby.uniq_name(:"none_cond"))
|
1122
|
+
end
|
1123
|
+
# Initialize the result.
|
1124
|
+
res <= 1
|
1125
|
+
# Performs the computation.
|
1126
|
+
if arg then
|
1127
|
+
# Compare elements to arg.
|
1128
|
+
self.seach do |elem|
|
1129
|
+
res <= res & (elem != arg)
|
1130
|
+
end
|
1131
|
+
elsif ruby_block then
|
1132
|
+
# Use the ruby block.
|
1133
|
+
self.seach do |elem|
|
1134
|
+
res <= res & ~ruby_block.call(elem)
|
1135
|
+
end
|
1136
|
+
else
|
1137
|
+
raise "Ruby nil does not have any meaning in HW."
|
1138
|
+
end
|
1139
|
+
res
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
# Tell if one and only one of the elements respects a given criterion
|
1143
|
+
# given either as +arg+ or as block.
|
1144
|
+
def sone?(arg = nil,&ruby_block)
|
1145
|
+
# Declare the result signal.
|
1146
|
+
res = nil
|
1147
|
+
HDLRuby::High.cur_system.open do
|
1148
|
+
res = bit.inner(HDLRuby.uniq_name(:"one_cond"))
|
1149
|
+
end
|
1150
|
+
# Initialize the result.
|
1151
|
+
res <= 0
|
1152
|
+
# Performs the computation.
|
1153
|
+
if arg then
|
1154
|
+
# Compare elements to arg.
|
1155
|
+
self.seach do |elem|
|
1156
|
+
res <= res ^ (elem == arg)
|
1157
|
+
end
|
1158
|
+
elsif ruby_block then
|
1159
|
+
# Use the ruby block.
|
1160
|
+
self.seach do |elem|
|
1161
|
+
res <= res ^ ruby_block.call(elem)
|
1162
|
+
end
|
1163
|
+
else
|
1164
|
+
raise "Ruby nil does not have any meaning in HW."
|
1165
|
+
end
|
1166
|
+
res
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
# HW implementation of the Ruby partition.
|
1170
|
+
# NOTE: to do, or may be not.
|
1171
|
+
def spartition(*args,&ruby_block)
|
1172
|
+
raise "spartition is not supported yet."
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
# HW implementatiob of the Ruby reject.
|
1176
|
+
def sreject(&ruby_block)
|
1177
|
+
return sselect {|elem| ~ruby_block.call(elem) }
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
# HW implementatiob of the Ruby reverse_each.
|
1181
|
+
def sreverse_each(*args,&ruby_block)
|
1182
|
+
# No block given? Generate a new wrapper enumerator for
|
1183
|
+
# sreverse_each.
|
1184
|
+
if !ruby_block then
|
1185
|
+
return SEnumeratorWrapper.new(self,:sreverse_each,*args)
|
1186
|
+
end
|
1187
|
+
# A block is given.
|
1188
|
+
# Declares the index.
|
1189
|
+
enum = self.seach
|
1190
|
+
idx = nil
|
1191
|
+
HDLRuby::High.cur_system.open do
|
1192
|
+
idx = bit[enum.size.width].inner(HDLRuby.uniq_name(:"reverse_idx"))
|
1193
|
+
end
|
1194
|
+
# Do the iteration.
|
1195
|
+
idx <= enum.size
|
1196
|
+
SequencerT.current.swhile(idx > 0) do
|
1197
|
+
idx <= idx - 1
|
1198
|
+
ruby_block.call(*args,enum.access(idx))
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
# HW implementation of the Ruby slice_after.
|
1203
|
+
# NOTE: to do, or may be not.
|
1204
|
+
def sslice_after(pattern = nil,&ruby_block)
|
1205
|
+
raise "sslice_after is not supported yet."
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
# HW implementation of the Ruby slice_before.
|
1209
|
+
# NOTE: to do, or may be not.
|
1210
|
+
def sslice_before(*args,&ruby_block)
|
1211
|
+
raise "sslice_before is not supported yet."
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
# HW implementation of the Ruby slice_when.
|
1215
|
+
# NOTE: to do, or may be not.
|
1216
|
+
def sslice_when(*args,&ruby_block)
|
1217
|
+
raise "sslice_before is not supported yet."
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
# HW implementation of the Ruby sort.
|
1221
|
+
def ssort(&ruby_block)
|
1222
|
+
enum = self.seach
|
1223
|
+
n = enum.size
|
1224
|
+
# Declare the result signal the flag and the result array size index
|
1225
|
+
# used for implementing the algorithm (shift-based sorting).
|
1226
|
+
res = nil
|
1227
|
+
flg = nil
|
1228
|
+
idx = nil
|
1229
|
+
HDLRuby::High.cur_system.open do
|
1230
|
+
res = enum.type[-n].inner(HDLRuby.uniq_name(:"sort_res"))
|
1231
|
+
flg = bit.inner(HDLRuby.uniq_name(:"sort_flg"))
|
1232
|
+
idx = bit[n.width].inner(HDLRuby.uniq_name(:"sort_idx"))
|
1233
|
+
end
|
1234
|
+
# Performs the sort using a shift-based algorithm (also used in
|
1235
|
+
# smin).
|
1236
|
+
enum.srewind
|
1237
|
+
# Do the iteration.
|
1238
|
+
idx <= 0
|
1239
|
+
SequencerT.current.swhile(enum.snext?) do
|
1240
|
+
# Multiple min case.
|
1241
|
+
SequencerT.current.sif(enum.snext?) do
|
1242
|
+
elem = enum.snext
|
1243
|
+
flg <= 1
|
1244
|
+
n.times do |i|
|
1245
|
+
# Compute the comparison between the result element at i
|
1246
|
+
# and the enum element.
|
1247
|
+
if ruby_block then
|
1248
|
+
cond = ruby_block.call(res[i],elem) > 0
|
1249
|
+
else
|
1250
|
+
cond = res[i] > elem
|
1251
|
+
end
|
1252
|
+
# If flg is 0, elem is already set as min, skip.
|
1253
|
+
# If the result array size index is equal to i, then
|
1254
|
+
# put the element whatever the comparison is since the
|
1255
|
+
# place is still empty.
|
1256
|
+
hif(flg & (cond | (idx == i))) do
|
1257
|
+
# A new min is found, shift res from i.
|
1258
|
+
((i+1)..(n-1)).reverse_each { |j| res[j] <= res[j-1] }
|
1259
|
+
# An set the new min in current position.
|
1260
|
+
res[i] <= elem
|
1261
|
+
# For now skip.
|
1262
|
+
flg <= 0
|
1263
|
+
end
|
1264
|
+
end
|
1265
|
+
idx <= idx + 1
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
return res
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
# HW implementation of the Ruby sort.
|
1272
|
+
def ssort_by(&ruby_block)
|
1273
|
+
# No block given? Generate a new wrapper enumerator for smin_by.
|
1274
|
+
if !ruby_block then
|
1275
|
+
return SEnumeratorWrapper.new(self,:ssort_by,n)
|
1276
|
+
end
|
1277
|
+
# A block is given, use smin with a proc that applies ruby_block
|
1278
|
+
# before comparing.
|
1279
|
+
return ssort { |a,b| ruby_block.call(a) <=> ruby_block.call(b) }
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
# HW implementation of the Ruby sum.
|
1283
|
+
def ssum(initial_value = nil,&ruby_block)
|
1284
|
+
enum = self.seach
|
1285
|
+
# Define the computation type: from the initial value if any,
|
1286
|
+
# otherwise from the enum.
|
1287
|
+
typ = initial_value ? initial_value.to_expr.type : enum.type
|
1288
|
+
# Ensures there is an initial value.
|
1289
|
+
initial_value = 0.to_expr.as(typ) unless initial_value
|
1290
|
+
# Generate the result signal.
|
1291
|
+
res = nil
|
1292
|
+
HDLRuby::High.cur_system.open do
|
1293
|
+
res = typ.inner(HDLRuby.uniq_name(:"sum_res"))
|
1294
|
+
end
|
1295
|
+
# Start the initialization
|
1296
|
+
enum.srewind
|
1297
|
+
# Yes, start with the initial value.
|
1298
|
+
res <= initial_value
|
1299
|
+
SequencerT.current.swhile(enum.snext?) do
|
1300
|
+
# Do the accumulation.
|
1301
|
+
if (ruby_block) then
|
1302
|
+
# There is a ruby block, use it to process the element first.
|
1303
|
+
res <= res + ruby_block.call(enum.snext)
|
1304
|
+
else
|
1305
|
+
# No ruby block, just do the su,
|
1306
|
+
res <= res + enum.snext
|
1307
|
+
end
|
1308
|
+
end
|
1309
|
+
return res
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
# The HW implementation of the Ruby take.
|
1313
|
+
def stake(n)
|
1314
|
+
enum = self.seach
|
1315
|
+
# Generate the result signal.
|
1316
|
+
res = nil
|
1317
|
+
HDLRuby::High.cur_system.open do
|
1318
|
+
res = enum.type[-n].inner(HDLRuby.uniq_name(:"sum_res"))
|
1319
|
+
end
|
1320
|
+
# Take the n first elements.
|
1321
|
+
n.stimes do |i|
|
1322
|
+
res[i] <= enum.access(i)
|
1323
|
+
end
|
1324
|
+
return res
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
# The HW implementation of the Ruby take_while.
|
1328
|
+
def stake_while(&ruby_block)
|
1329
|
+
# No block given? Generate a new wrapper enumerator for sdrop_while.
|
1330
|
+
if !ruby_block then
|
1331
|
+
return SEnumeratorWrapper.new(self,:stake_while)
|
1332
|
+
end
|
1333
|
+
# A block is given.
|
1334
|
+
# Generate the vector to put the result in.
|
1335
|
+
# The declares the resulting vector and take flag.
|
1336
|
+
res = nil
|
1337
|
+
flg = nil
|
1338
|
+
enum = self.seach
|
1339
|
+
HDLRuby::High.cur_system.open do
|
1340
|
+
res = enum.type[-enum.size].inner(HDLRuby.uniq_name(:"take_vec"))
|
1341
|
+
flg = bit.inner(HDLRuby.uniq_name(:"take_flg"))
|
1342
|
+
end
|
1343
|
+
# And do the iteration.
|
1344
|
+
# First fill from current enumerable elements.
|
1345
|
+
flg <= 1
|
1346
|
+
enum.seach.with_index do |elem,i|
|
1347
|
+
HDLRuby::High.top_user.hif(flg == 1) do
|
1348
|
+
HDLRuby::High.top_user.hif(ruby_block.call(elem) == 0) do
|
1349
|
+
flg <= 0
|
1350
|
+
end
|
1351
|
+
end
|
1352
|
+
HDLRuby::High.top_user.hif(flg == 1) do
|
1353
|
+
res[i] <= elem
|
1354
|
+
end
|
1355
|
+
HDLRuby::High.top_user.helse do
|
1356
|
+
res[i] <= 0
|
1357
|
+
end
|
1358
|
+
end
|
1359
|
+
# Return the resulting vector.
|
1360
|
+
return res
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
# HW implementation of the Ruby tally.
|
1364
|
+
# NOTE: to do, or may be not.
|
1365
|
+
def stally(h = nil)
|
1366
|
+
raise "stally is not supported yet."
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
# HW implementation of the Ruby to_h.
|
1370
|
+
# NOTE: to do, or may be not.
|
1371
|
+
def sto_h(h = nil)
|
1372
|
+
raise "sto_h is not supported yet."
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
# HW implementation of the Ruby uniq.
|
1376
|
+
def suniq(&ruby_block)
|
1377
|
+
enum = self.seach
|
1378
|
+
n = enum.size
|
1379
|
+
# Declare the result signal the flag and the result array size index
|
1380
|
+
# used for implementing the algorithm (shift-based sorting).
|
1381
|
+
res = nil
|
1382
|
+
flg = nil
|
1383
|
+
idx = nil
|
1384
|
+
HDLRuby::High.cur_system.open do
|
1385
|
+
res = enum.type[-n].inner(HDLRuby.uniq_name(:"suniq_res"))
|
1386
|
+
flg = bit.inner(HDLRuby.uniq_name(:"suniq_flg"))
|
1387
|
+
idx = bit[n.width].inner(HDLRuby.uniq_name(:"suniq_idx"))
|
1388
|
+
end
|
1389
|
+
enum.srewind
|
1390
|
+
# Do the iteration.
|
1391
|
+
idx <= 0
|
1392
|
+
SequencerT.current.swhile(enum.snext?) do
|
1393
|
+
# Multiple min case.
|
1394
|
+
SequencerT.current.sif(enum.snext?) do
|
1395
|
+
elem = enum.snext
|
1396
|
+
flg <= 1
|
1397
|
+
n.times do |i|
|
1398
|
+
# Compute the comparison between the result element at i
|
1399
|
+
# and the enum element.
|
1400
|
+
hif(i < idx) do
|
1401
|
+
if ruby_block then
|
1402
|
+
flg <= (flg &
|
1403
|
+
(ruby_block.call(res[i]) != ruby_block.call(elem)))
|
1404
|
+
else
|
1405
|
+
flg <= (flg & (res[i] != elem))
|
1406
|
+
end
|
1407
|
+
end
|
1408
|
+
# If flg is 1 the element is new, if it is the right
|
1409
|
+
# position, add it to the result.
|
1410
|
+
hif((idx == i) & flg) do
|
1411
|
+
# An set the new min in current position.
|
1412
|
+
res[i] <= elem
|
1413
|
+
# For next position now.
|
1414
|
+
idx <= idx + 1
|
1415
|
+
# Stop here for current element.
|
1416
|
+
flg <= 0
|
1417
|
+
end
|
1418
|
+
end
|
1419
|
+
end
|
1420
|
+
end
|
1421
|
+
# Fills the remaining location with 0.
|
1422
|
+
SequencerT.current.swhile(idx < enum.size) do
|
1423
|
+
res[idx] <= 0
|
1424
|
+
idx <= idx + 1
|
1425
|
+
end
|
1426
|
+
return res
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
# HW implementation of the Ruby zip.
|
1430
|
+
# NOTE: for now szip is deactivated untile tuples are properly
|
1431
|
+
# handled by HDLRuby.
|
1432
|
+
def szip(obj,&ruby_block)
|
1433
|
+
res = nil
|
1434
|
+
l0,r0,l1,r1 = nil,nil,nil,nil
|
1435
|
+
idx = nil
|
1436
|
+
enum0 = self.seach
|
1437
|
+
enum1 = obj.seach
|
1438
|
+
# Compute the minimal and maximal iteration sizes of both
|
1439
|
+
# enumerables.
|
1440
|
+
size_min = [enum0.size,enum1.size].min
|
1441
|
+
size_max = [enum0.size,enum1.size].max
|
1442
|
+
HDLRuby::High.cur_system.open do
|
1443
|
+
# If there is no ruby_block, szip generates a resulting vector
|
1444
|
+
# and its access indexes.
|
1445
|
+
unless ruby_block then
|
1446
|
+
res = bit[enum0.type.width+enum1.type.width][-size_max].inner(HDLRuby.uniq_name(:"zip_res"))
|
1447
|
+
l0 = enum0.type.width+enum1.type.width - 1
|
1448
|
+
r0 = enum1.type.width
|
1449
|
+
l1 = r0-1
|
1450
|
+
r1 = 0
|
1451
|
+
end
|
1452
|
+
# Generate the index.
|
1453
|
+
idx = [size_max.width].inner(HDLRuby.uniq_name(:"zip_idx"))
|
1454
|
+
end
|
1455
|
+
# Do the iteration.
|
1456
|
+
enum0.srewind
|
1457
|
+
enum1.srewind
|
1458
|
+
# As long as there is enough elements.
|
1459
|
+
idx <= 0
|
1460
|
+
SequencerT.current.swhile(idx < size_min) do
|
1461
|
+
# Generate the access to the elements.
|
1462
|
+
elem0 = enum0.snext
|
1463
|
+
elem1 = enum1.snext
|
1464
|
+
if ruby_block then
|
1465
|
+
# A ruby block is given, applies it directly on the elements.
|
1466
|
+
ruby_block.call(elem0,elem1)
|
1467
|
+
else
|
1468
|
+
# No ruby block, put the access results into res.
|
1469
|
+
# res[idx][l0..r0] <= elem0
|
1470
|
+
# res[idx][l1..r1] <= elem1
|
1471
|
+
res[idx] <= [elem0,elem1]
|
1472
|
+
end
|
1473
|
+
idx <= idx + 1
|
1474
|
+
end
|
1475
|
+
# For the remaining iteration use zeros for the smaller enumerable.
|
1476
|
+
SequencerT.current.swhile(idx < size_max) do
|
1477
|
+
# Generate the access to the elements.
|
1478
|
+
elem0 = enum0.size < size_max ? 0 : enum0.snext
|
1479
|
+
elem1 = enum1.size < size_max ? 0 : enum1.snext
|
1480
|
+
if ruby_block then
|
1481
|
+
# A ruby block is given, applies it directly on the elements.
|
1482
|
+
ruby_block.call(elem0,elem1)
|
1483
|
+
else
|
1484
|
+
# No ruby block, put the access results into res.
|
1485
|
+
# res[idx][l0..r0] <= elem0
|
1486
|
+
# res[idx][l1..r1] <= elem1
|
1487
|
+
res[idx] <= [elem0,elem1]
|
1488
|
+
end
|
1489
|
+
idx <= idx + 1
|
1490
|
+
end
|
1491
|
+
unless ruby_block then
|
1492
|
+
return res
|
1493
|
+
end
|
1494
|
+
end
|
1495
|
+
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
|
1499
|
+
# Describes a sequencer enumerator class that allows to generate HW iteration
|
1500
|
+
# over HW or SW objects within sequencers.
|
1501
|
+
# This is the abstract Enumerator class.
|
1502
|
+
class SEnumerator
|
1503
|
+
include SEnumerable
|
1504
|
+
|
1505
|
+
# The methods that need to be defined.
|
1506
|
+
[:size, :type, :result, :index,
|
1507
|
+
:clone, :speek, :snext, :srewind].each do |name|
|
1508
|
+
define_method(:name) do
|
1509
|
+
raise "Method '#{name}' must be defined for a valid sequencer enumerator."
|
1510
|
+
end
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
# Iterate on each element.
|
1514
|
+
def seach(&ruby_block)
|
1515
|
+
# No block given, returns self.
|
1516
|
+
return self unless ruby_block
|
1517
|
+
# A block is given, iterate.
|
1518
|
+
this = self
|
1519
|
+
# Reitialize the iteration.
|
1520
|
+
this.srewind
|
1521
|
+
# Performs the iteration.
|
1522
|
+
SequencerT.current.swhile(self.index < self.size) do
|
1523
|
+
ruby_block.call(this.snext)
|
1524
|
+
end
|
1525
|
+
end
|
1526
|
+
|
1527
|
+
# Iterate on each element with index.
|
1528
|
+
def seach_with_index(&ruby_block)
|
1529
|
+
return self.with_index(&ruby_block)
|
1530
|
+
end
|
1531
|
+
|
1532
|
+
# Iterate on each element with arbitrary object +obj+.
|
1533
|
+
def seach_with_object(val,&ruby_block)
|
1534
|
+
# self.seach do |elem|
|
1535
|
+
# ruby_block(elem,val)
|
1536
|
+
# end
|
1537
|
+
return self.with_object(val,&ruby_block)
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
# Iterates with an index.
|
1541
|
+
def with_index(&ruby_block)
|
1542
|
+
# Is there a ruby block?
|
1543
|
+
if ruby_block then
|
1544
|
+
# Yes, iterate directly.
|
1545
|
+
idx = self.index
|
1546
|
+
return self.seach do |elem|
|
1547
|
+
ruby_block.call(elem,idx-1)
|
1548
|
+
end
|
1549
|
+
end
|
1550
|
+
# No, create a new enumerator with +with_index+ as default
|
1551
|
+
# iteration.
|
1552
|
+
return SEnumeratorWrapper.new(self,:with_index)
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
# Return a new SEnumerator with an arbitrary arbitrary object +obj+.
|
1556
|
+
def with_object(obj)
|
1557
|
+
# Is there a ruby block?
|
1558
|
+
if ruby_block then
|
1559
|
+
# Yes, iterate directly.
|
1560
|
+
return self.seach do |elem|
|
1561
|
+
ruby_block.call(elem,val)
|
1562
|
+
end
|
1563
|
+
end
|
1564
|
+
# No, create a new enumerator with +with_index+ as default
|
1565
|
+
# iteration.
|
1566
|
+
return SEnumeratorWrapper.new(self,:with_object,obj)
|
1567
|
+
end
|
1568
|
+
|
1569
|
+
# Return a new SEnumerator going on iteration over enumerable +obj+
|
1570
|
+
def +(obj)
|
1571
|
+
enum = self.clone
|
1572
|
+
obj_enum = obj.seach
|
1573
|
+
res = nil
|
1574
|
+
this = self
|
1575
|
+
HDLRuby::High.cur_system.open do
|
1576
|
+
res = this.type.inner(HDLRuby.uniq_name("enum_plus"))
|
1577
|
+
end
|
1578
|
+
return SEnumeratorBase.new(this.type,this.size+obj_enum.size) do|idx|
|
1579
|
+
HDLRuby::High.top_user.hif(idx < this.size) { res <= enum.snext }
|
1580
|
+
HDLRuby::High.top_user.helse { res <= obj_enum.snext }
|
1581
|
+
res
|
1582
|
+
end
|
1583
|
+
end
|
1584
|
+
end
|
1585
|
+
|
1586
|
+
|
1587
|
+
# Describes a sequencer enumerator class that allows to generate HW iterations
|
1588
|
+
# over HW or SW objects within sequencers.
|
1589
|
+
# This is the wrapper Enumerator over an other one for applying an other
|
1590
|
+
# interation method over the first one.
|
1591
|
+
class SEnumeratorWrapper < SEnumerator
|
1592
|
+
|
1593
|
+
# Create a new SEnumerator wrapper over +enum+ with +iter+ iteration
|
1594
|
+
# method and +args+ argument.
|
1595
|
+
def initialize(enum,iter,*args)
|
1596
|
+
if enum.is_a?(SEnumerator) then
|
1597
|
+
@enumerator = enum.clone
|
1598
|
+
else
|
1599
|
+
@enumerator = enum.seach
|
1600
|
+
end
|
1601
|
+
@iterator = iter.to_sym
|
1602
|
+
@arguments = args
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
# The directly delegate methods.
|
1606
|
+
def size
|
1607
|
+
return @enumerator.size
|
1608
|
+
end
|
1609
|
+
|
1610
|
+
def type
|
1611
|
+
return @enumerator.type
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
def result
|
1615
|
+
return @enumerator.result
|
1616
|
+
end
|
1617
|
+
|
1618
|
+
def index
|
1619
|
+
return @enumerator.index
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
def access(idx)
|
1623
|
+
return @enumerator.access(idx)
|
1624
|
+
end
|
1625
|
+
|
1626
|
+
def speek
|
1627
|
+
return @enumerator.speek
|
1628
|
+
end
|
1629
|
+
|
1630
|
+
def snext
|
1631
|
+
return @enumerator.snext
|
1632
|
+
end
|
1633
|
+
|
1634
|
+
def snext?
|
1635
|
+
return @enumerator.snext?
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
def srewind
|
1639
|
+
return @enumerator.srewind
|
1640
|
+
end
|
1641
|
+
|
1642
|
+
# Clones the enumerator.
|
1643
|
+
def clone
|
1644
|
+
return SEnumeratorWrapper.new(@enumerator,@iterator,*@arguments)
|
1645
|
+
end
|
1646
|
+
|
1647
|
+
# Iterate over each element.
|
1648
|
+
def seach(&ruby_block)
|
1649
|
+
# No block given, returns self.
|
1650
|
+
return self unless ruby_block
|
1651
|
+
# A block is given, iterate.
|
1652
|
+
return @enumerator.send(@iterator,*@arguments,&ruby_block)
|
1653
|
+
end
|
1654
|
+
end
|
1655
|
+
|
1656
|
+
|
1657
|
+
# Describes a sequencer enumerator class that allows to generate HW
|
1658
|
+
# iterations over HW or SW objects within sequencers.
|
1659
|
+
# This is the base Enumerator that directly iterates.
|
1660
|
+
class SEnumeratorBase < SEnumerator
|
1661
|
+
|
1662
|
+
attr_reader :size
|
1663
|
+
attr_reader :type
|
1664
|
+
attr_reader :result
|
1665
|
+
attr_reader :index
|
1666
|
+
|
1667
|
+
# Create a new sequencer for +size+ elements as +typ+ with an HW
|
1668
|
+
# array-like accesser +access+.
|
1669
|
+
def initialize(typ,size,&access)
|
1670
|
+
# Sets the size.
|
1671
|
+
@size = size
|
1672
|
+
# Sets the type.
|
1673
|
+
@type = typ
|
1674
|
+
# Sets the accesser.
|
1675
|
+
@access = access
|
1676
|
+
# Compute the index width (default: safe 32 bits).
|
1677
|
+
width = @size.respond_to?(:width) ? @size.width : 32
|
1678
|
+
# Create the index and the iteration result.
|
1679
|
+
idx = nil
|
1680
|
+
result = nil
|
1681
|
+
HDLRuby::High.cur_system.open do
|
1682
|
+
idx = [width].inner({
|
1683
|
+
HDLRuby.uniq_name("enum_idx") => 0 })
|
1684
|
+
result = typ.inner(HDLRuby.uniq_name("enum_res"))
|
1685
|
+
end
|
1686
|
+
@index = idx
|
1687
|
+
@result = result
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
# Clones the enumerator.
|
1691
|
+
def clone
|
1692
|
+
return SEnumeratorBase.new(@type,@size,&@access)
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
# Generates the access at +idx+
|
1696
|
+
def access(idx)
|
1697
|
+
@access.call(idx)
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
# View the next element without advancing the iteration.
|
1701
|
+
def speek
|
1702
|
+
@result <= @access.call(@index)
|
1703
|
+
return @result
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
# Get the next element.
|
1707
|
+
def snext
|
1708
|
+
@result <= @access.call(@index)
|
1709
|
+
@index <= @index + 1
|
1710
|
+
return @result
|
1711
|
+
end
|
1712
|
+
|
1713
|
+
# Tell if there is a next element.
|
1714
|
+
def snext?
|
1715
|
+
return @index < @size
|
1716
|
+
end
|
1717
|
+
|
1718
|
+
# Restart the iteration.
|
1719
|
+
def srewind
|
1720
|
+
@index <= 0
|
1721
|
+
end
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
|
1725
|
+
module HDLRuby::High::HExpression
|
1726
|
+
# Enhance the HExpression module with sequencer iteration.
|
1727
|
+
|
1728
|
+
# HW iteration on each element.
|
1729
|
+
def seach(&ruby_block)
|
1730
|
+
# Create the hardware iterator.
|
1731
|
+
this = self
|
1732
|
+
hw_enum = SEnumeratorBase.new(this.type.base,this.type.size) do |idx|
|
1733
|
+
this[idx]
|
1734
|
+
end
|
1735
|
+
# Is there a ruby block?
|
1736
|
+
if(ruby_block) then
|
1737
|
+
# Yes, apply it.
|
1738
|
+
return hw_enum.seach(&ruby_block)
|
1739
|
+
else
|
1740
|
+
# No, return the resulting enumerator.
|
1741
|
+
return hw_enum
|
1742
|
+
end
|
1743
|
+
end
|
1744
|
+
|
1745
|
+
# Also adds the methods of SEnumerable.
|
1746
|
+
SEnumerable.instance_methods.each do |meth|
|
1747
|
+
define_method(meth,SEnumerable.instance_method(meth))
|
1748
|
+
end
|
1749
|
+
end
|
1750
|
+
|
1751
|
+
|
1752
|
+
module ::Enumerable
|
1753
|
+
# Enhance the Enumerable module with sequencer iteration.
|
1754
|
+
|
1755
|
+
# HW iteration on each element.
|
1756
|
+
def seach(&ruby_block)
|
1757
|
+
# Convert the enumrable to an array for easier processing.
|
1758
|
+
ar = self.to_a
|
1759
|
+
return if ar.empty? # The array is empty, nothing to do.
|
1760
|
+
# Compute the type of the elements.
|
1761
|
+
typ = ar[0].respond_to?(:type) ? ar[0].type : signed[32]
|
1762
|
+
# Create the hardware iterator.
|
1763
|
+
hw_enum = SEnumeratorBase.new(typ,ar.size) do |idx|
|
1764
|
+
HDLRuby::High.top_user.mux(idx,*ar)
|
1765
|
+
end
|
1766
|
+
# Is there a ruby block?
|
1767
|
+
if(ruby_block) then
|
1768
|
+
# Yes, apply it.
|
1769
|
+
return hw_enum.seach(&ruby_block)
|
1770
|
+
else
|
1771
|
+
# No, return the resulting enumerator.
|
1772
|
+
return hw_enum
|
1773
|
+
end
|
1774
|
+
end
|
1775
|
+
|
1776
|
+
# Also adds the methods of SEnumerable.
|
1777
|
+
SEnumerable.instance_methods.each do |meth|
|
1778
|
+
define_method(meth,SEnumerable.instance_method(meth))
|
1779
|
+
end
|
1780
|
+
end
|
1781
|
+
|
1782
|
+
|
1783
|
+
class ::Range
|
1784
|
+
# Enhance the Range class with sequencer iteration.
|
1785
|
+
include SEnumerable
|
1786
|
+
|
1787
|
+
# HW iteration on each element.
|
1788
|
+
def seach(&ruby_block)
|
1789
|
+
# Create the iteration type.
|
1790
|
+
typ = bit[[self.first.width,self.last.width].max]
|
1791
|
+
# Create the hardware iterator.
|
1792
|
+
this = self
|
1793
|
+
size = this.size ? this.size : this.last - this.first + 1
|
1794
|
+
hw_enum = SEnumeratorBase.new(signed[32],size) do |idx|
|
1795
|
+
idx.as(typ) + this.first
|
1796
|
+
end
|
1797
|
+
# Is there a ruby block?
|
1798
|
+
if(ruby_block) then
|
1799
|
+
# Yes, apply it.
|
1800
|
+
return hw_enum.seach(&ruby_block)
|
1801
|
+
else
|
1802
|
+
# No, return the resulting enumerator.
|
1803
|
+
return hw_enum
|
1804
|
+
end
|
1805
|
+
end
|
1806
|
+
end
|
1807
|
+
|
1808
|
+
|
1809
|
+
class ::Integer
|
1810
|
+
# Enhance the Integer class with sequencer iterations.
|
1811
|
+
|
1812
|
+
# HW times iteration.
|
1813
|
+
def stimes(&ruby_block)
|
1814
|
+
return (0...self).seach(&ruby_block)
|
1815
|
+
end
|
1816
|
+
|
1817
|
+
# HW upto iteration.
|
1818
|
+
def supto(val,&ruby_block)
|
1819
|
+
return (self..val).seach(&ruby_block)
|
1820
|
+
end
|
1821
|
+
|
1822
|
+
# HW downto iteration.
|
1823
|
+
def sdownto(val,&ruby_block)
|
1824
|
+
# Create the hardware iterator.
|
1825
|
+
range = val..self
|
1826
|
+
hw_enum = SEnumeratorBase.new(signed[32],range.size) do |idx|
|
1827
|
+
range.last - idx
|
1828
|
+
end
|
1829
|
+
# Is there a ruby block?
|
1830
|
+
if(ruby_block) then
|
1831
|
+
# Yes, apply it.
|
1832
|
+
return hw_enum.seach(&ruby_block)
|
1833
|
+
else
|
1834
|
+
# No, return the resulting enumerator.
|
1835
|
+
return hw_enum
|
1836
|
+
end
|
1837
|
+
end
|
1838
|
+
end
|
1839
|
+
|
1840
|
+
|
1841
|
+
|
1842
|
+
# Creates a sequencer of code synchronised of +clk+ and starting on +start+.
|
1843
|
+
def sequencer(clk,start,&ruby_block)
|
1844
|
+
return SequencerT.new(clk,start,&ruby_block)
|
1845
|
+
end
|
1846
|
+
|
1847
|
+
# Creates an sequencer enumerator using a specific block access.
|
1848
|
+
# - +typ+ is the data type of the elements.
|
1849
|
+
# - +size+ is the number of elements.
|
1850
|
+
# - +access+ is the block implementing the access method.
|
1851
|
+
def senumerator(typ,size,&access)
|
1852
|
+
return SEnumeratorBase.new(typ,size,&access)
|
1853
|
+
end
|
1854
|
+
|
1855
|
+
|
1856
|
+
|
1857
|
+
end
|