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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01c5cc3826577779dad647fb9c8811d4bec3445bc19ca873f1015990aa689e68
|
4
|
+
data.tar.gz: 84985eda69036fe35175cc5255786c53839d7611a98170d2d1d131b3d4c0ec1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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,
|
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
|
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
|
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
|
-
|
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
|
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,
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|