HDLRuby 3.7.1 → 3.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01c5cc3826577779dad647fb9c8811d4bec3445bc19ca873f1015990aa689e68
4
- data.tar.gz: 84985eda69036fe35175cc5255786c53839d7611a98170d2d1d131b3d4c0ec1d
3
+ metadata.gz: 9c6e130a54f880c57186b29328c125d603604f4da1f25a5c4f890549a9847782
4
+ data.tar.gz: 19256d21296a7662f6241c27b41a969c0bb411c64084d8e48e740950c84867ac
5
5
  SHA512:
6
- metadata.gz: 45fbf8ad20c226c543770c85e3b41fd3dabf9fb337830c518544f67b86afd417240e3309575993e58a13de17233b8a197b08e9ca3a7ba7eb9a6e505900b41251
7
- data.tar.gz: 8728928e73e6ccd092c5741be652d8f0730c7cf07f04ddbb4af64615b8472df2db50dfa6d0ad4c310c09270f61cc6d3e760fe6d4a87850ca97156ef64e2518ed
6
+ metadata.gz: c6069997b2fbeb1acf6a4202e72fa6558060283de21d2ed2ea6a8ef72032f7c54166788346e03b4b4ba79d3c8cf0565edd3bee945b4c736907210b35b97d8331
7
+ data.tar.gz: be5e84ac24bd4df32e1a6a83fe37a294c9f17475de7c12bb8a40e96d944fb63f2e94556ea9cb6b954d82e81ff03fa44e9550dcd6cba349dc7d7b263e3808dece
data/README.md CHANGED
@@ -17,6 +17,16 @@ hdrcc --get-tuto
17
17
 
18
18
  __What's new__
19
19
 
20
+ For HDLRuby version 3.7.2:
21
+
22
+ * Added the `text` command for the sequencers in software.
23
+
24
+ * Added the `value_text` method to sequencers in software's signal for generatign Ruby/C code for accessing a value with correct typing.
25
+
26
+ * Added the `alive?` and `reset!` commands for HDLRuby sequencers.
27
+
28
+ * Added the `require_ruby` method for loading Ruby (i.e., non-HDLRuby) libraries.
29
+
20
30
  For HDLRuby version 3.7.x:
21
31
 
22
32
  * Added the possibility to run [sequencers in software](#sequencers-as-software-code). (WIP)
@@ -255,7 +265,9 @@ hdr_vhdl
255
265
  hdr_sim
256
266
  ```
257
267
 
268
+ ## HDLRuby files.
258
269
 
270
+ HDLRuby being built on top of the Ruby language, we choose as convension to name the HDLRuby file with the `.rb` extension. For the same reason, including external HDLRuby files is done using the `require` or `require_relative` methods, that are identical to their Ruby counterpart. Those method however can only be used for including HDLRuby description file and not Ruby ones, for the later, the method `require_ruby` and `require_relative_ruby` must be used instead.
259
271
 
260
272
 
261
273
  # HDLRuby programming guide
@@ -739,7 +751,7 @@ __Notes__:
739
751
  - Since this is Ruby code, the body can also be delimited by the `do` and `end` Ruby keywords (in which case the parentheses can be omitted) as follows:
740
752
 
741
753
  ```ruby
742
- system :box does
754
+ system :box do
743
755
  end
744
756
  ```
745
757
 
@@ -927,9 +939,17 @@ inner sig: 0
927
939
  As another example, an 8-bit 8-word ROM could be declared and initialized as follows:
928
940
 
929
941
  ```ruby
930
- bit[8][-8] rom: [ 0,1,2,3,4,5,6,7 ]
942
+ bit[8][-8] rom: [ _h00,_h01,_h02,_h03,_h04,_h05,_h06,_h07 ]
931
943
  ```
932
944
 
945
+ __Note__:
946
+
947
+ * The notation `_hXY` is used for indicating a 2-digit, `X` and `Y`, hexadecimal.
948
+
949
+ * By default, Ruby integers (not preceded by the `_` prefix) are typed as 64-bit HDLRuby values, whereas HDLRuby explicit values (preceded by the `_ ` prefix) have a bit-width corresponding to their representation.
950
+
951
+ * When declaring the contents of a ROM, the bit-width of the elements must match that of the declared type; otherwise, misalignments may occur.
952
+
933
953
 
934
954
  ### Scope in a system
935
955
 
@@ -3255,6 +3275,29 @@ A sequence is a specific case of a `seq` block that includes the following softw
3255
3275
 
3256
3276
  - `sterminate`: ends the execution of the sequence.
3257
3277
 
3278
+ - `alive?`: is 0 if the sequencer is still running and not 0 otherwise.
3279
+ Can be used outside the sequencer.
3280
+
3281
+ - `reset!`: resets the sequencer to its start.
3282
+ Can be used outside the sequencer.
3283
+
3284
+ The two last commands can be used to control a sequencer outside of it. For that purpose, a reference must be assigned to the sequencer as follows, where `ref_sequencer` is a Ruby variable that will refer to the sequencer:
3285
+
3286
+ ```ruby
3287
+ ref_sequencer = sequencer(clk,start) do
3288
+ < some sequencer code >
3289
+ end
3290
+
3291
+ < somewhere else in the code. >
3292
+
3293
+ # Reset the sequencer if it ended its execution.
3294
+ hif(ref_sequencer.alive? == 0) do
3295
+ ref_sequencer.reset!
3296
+ end
3297
+ ```
3298
+
3299
+
3300
+
3258
3301
  It is also possible to use enumerators (iterators) similar to the Ruby `each` using the following methods within sequences:
3259
3302
 
3260
3303
  - `<object>.seach`: `object` any enumerable Ruby object or any signal. If a block is given, it works like `sfor`, otherwise, it returns a HDLRuby enumerator (please see [enumerator](#hdlruby-enumerators-and-enumerable-objects-stdsequencerrb) for details about them).
@@ -3917,17 +3960,26 @@ sequencer do
3917
3960
  end.()
3918
3961
  ```
3919
3962
 
3920
- Another possibility is to put the code into a string as follows:
3963
+ Another possibility is to put the code into a string using the command `text` as follows:
3921
3964
 
3922
3965
  ```
3923
3966
  sequencer do
3924
3967
  stimes.10 do
3925
- ruby('puts "Hello"')
3968
+ text('puts "Hello"')
3926
3969
  end
3927
3970
  end.()
3928
3971
  ```
3929
3972
 
3930
- Both method are functionally equivalent. However, the first is faster and safer but is incompatible with separated code generation, while the second allows separate code generation but is slower and less safe.
3973
+ Both method are functionally equivalent. However, the first is safer as potential errors are detected at the compile stage, but is incompatible with separated code generation and is slow, while the second allows separate code generation, if fast, but is less safe since it is only at the execution stage that the code is checked.
3974
+
3975
+ __Note__: Since the string in text is grafted as is into the generated Ruby (or C) code, you cannot directly access the value of a signal. However, you can use to_ruby or to_c to access the underlying raw value, or use value_text to retrieve the value with proper type adjustment in case of overflow or underflow. For example, the following will display the raw value of signal sig0 and the hardware-accurate value of signal sig1:
3976
+
3977
+ ```ruby
3978
+ sequencer do
3979
+ text("puts #{sig0.to_ruby}")
3980
+ text("puts #{sig1.value_text}")
3981
+ end
3982
+ ```
3931
3983
 
3932
3984
 
3933
3985
  ## Fixed-point (fixpoint): `std/fixpoint.rb`
@@ -63,6 +63,7 @@ puts "b=#{b}"
63
63
  puts "c=#{c}"
64
64
  puts "d=#{d}"
65
65
  puts "ar=#{ar}"
66
+ puts "ar[1]=#{ar.value[1]}"
66
67
  puts "res0=#{res0}"
67
68
  puts "res1=#{res1}"
68
69
  puts "clk=#{clk}"
@@ -1466,6 +1466,11 @@ module HDLRuby::High
1466
1466
  sys.no_parent!
1467
1467
  systemT.scope.add_systemI(sys)
1468
1468
  end
1469
+ # Adds it programs.
1470
+ included.scope.each_program do |program|
1471
+ program.no_parent!
1472
+ systemT.scope.add_program(program)
1473
+ end
1469
1474
  # Adds its code.
1470
1475
  included.scope.each_code do |code|
1471
1476
  code.no_parent!
@@ -5495,6 +5500,16 @@ module HDLRuby::High
5495
5500
 
5496
5501
  end
5497
5502
 
5503
+ # Require a Ruby file.
5504
+ def self.require_ruby(str)
5505
+ require(str)
5506
+ end
5507
+
5508
+ # Require a Ruby file from current path.
5509
+ def self.require_relative_ruby(str)
5510
+ require_relative(str)
5511
+ end
5512
+
5498
5513
  # Tell if already configured.
5499
5514
  $HDLRuby_configure = false
5500
5515
 
@@ -559,7 +559,7 @@ module HDLRuby::High
559
559
  # Loads the code files.
560
560
  self.each_code do |code|
561
561
  if code.is_a?(Proc)
562
- TOPLEVEL_BINDING.eval(&code)
562
+ Object.instance_eval(&code)
563
563
  else
564
564
  Kernel.require("./"+code.to_s)
565
565
  end
@@ -315,6 +315,16 @@ module HDLRuby::High::Std
315
315
  expr.seach.with_index(&ruby_block)
316
316
  end
317
317
 
318
+ # Tell if the sequencer ends it execution.
319
+ def alive?
320
+ return @fsm.cur_state_sig != self.end_state_value
321
+ end
322
+
323
+ # Resets the sequencer.
324
+ def reset!
325
+ @fsm.next_state_sig <= self.start_state_value
326
+ end
327
+
318
328
 
319
329
  # Fills the top user with the content of block +blk+.
320
330
  def fill_top_user(blk)
@@ -54,7 +54,7 @@ module RubyHDL::High
54
54
 
55
55
  # Generate inner signals with type +type+ and names from +names+ list.
56
56
  def make_inners(type,*names)
57
- puts "make_inners with names=#{names.join(",")}"
57
+ # puts "make_inners with names=#{names.join(",")}"
58
58
  type = type.to_type
59
59
  last_sig = nil
60
60
  names.each do |name|
@@ -151,22 +151,44 @@ module RubyHDL::High
151
151
  # end
152
152
 
153
153
 
154
+ # RUBY_OPERATOR = {
155
+ # # Unary operators.
156
+ # :"-@" => "-(%s)", :"+@" => "+(%s)", :"~" => "~(%s)",
157
+ # :abs => "(%s).abs",
158
+ # :boolean => "%s", :bit => "%s",
159
+ # :signed => "%s", :unsigned => "(%s) & 0xFFFFFFFFFFFFFFFF",
160
+
161
+ # # Binary operators.
162
+ # :"+" => "(%s)+(%s)", :"-" => "(%s)-(%s)", :"*" => "(%s)*(%s)",
163
+ # :"/" => "(%s)/(%s)", :"%" => "(%s)%%(%s)", :"**" => "(%s)**(%s)",
164
+ # :"&" => "(%s)&(%s)", :"|" => "(%s)|(%s)", :"^" => "(%s)^(%s)",
165
+ # :"<<" => "(%s)<<(%s)", :">>" => "(%s)>>(%s)",
166
+ # :"==" => "(%s)==(%s)", :"!=" => "(%s)!=(%s)",
167
+ # :"<" => "(%s)<(%s)", :">" => "(%s)>(%s)",
168
+ # :"<=" => "(%s)<=(%s)",:">=" => "(%s)>=(%s)"
169
+ # }
170
+
154
171
  # The translation of operators into Ruby code.
155
172
  RUBY_OPERATOR = {
156
173
  # Unary operators.
157
- :"-@" => "-(%s)", :"+@" => "+(%s)", :"~" => "~(%s)",
158
- :abs => "(%s).abs",
159
- :boolean => "%s", :bit => "%s",
160
- :signed => "%s", :unsigned => "(%s) & 0xFFFFFFFFFFFFFFFF",
174
+ :"-@" => "-(%{l})", :"+@" => "+(%{l})", :"~" => "~(%{l})",
175
+ :abs => "(%{l}).abs",
176
+ :boolean => "%{l}", :bit => "%{l}",
177
+ :signed => "%{l}", :unsigned => "(%{l}) & 0xFFFFFFFFFFFFFFFF",
161
178
 
162
179
  # Binary operators.
163
- :"+" => "(%s)+(%s)", :"-" => "(%s)-(%s)", :"*" => "(%s)*(%s)",
164
- :"/" => "(%s)/(%s)", :"%" => "(%s)%%(%s)", :"**" => "(%s)**(%s)",
165
- :"&" => "(%s)&(%s)", :"|" => "(%s)|(%s)", :"^" => "(%s)^(%s)",
166
- :"<<" => "(%s)<<(%s)", :">>" => "(%s)>>(%s)",
167
- :"==" => "(%s)==(%s)", :"!=" => "(%s)!=(%s)",
168
- :"<" => "(%s)<(%s)", :">" => "(%s)>(%s)",
169
- :"<=" => "(%s)<=(%s)",:">=" => "(%s)>=(%s)"
180
+ :"+" => "(%{l})+(%{r})", :"-" => "(%{l})-(%{r})",
181
+ :"*" => "(%{l})*(%{r})", :"/" => "(%{l})/(%{r})",
182
+ :"%" => "(%{l})%%(%{r})", :"**" => "(%{l})**(%{r})",
183
+ :"&" => "(%{l})&(%{r})", :"|" => "(%{l})|(%{r})",
184
+ :"^" => "(%{l})^(%{r})",
185
+ :"<<" => "(%{l})<<(%{r})", :">>" => "(%{l})>>(%{r})",
186
+ :"==" => "(%{l}) & %{m}==(%{r}) & %{m}",
187
+ :"!=" => "(%{l}) & %{m}!=(%{r}) %{m}",
188
+ :"<" => "(%{l}) & %{m}%{s} < (%{r}) & %{m}%{s}",
189
+ :">" => "(%{l}) & %{m}%{s} > (%{r}) & %{m}%{s}",
190
+ :"<=" => "(%{l}) & %{m}%{s} <=(%{r}) & %{m}%{s}",
191
+ :">=" => "(%{l}) & %{m}%{s} >=(%{r}) & %{m}%{s}"
170
192
  }
171
193
 
172
194
  # The translation of operators into C code.
@@ -985,12 +1007,30 @@ module RubyHDL::High
985
1007
 
986
1008
  # The signed bit type.
987
1009
  Signed = define_type(:signed)
1010
+ class << Signed
1011
+ # Tells if the type signed.
1012
+ def signed?
1013
+ return true
1014
+ end
1015
+ end
988
1016
 
989
1017
  # The unsigned bit type.
990
1018
  Unsigned = define_type(:unsigned)
1019
+ class << Unsigned
1020
+ # Tells if the type unsigned.
1021
+ def unsigned?
1022
+ return true
1023
+ end
1024
+ end
991
1025
 
992
1026
  # The float bit type
993
1027
  Float = define_type(:float)
1028
+ class << Float
1029
+ # Tells if the type signed.
1030
+ def signed?
1031
+ return true
1032
+ end
1033
+ end
994
1034
 
995
1035
  # The string type
996
1036
  StringT = define_type(:string)
@@ -1823,11 +1863,13 @@ module RubyHDL::High
1823
1863
  super(type)
1824
1864
  @operator = operator.to_sym
1825
1865
  @child = child.to_expr
1866
+ @mask = (2 ** @type.width)-1
1826
1867
  end
1827
1868
 
1828
1869
  # Convert to Ruby code.
1829
1870
  def to_ruby
1830
- return RUBY_OPERATOR[@operator] % @child.to_ruby
1871
+ # return RUBY_OPERATOR[@operator] % @child.to_ruby
1872
+ return RUBY_OPERATOR[@operator] % { l: @child.to_ruby }
1831
1873
  end
1832
1874
 
1833
1875
  # Convert to C code.
@@ -1845,11 +1887,22 @@ module RubyHDL::High
1845
1887
  @operator = operator.to_sym
1846
1888
  @left = left.to_expr
1847
1889
  @right = right.to_expr
1890
+ # Compute the mask for fixing the bit width.
1891
+ @mask = (2 ** @type.width)-1
1892
+ # Compute xor mask for handling the sign.
1893
+ # Make it as a string so that no addition computation is required
1894
+ # if no sign is required.
1895
+ @sign_fix = ""
1896
+ if type.signed? then
1897
+ @sign_fix = " ^ #{2**(@type.width-1)}"
1898
+ end
1848
1899
  end
1849
1900
 
1850
1901
  # Convert to Ruby code.
1851
1902
  def to_ruby
1852
- return RUBY_OPERATOR[@operator] % [ @left.to_ruby, @right.to_ruby ]
1903
+ # return RUBY_OPERATOR[@operator] % [ @left.to_ruby, @right.to_ruby ]
1904
+ return RUBY_OPERATOR[@operator] %
1905
+ { l: @left.to_ruby, r: @right.to_ruby, m: @mask, s: @sign_fix }
1853
1906
  end
1854
1907
 
1855
1908
  # Convert to C code.
@@ -3110,6 +3163,9 @@ module RubyHDL::High
3110
3163
  def initialize(type,name)
3111
3164
  @type = type.to_type
3112
3165
  @name = name.to_sym
3166
+ # Compute the mask for adjusting the value to the type.
3167
+ @mask = (2 ** @type.width)-1
3168
+ @sign = 2 ** (@type.width-1)
3113
3169
  end
3114
3170
 
3115
3171
  # Tell if the signal is an array.
@@ -3132,7 +3188,31 @@ module RubyHDL::High
3132
3188
 
3133
3189
  # Gets the value of the signal.
3134
3190
  def value
3135
- return TOPLEVEL_BINDING.eval(self.to_ruby)
3191
+ # return TOPLEVEL_BINDING.eval(self.to_ruby)
3192
+ res = TOPLEVEL_BINDING.eval(self.to_ruby)
3193
+ if res.is_a?(Integer) then
3194
+ res = res & @mask
3195
+ if @type.signed? then
3196
+ if res & @sign != 0 then
3197
+ return res - (@mask+1)
3198
+ end
3199
+ end
3200
+ end
3201
+ return res
3202
+ end
3203
+
3204
+ # Generate a Ruby/C string code for accessing the value of the
3205
+ # signal with proper bit width and sign.
3206
+ def value_text
3207
+ unless self.array? then
3208
+ if @type.signed? then
3209
+ return "(#{self.to_ruby} & #{@sign} != 0 ? #{self.to_ruby} & #{@mask} - #{@mask+1} : #{self.to_ruby} & #{@mask})"
3210
+ else
3211
+ return "(#{self.to_ruby} & #{@mask})"
3212
+ end
3213
+ else
3214
+ return self.to_ruby
3215
+ end
3136
3216
  end
3137
3217
 
3138
3218
  # Sets the value of the signal.
@@ -3272,16 +3352,19 @@ module RubyHDL::High
3272
3352
  def sif(cond, &ruby_block)
3273
3353
  self << RubyHDL::High::Sif.new(@sequencer,cond,&ruby_block)
3274
3354
  end
3355
+ alias_method :hif, :sif
3275
3356
 
3276
3357
  # Create a sequential elsif statement on +cond+.
3277
3358
  def selsif(cond, &ruby_block)
3278
3359
  self.last_statement.selsif(&ruby_block)
3279
3360
  end
3361
+ alias_method :helsif, :selsif
3280
3362
 
3281
3363
  # Create a sequential else statement.
3282
3364
  def selse(&ruby_block)
3283
3365
  self.last_statement.selse(&ruby_block)
3284
3366
  end
3367
+ alias_method :helse, :selse
3285
3368
 
3286
3369
  # Wait a given condition.
3287
3370
  def swait(cond)
@@ -3321,6 +3404,11 @@ module RubyHDL::High
3321
3404
  def ruby(str = nil, &ruby_block)
3322
3405
  self << RubyHDL::High::Ruby.new(str,&ruby_block)
3323
3406
  end
3407
+
3408
+ # Some arbitrary code whose text is to add direction.
3409
+ def text(str)
3410
+ self << str.to_s
3411
+ end
3324
3412
  end
3325
3413
 
3326
3414
 
@@ -3411,7 +3499,7 @@ Fiber.new do
3411
3499
  end
3412
3500
  BUILD
3413
3501
  # puts "building code_txt=" + @source
3414
- @code = TOPLEVEL_BINDING.eval(@source)
3502
+ self.reset!
3415
3503
  end
3416
3504
 
3417
3505
  # Get the Ruby code.
@@ -3462,6 +3550,11 @@ BUILDC
3462
3550
  end
3463
3551
  alias_method :call, :resume
3464
3552
 
3553
+ # Resets the sequencer.
3554
+ def reset!
3555
+ @code = TOPLEVEL_BINDING.eval(@source)
3556
+ end
3557
+
3465
3558
  # Check is the sequencer can still be resumed.
3466
3559
  def alive?
3467
3560
  @code.alive?
@@ -3479,6 +3572,11 @@ BUILDC
3479
3572
  return SequencerT.new(clk,start,&ruby_block)
3480
3573
  end
3481
3574
 
3575
+ # Create a 1-bit signal.
3576
+ def inner(*names)
3577
+ return [1].inner(*names)
3578
+ end
3579
+
3482
3580
  # Create a new function named +name+, built using block +ruby_block+.
3483
3581
  def sdef(name,&ruby_block)
3484
3582
  name = name.to_sym
@@ -1,3 +1,3 @@
1
1
  module HDLRuby
2
- VERSION = "3.7.1"
2
+ VERSION = "3.7.2"
3
3
  end
@@ -131,6 +131,12 @@ To do this, you can use the following command:</p>
131
131
  </code></pre>
132
132
  <p><strong>Note</strong>: for the command above, it is assumed that 'adder.v' contains a simulation benchmark.</p>
133
133
  <p>And that's it! For details about all the actions that can be performed, how to write an input file, and what kind of output can be produced, let us see the remaining of the tutorial.</p>
134
+ <h3>1.4. About the HDLRuby files.</h3>
135
+ <p>The HDLRuby files, that include HDLRuby description of circuits, are text files (the default encoding is UTF-8), is file name's extension is by convension <code>.rb</code>. It is possible to include other HDLRuby file within the current one using the <code>require</code> (for HDLRuby standard files) or <code>require_relative</code> (for local HDLRuby files) methods as follows:</p>
136
+ <pre><code class="language-ruby">require &quot;filename&quot;
137
+ require_relative &quot;path_to_another_filename&quot;
138
+ </code></pre>
139
+ <p>As it will be seen later, software Ruby code can also be used for generic descriptions of circuits. It is also possible to include Ruby code from different files using respectively <code>require_ruby</code> for standard libraries and gems, and <code>require_relative_ruby</code> for local files.</p>
134
140
  <h2>2. How to represent a circuit in HDLRuby</h2>
135
141
  <p>In this section we will see:</p>
136
142
  <ul>
data/tuto/tutorial_sw.md CHANGED
@@ -187,6 +187,18 @@ __Note__: for the command above, it is assumed that 'adder.v' contains a simulat
187
187
 
188
188
  And that's it! For details about all the actions that can be performed, how to write an input file, and what kind of output can be produced, let us see the remaining of the tutorial.
189
189
 
190
+ ### 1.4. About the HDLRuby files.
191
+
192
+ The HDLRuby files, that include HDLRuby description of circuits, are text files (the default encoding is UTF-8), is file name's extension is by convension `.rb`. It is possible to include other HDLRuby file within the current one using the `require` (for HDLRuby standard files) or `require_relative` (for local HDLRuby files) methods as follows:
193
+
194
+ ```ruby
195
+ require "filename"
196
+ require_relative "path_to_another_filename"
197
+ ```
198
+
199
+ As it will be seen later, software Ruby code can also be used for generic descriptions of circuits. It is also possible to include Ruby code from different files using respectively `require_ruby` for standard libraries and gems, and `require_relative_ruby` for local files.
200
+
201
+
190
202
 
191
203
  ## 2. How to represent a circuit in HDLRuby
192
204
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: HDLRuby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.1
4
+ version: 3.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lovic Gauthier
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-16 00:00:00.000000000 Z
10
+ date: 2025-03-24 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler