HDLRuby 3.7.0 → 3.7.1

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: '096e1c8ad3a0b6627819a744569d9ef159a40201ed13b36f11203f4ba751ee84'
4
- data.tar.gz: c0d06d1991d5e8f4f691b56402cd00230f8f46f87a1fbbce235ccd27b6921140
3
+ metadata.gz: 01c5cc3826577779dad647fb9c8811d4bec3445bc19ca873f1015990aa689e68
4
+ data.tar.gz: 84985eda69036fe35175cc5255786c53839d7611a98170d2d1d131b3d4c0ec1d
5
5
  SHA512:
6
- metadata.gz: b13fed12851411946a251af87cb00053a1f65ef118b5ade71c017ed3642aec055c8c60943d9873422100e389a87dd404f98b16e1a55d90cb2529a2d137405b37
7
- data.tar.gz: fb7231f1cda8cef8afdfa13077952ecc3a71d281e12d83379df0bf64ffd1623266f2e59b218fd2e08be607225eaff0f901346cf892f1ad80f640401f45ff1f1b
6
+ metadata.gz: 45fbf8ad20c226c543770c85e3b41fd3dabf9fb337830c518544f67b86afd417240e3309575993e58a13de17233b8a197b08e9ca3a7ba7eb9a6e505900b41251
7
+ data.tar.gz: 8728928e73e6ccd092c5741be652d8f0730c7cf07f04ddbb4af64615b8472df2db50dfa6d0ad4c310c09270f61cc6d3e760fe6d4a87850ca97156ef64e2518ed
data/README.md CHANGED
@@ -17,9 +17,9 @@ hdrcc --get-tuto
17
17
 
18
18
  __What's new__
19
19
 
20
- For HDLRuby version 3.7.0:
20
+ For HDLRuby version 3.7.x:
21
21
 
22
- * Added the possibility to run sequencers in software (WIP).
22
+ * Added the possibility to run [sequencers in software](#sequencers-as-software-code). (WIP)
23
23
  This allows both much faster simulation and the use of the same code for both hardware and software design.
24
24
 
25
25
 
@@ -3221,7 +3221,7 @@ end
3221
3221
  ## Sequencer (software-like hardware coding):: `std/sequencer.rb`
3222
3222
  <a name="sequencer"></a>
3223
3223
 
3224
- This library provides a new set of software-like control statements for describing the behavior of a circuit. Behind the curtain, these constructs build a finite state machine where states are deduced from the control points within the description. Eventhough sequencers are ment to describe hardware, they are software-compatible so that they can efficiently be executed as software programs as explain in section [software sequencers](#sequencers-as-software-code).
3224
+ This library provides a new set of software-like control statements for describing the behavior of a circuit. Behind the curtain, these constructs build a finite state machine where states are deduced from the control points within the description. Eventhough sequencers are ment to describe hardware, they are software-compatible so that they can efficiently be executed as software programs as explain in section about [software sequencers](#sequencers-as-software-code).
3225
3225
 
3226
3226
  A sequencer can be declared anywhere in a system provided it is outside a behavior using the `sequencer` keyword as follows:
3227
3227
 
@@ -3725,7 +3725,7 @@ __Notes__:
3725
3725
 
3726
3726
  #### Introduction to Sequencer as Software Code
3727
3727
 
3728
- Sequencers can be executed in software using a Ruby interpreter with functional equivalance to the hardware implementation. To achieve this, the following headers must be added to your Ruby source code:
3728
+ Sequencers can be executed in software using a Ruby interpreter while maintaining functional equivalence with the hardware implementation. To achieve this, the following headers must be added to your Ruby source code:
3729
3729
 
3730
3730
  ```ruby
3731
3731
  require 'HDLRuby/std/sequencer_sw'
@@ -3733,7 +3733,7 @@ include RubyHDL::High
3733
3733
  using RubyHDL::High
3734
3734
  ```
3735
3735
 
3736
- After this, signals and sequencers can be described exactly like in HDLRuby. However, the resulting sequencer objects are not executed immediately and must be stored in a variable for further reference. For example the following Ruby code defines a sequencer, refered by the variable `my_seq`, which increments signal `counter` up to 1000:
3736
+ After this, signals and sequencers can be described exactly like in HDLRuby. However, the resulting sequencer objects are not executed immediately and must be stored in a variable for further reference. For example, the following Ruby code defines a sequencer, referred by the variable `my_seq`, which increments the signal `counter` up to 1000:
3737
3737
 
3738
3738
  ```ruby
3739
3739
  require 'HDLRuby/std/sequencer_sw'
@@ -3752,7 +3752,7 @@ end
3752
3752
 
3753
3753
  You may notice that no clock or start signal is provided to the sequencer. This is because, in software, execution is sequential, and no clock nor control signals are required. Instead, starting the execution of a sequencer is done using the call operators as follows: `my_seq.()`.
3754
3754
 
3755
- To verify wether the sequencer executed correctly, you can access the values of signals outside the sequencer using the `value` method. For example, the following code, initialize `counter` to 0, and then display the counter value after executing the sequencer.
3755
+ To verify whether the sequencer executed correctly, you can access signal values outside the sequencer using the `value` method. For example, the following code initializes `counter` to 0 and then displays the counter value after executing the sequencer.
3756
3756
 
3757
3757
  ```ruby
3758
3758
  require 'HDLRuby/std/sequencer_sw'
@@ -3781,6 +3781,17 @@ __Note__: When displaying the value of a signal, the `.value` method can be omit
3781
3781
  puts "counter=#{counter}"
3782
3782
  ```
3783
3783
 
3784
+ Internally, the HDLRuby code of a sequencer is converted to Ruby before execution. This code can be accessed through the `source` command. It can then be saved into a file for separate execution for example, as follows:
3785
+
3786
+ ```ruby
3787
+ File.open("sequencer_in_ruby.rb","w") do |f|
3788
+ f << my_seq.source
3789
+ end
3790
+ ```
3791
+
3792
+ __Note__: the ruby code for sequencers is compatible with mruby for execution on embedded systems.
3793
+
3794
+
3784
3795
  #### Why Would I Want to Execute a Sequencer in Software, and What are the Limitations?
3785
3796
 
3786
3797
  There are two main reasons for executing sequencers in software:
@@ -3793,12 +3804,12 @@ There are two main reasons for executing sequencers in software:
3793
3804
 
3794
3805
  * Reduced design time (no need for recoding).
3795
3806
 
3796
- While software sequencer are functionaly equivalent to their hardware implementation, their handling of time and parallelism is fundamentally different. In hardware, sequencers are implemented as finite state machines that transition according to a clock and that run in parallel with the remain of the circuits. By contrast, in software, sequencers are implemented as functions executed in sequence. If parallel synchronization is important in your design, e.g., a communication protocol, software sequencers may not be useful. However, there are ways to add hardware timing and parallelism in the following sections.
3807
+ While software sequencer are functionally equivalent to their hardware implementations, their handling of time and parallelism is fundamentally different. In hardware, sequencers are implemented as finite state machines that transition according to a clock and that run in parallel with the remain of the circuits. By contrast, in software, sequencers are implemented as fibers executed sequentially. If parallel synchronization is important in your design (e.g., a communication protocol), software sequencers may not be useful. However, there are ways to add hardware timing and parallelism as described in the following sections.
3797
3808
 
3798
3809
 
3799
3810
  #### Adding a Clock to a Software Sequencer.
3800
3811
 
3801
- While there is no clock in software, it is possible to simulate one while executing a sequencer to estimate its performance when implemented in hardware. This is done by passing as argument a signal that will be increase at each estimated clock cycle as follows:
3812
+ As mentioned earlier, there is no clock in software. However, it is possible to simulate one while executing a sequencer to estimate its performance when implemented in hardware. This is done by passing as argument a signal that will be increase at each estimated clock cycle as follows:
3802
3813
 
3803
3814
  ```ruby
3804
3815
  sequencer(<clock counting signal>) do
@@ -3806,8 +3817,7 @@ sequencer(<clock counting signal>) do
3806
3817
  end
3807
3818
  ```
3808
3819
 
3809
- After the executing of a sequencer with a clock, the estimate number of clock cycles required by the hardware implementation is stored into the clock signal. For example the following code will display `1000 clocks` which is the estimated number of executed clocks if the sequencer is implemented in hardware:
3810
-
3820
+ After the execution of a sequencer with a clock, the estimated number of clock cycles required for the hardware implementation is stored into the clock signal. For example, the following code will display `1000 clocks`, which is the estimated number of executed clocks if the sequencer were implemented in hardware:
3811
3821
 
3812
3822
  ```ruby
3813
3823
  [32].inner :clk_count
@@ -3824,7 +3834,7 @@ __Note__: In the code above, the sequencer is not stored in a variable because i
3824
3834
 
3825
3835
  #### Adding a Signal to Control the Execution of a Software Sequencer.
3826
3836
 
3827
- In addition to a clock counter signal, it is possible to add a signal that when written one will start the execution of a software sequencer, like it is the case for the hardware implementation. For that purpose this signal is to be passed as second argument of the sequencer. For example the following code, starts the execution of the sequencer using signal `start`:
3837
+ In addition to a clock counter signal, you can add a signal that, when set to 1, starts the execution of a software sequencer, just like in the hardware implementation. To achieve this, pass the signal as second argument of the sequencer. For example the following code, starts the execution of the sequencer using signal `start`:
3828
3838
 
3829
3839
  ```ruby
3830
3840
  [32].inner :clk_count
@@ -3840,7 +3850,7 @@ start.value = 1
3840
3850
  puts "#{clk_count} clocks"
3841
3851
  ```
3842
3852
 
3843
- With this alternate way for executing a software sequencer, it is not necesary any longer to store it into a ruby variable, and it is possible to start the execution of a sequencer exactly like in hardware, and also from anther sequencer. For example, in the following code, the sequencer sequencer start is controlled by the first one.
3853
+ With this alternative execution method, storing the sequencer in a Ruby variable is no longer necessary. The execution can be started exactly as in hardware, and also from another sequencer. For example, in the following code, the execution of the second sequencer is controlled by the first one.
3844
3854
 
3845
3855
  ```ruby
3846
3856
  [1].inner :start0, :start1
@@ -3857,7 +3867,6 @@ sequencer(nil,start1) do
3857
3867
  swhile(count1<100) { count1 <= count1 + 1 }
3858
3868
  end
3859
3869
  ```
3860
-
3861
3870
 
3862
3871
  #### Synchronizing Sequencers for Pseudo-Parallel Execution
3863
3872
 
@@ -3889,6 +3898,11 @@ puts "end at count=#{count}"
3889
3898
 
3890
3899
  For full cycle-accurate synchronization, insert a sync command at each estimated cycle. However, sync has a significant performance cost, and depending on the Ruby interpreter and software configuration, excessive use may make execution slower than the HDLRuby hardware simulator. Hence it is recommended to use this command only when necessary, and use the HDLRuby hardware simulator for cycle-accurate synchronization.
3891
3900
 
3901
+ Finally, to determine whether a sequencer has completed execution or is paused at sync command, use the `alive?` method. For example, the following code will resume execution of sequencer `my_seq` until it completes:
3902
+
3903
+ ```ruby
3904
+ my_seq.() while(my_seq.alive?)
3905
+ ```
3892
3906
 
3893
3907
  #### Executing ruby code within a software sequencer.
3894
3908
 
@@ -3903,6 +3917,18 @@ sequencer do
3903
3917
  end.()
3904
3918
  ```
3905
3919
 
3920
+ Another possibility is to put the code into a string as follows:
3921
+
3922
+ ```
3923
+ sequencer do
3924
+ stimes.10 do
3925
+ ruby('puts "Hello"')
3926
+ end
3927
+ end.()
3928
+ ```
3929
+
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.
3931
+
3906
3932
 
3907
3933
  ## Fixed-point (fixpoint): `std/fixpoint.rb`
3908
3934
  <a name="fixpoint"></a>
@@ -19,15 +19,19 @@ some_ruby_value = 1
19
19
  prog0 = sequencer(clk) do
20
20
  a <= 1
21
21
  b <= 2
22
- c <= ruby { some_ruby_value }
22
+ # c <= ruby { some_ruby_value }
23
+ c <= ruby("some_ruby_value")
23
24
  d <= 0
24
25
  i <= 0
25
26
  # swhile(c<10000000) do
26
- 10000000.stimes do
27
+ # 10000000.stimes do
28
+ sfor(0..10000000) do |u|
27
29
  c <= a + b + d
28
30
  d <= c + 1
29
- ar[i%4] <= i
30
- i <= i + 1
31
+ # ar[i%4] <= i
32
+ ar[u%4] <= i
33
+ sif(i<1000) { i <= i + 1 }
34
+ selse { i <= 0 }
31
35
  sync
32
36
  end
33
37
  a[4] <= 1
@@ -35,7 +39,10 @@ prog0 = sequencer(clk) do
35
39
  res0 <= ar[0]
36
40
  end
37
41
 
38
- puts "prog0 source code: #{prog0.source}\n"
42
+ puts "Generating file from prog0 source code..."
43
+ File.open("with_sw_hruby_mruby.rb","w") do |f|
44
+ f << prog0.source
45
+ end
39
46
 
40
47
  prog1 = sequencer do
41
48
  sloop do
@@ -44,6 +51,8 @@ prog1 = sequencer do
44
51
  end
45
52
  end
46
53
 
54
+ puts "Executing concurrently prog0 and prog1..."
55
+
47
56
  while prog0.alive? do
48
57
  prog0.call
49
58
  prog1.call
@@ -23,11 +23,14 @@ system :test_with_sw_ruby do
23
23
  i <= 0
24
24
  e <= 0
25
25
  # swhile(c<10000000) do
26
- 10000000.stimes do
26
+ # 10000000.stimes do
27
+ sfor(0..10000000) do |u|
27
28
  c <= a + b + d
28
29
  d <= c + 1
29
- ar[i%4] <= i
30
- i <= i + 1
30
+ # ar[i%4] <= i
31
+ ar[u%4] <= i
32
+ sif(i<1000) { i <= i + 1 }
33
+ selse { i <= 0 }
31
34
  end
32
35
  a[4] <= 1
33
36
  b[7..5] <= 5