HDLRuby 3.0.0 → 3.2.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/HDLRuby.gemspec +1 -0
  3. data/README.md +149 -79
  4. data/ext/hruby_sim/hruby_rcsim_build.c +2 -0
  5. data/ext/hruby_sim/hruby_sim_calc.c +33 -6
  6. data/ext/hruby_sim/hruby_sim_tree_calc.c +111 -22
  7. data/lib/HDLRuby/hdr_samples/comparison_bench.rb +2 -2
  8. data/lib/HDLRuby/hdr_samples/constant_in_function.rb +2 -1
  9. data/lib/HDLRuby/hdr_samples/counter_bench.rb +1 -1
  10. data/lib/HDLRuby/hdr_samples/counter_dff_bench.rb +8 -7
  11. data/lib/HDLRuby/hdr_samples/dff_properties.rb +2 -0
  12. data/lib/HDLRuby/hdr_samples/enum_as_param.rb +52 -0
  13. data/lib/HDLRuby/hdr_samples/linear_test.rb +2 -0
  14. data/lib/HDLRuby/hdr_samples/logic_bench.rb +6 -0
  15. data/lib/HDLRuby/hdr_samples/mei8.rb +6 -6
  16. data/lib/HDLRuby/hdr_samples/mei8_bench.rb +6 -6
  17. data/lib/HDLRuby/hdr_samples/memory_test.rb +2 -0
  18. data/lib/HDLRuby/hdr_samples/named_sub.rb +9 -5
  19. data/lib/HDLRuby/hdr_samples/ram.rb +7 -6
  20. data/lib/HDLRuby/hdr_samples/ruby_fir_hw.rb +2 -0
  21. data/lib/HDLRuby/hdr_samples/struct.rb +15 -3
  22. data/lib/HDLRuby/hdr_samples/with_bram.rb +1 -1
  23. data/lib/HDLRuby/hdr_samples/with_bram_frame_stack.rb +1 -1
  24. data/lib/HDLRuby/hdr_samples/with_bram_stack.rb +1 -1
  25. data/lib/HDLRuby/hdr_samples/with_channel.rb +2 -0
  26. data/lib/HDLRuby/hdr_samples/with_channel_other.rb +2 -0
  27. data/lib/HDLRuby/hdr_samples/with_class.rb +3 -1
  28. data/lib/HDLRuby/hdr_samples/with_connector.rb +2 -0
  29. data/lib/HDLRuby/hdr_samples/with_connector_memory.rb +2 -0
  30. data/lib/HDLRuby/hdr_samples/with_fixpoint.rb +6 -0
  31. data/lib/HDLRuby/hdr_samples/with_fixpoint_adv.rb +73 -0
  32. data/lib/HDLRuby/hdr_samples/with_leftright.rb +1 -1
  33. data/lib/HDLRuby/hdr_samples/with_ref_expr.rb +30 -0
  34. data/lib/HDLRuby/hdr_samples/with_sequencer.rb +49 -37
  35. data/lib/HDLRuby/hdr_samples/with_sequencer_channel.rb +58 -0
  36. data/lib/HDLRuby/hdr_samples/with_sequencer_enumerable.rb +113 -69
  37. data/lib/HDLRuby/hdr_samples/with_sequencer_enumerator.rb +28 -14
  38. data/lib/HDLRuby/hdr_samples/with_sequencer_func.rb +63 -0
  39. data/lib/HDLRuby/hdr_samples/with_sequencer_sync.rb +2 -1
  40. data/lib/HDLRuby/hdrcc.rb +13 -1
  41. data/lib/HDLRuby/hruby_high.rb +105 -31
  42. data/lib/HDLRuby/hruby_low.rb +127 -3
  43. data/lib/HDLRuby/hruby_low2programs.rb +47 -0
  44. data/lib/HDLRuby/hruby_low_resolve.rb +3 -2
  45. data/lib/HDLRuby/hruby_low_without_namespace.rb +133 -5
  46. data/lib/HDLRuby/hruby_low_without_subsignals.rb +51 -12
  47. data/lib/HDLRuby/hruby_rcsim.rb +24 -1
  48. data/lib/HDLRuby/hruby_serializer.rb +2 -1
  49. data/lib/HDLRuby/hruby_types.rb +5 -5
  50. data/lib/HDLRuby/hruby_values.rb +7 -7
  51. data/lib/HDLRuby/hruby_verilog.rb +193 -35
  52. data/lib/HDLRuby/hruby_verilog_name.rb +35 -42
  53. data/lib/HDLRuby/std/fixpoint.rb +2 -2
  54. data/lib/HDLRuby/std/fsm.rb +10 -1
  55. data/lib/HDLRuby/std/function_generator.rb +1 -1
  56. data/lib/HDLRuby/std/linear.rb +7 -7
  57. data/lib/HDLRuby/std/sequencer.rb +538 -60
  58. data/lib/HDLRuby/std/sequencer_channel.rb +90 -0
  59. data/lib/HDLRuby/std/sequencer_func.rb +546 -0
  60. data/lib/HDLRuby/std/std.rb +2 -0
  61. data/lib/HDLRuby/version.rb +1 -1
  62. data/tuto/tutorial_sw.md +267 -61
  63. metadata +25 -4
  64. data/lib/HDLRuby/hdr_samples/with_register_stack.rb +0 -150
data/README.md CHANGED
@@ -11,6 +11,28 @@ If you are new to HDLRuby, it is recommended that you consult first the followin
11
11
 
12
12
  __What's new__
13
13
 
14
+ For HDLRuby version 3.2.0:
15
+
16
+ * Added component for declaring BRAM and BRAM-based stacks.
17
+ The goal is to efficiently allocate memories inside FPGAs.
18
+
19
+ * Inner code overhaul for preparing version 4.0.0
20
+
21
+ * Multiple bug fixes
22
+
23
+
24
+ For HDLRuby version 3.1.0:
25
+
26
+ * [Functions for sequencers](#sequencer-specific-function-std-sequencer_func-rb) supporting recursion;
27
+
28
+ * The `function` keyword was replaced with `hdef` for better consistency with the new functions for sequencers;
29
+
30
+ * The `steps` command was added for waiting several steps in a sequencer;
31
+
32
+ * Verilog HDL code generation was improved to preserve as much as possible the original names of the signals;
33
+
34
+ * Several bug fixes for the sequencers.
35
+
14
36
  For HDLRuby version 3.0.0:
15
37
 
16
38
  * This section;
@@ -39,7 +61,7 @@ git clone HDLRuby
39
61
  __Warning__:
40
62
 
41
63
  - This is still preliminary work which may change before we release a stable version.
42
- - It is highly recommended to have both basic knowledge of the Ruby language and hardware description languages before using HDLRuby.
64
+ - It is highly recommended to have both basic knowledges of the Ruby language and hardware description languages before using HDLRuby.
43
65
 
44
66
 
45
67
  # Compiling HDLRuby descriptions
@@ -72,7 +94,7 @@ Where:
72
94
  | `-S, --sim` | Perform the simulation with the default engine |
73
95
  | `--csim` | Perform the simulation with the standalone engine |
74
96
  | `--rsim` | Perform the simulation with the Ruby engine |
75
- | `--rcsim` | Perform the simulation with the Hybris engine |
97
+ | `--rcsim` | Perform the simulation with the Hybrid engine |
76
98
  | `--vcd` | Make the simulator generate a VCD file |
77
99
  | `-d, --directory` | Specify the base directory for loading the HDLRuby files |
78
100
  | `-D, --debug` | Set the HDLRuby debug mode |
@@ -92,7 +114,7 @@ __Notes__:
92
114
  hdrcc --get-samples
93
115
  ```
94
116
 
95
- Then in your current directory (folder) the `hdr_samples` subdirectory will appear that contains several HDLRuby example files. For details about the samples can be found there: [samples](#sample-hdlruby-descriptions).
117
+ Then in your current directory (folder) the `hdr_samples` subdirectory will appear that contains several HDLRuby example files. Details about the samples can be found here: [samples](#sample-hdlruby-descriptions).
96
118
 
97
119
 
98
120
  __Examples__:
@@ -103,7 +125,7 @@ __Examples__:
103
125
  hdrcc --yaml --top adder adder.rb adder
104
126
  ```
105
127
 
106
- * Compile `adder.rb` input file and generate a low-level Verilog HDL description into directory `adder`:
128
+ * Compile `adder.rb` input file and generate a low-level Verilog HDL description into the directory `adder`:
107
129
 
108
130
  ```bash
109
131
  hdrcc -v adder.rb adder
@@ -121,7 +143,7 @@ hdrcc -V -t adder --param 16 adder_gen.rb adder
121
143
  hdrcc -y -t multer -p 16,16,32 multer_gen.rb multer
122
144
  ```
123
145
 
124
- * Simulate the circuit described in file `counter_bench.rb` using the default simulation engine and putting the simulator's files in directory `counter`:
146
+ * Simulate the circuit described in file `counter_bench.rb` using the default simulation engine and putting the simulator's files in the directory `counter`:
125
147
 
126
148
  ```bash
127
149
  hdrcc -S counter_bench.rb counter
@@ -257,7 +279,7 @@ system :counter2 do
257
279
  end
258
280
  ```
259
281
 
260
- In the code above, two possible connection methods are shown: for `dff0` ports are connected by name, and for `dff1` ports are connected by declaration order. Please notice that it is also possible to connect only a subset of the ports while declaring, and to reconnect already connected ports in further statements.
282
+ In the code above, two possible connection methods are shown: for `dff0` ports are connected by name, and for `dff1` ports are connected in declaration order. Please notice that it is also possible to connect only a subset of the ports while declaring, as well as to reconnect already connected ports in further statements.
261
283
 
262
284
  While a circuit can be generated from the code given above, a benchmark must
263
285
  be provided to test it. Such a benchmark is described by constructs called
@@ -323,8 +345,7 @@ instance :dff_single do
323
345
  end
324
346
  ```
325
347
 
326
- In the example above, `dff_single` is an instance describing, again, a
327
- D-FF, but whose system is anonymous.
348
+ In the example above, `dff_single` is an instance describing, again, a D-FF, but whose system is anonymous.
328
349
 
329
350
  Furthermore, generic parameters can be used for anything in HDLRuby.
330
351
  For instance, the following code describes an 8-bit register without any parameterization:
@@ -482,7 +503,7 @@ sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit
482
503
 
483
504
  As seen in the code above, when passing a generic argument for instantiating a generic system, the name of the instance is put between brackets for avoiding confusion.
484
505
 
485
- While the description `sumprod` is already usable in a wide range of cases, it still uses standard addition and multiplication. However, there are cases where specific components are to be used for these operations, either for sake of performance, compliance with constraints, or because functionally different operations are required (e.g., saturated computations). This can be solved by using functions implementing such computation in place of operators, for example as follows:
506
+ While the description `sumprod` is already usable in a wide range of cases, it still uses standard addition and multiplication. However, there are cases where specific components are to be used for these operations, either for the sake of performance, compliance with constraints, or because functionally different operations are required (e.g., saturated computations). This can be solved by using functions implementing such computation in place of operators, for example, as follows:
486
507
 
487
508
  ```ruby
488
509
  system :sumprod_func do |typ,coefs|
@@ -499,7 +520,7 @@ end
499
520
  Where `add` and `mult` are functions implementing the required specific operations. HDLRuby functions are equivalent to the Verilog HDL ones. In our example, an addition that saturates at 1000 could be described as follows:
500
521
 
501
522
  ```ruby
502
- function :add do |x,y|
523
+ hdef :add do |x,y|
503
524
  inner :res
504
525
  seq do
505
526
  res <= x + y
@@ -517,7 +538,7 @@ With HDLRuby functions, the result of the last statement in the return value, in
517
538
  With functions, it is enough to change their content to obtain a new kind of circuit without changing the main code. This approach suffers from two drawbacks though: first, the level of saturation is hard coded in the function, and second, it would be preferable to be able to select the function to execute instead of modifying its code. For the first problem, a simple approach is to add an argument to the function given the saturation level. Such an add function would therefore be as follows:
518
539
 
519
540
  ```ruby
520
- function :add do |max, x, y|
541
+ hdef :add do |max, x, y|
521
542
  inner :res
522
543
  seq do
523
544
  res <= x + y
@@ -526,7 +547,7 @@ function :add do |max, x, y|
526
547
  end
527
548
  ```
528
549
 
529
- It would however be necessary to add this argument when invoking the function, e.g., `add(1000,sum,mult(...))`. While this argument is relevant for addition with saturation, it is not for the other kind of addition operations, and hence, the code of `sumprod` is not general-purpose any longer.
550
+ It would however be necessary to add this argument when invoking the function, e.g., `add(1000,sum,mult(...))`. While this argument is relevant for addition with saturation, it is not for the other kind of addition operations, and hence, the code of `sumprod` is no general purpose.
530
551
 
531
552
  HDLRuby provides two ways to address such issues. First, it is possible to pass code as an argument. In the case of `sumprod`, it would then be enough to add two arguments that perform the required addition and multiplication. The example is below:
532
553
 
@@ -608,12 +629,7 @@ sumprod(sat(16,1000),
608
629
  ```
609
630
 
610
631
 
611
- Lastly note, HDLRuby is also a language with supports reflection for
612
- all its constructs. For example, the system of an instance can be accessed
613
- using the `systemT` method, and this latter can be used to create
614
- other instances. For example, previously, `dff_single` was declared with
615
- an anonymous system (i.e., it cannot be accessed by name). This system
616
- can however be used as follows to generate another instance:
632
+ Lastly note, HDLRuby is also a language with supports reflection for all its constructs. For example, the system of an instance can be accessed using the `systemT` method, and this latter can be used to create other instances. For example, previously, `dff_single` was declared with an anonymous system (i.e., it cannot be accessed by name). This system can however be used as follows to generate another instance:
617
633
 
618
634
  ```ruby
619
635
  dff_single.systemT.instantiate(:dff_not_single)
@@ -622,12 +638,8 @@ dff_single.systemT.instantiate(:dff_not_single)
622
638
  In the above example, `dff_not_single` is declared to be an instance
623
639
  of the same system as `dff_single`.
624
640
 
625
- This reflection capability can also be used for instance, for accessing the
626
- data type of a signal (`sig.type`), but also the current basic block
627
- (`cur_block`), the current process (`cur_behavior`) and so on.
628
- The standard library of HDLRuby includes several hardware constructs
629
- like finite state machine descriptors and is mainly based on using these
630
- reflection features.
641
+ This reflection capability can also be used for instance, for accessing the data type of a signal (`sig.type`), but also the current basic block (`cur_block`), the current process (`cur_behavior`), and so on.
642
+ The standard library of HDLRuby includes several hardware constructs like finite state machine descriptors and is mainly based on using these reflection features.
631
643
 
632
644
 
633
645
 
@@ -672,8 +684,7 @@ system(:box) {}
672
684
 
673
685
  __Notes__:
674
686
 
675
- - Since this is Ruby code, the body can also be delimited by the `do` and `end`
676
- Ruby keywords (in which case the parentheses can be omitted) are as follows:
687
+ - 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) are as follows:
677
688
 
678
689
  ```ruby
679
690
  system :box does
@@ -703,8 +714,7 @@ Now, since `bit` is the default data type in HDLRuby, it can be omitted as follo
703
714
  input :clk
704
715
  ```
705
716
 
706
- The following is a more complete example: it is the code of a system describing an 8-bit data, 16-bit address memory whose interface includes a 1-bit input
707
- clock (`clk`), a 1-bit signal for selecting reading or writing access (`rwb`), a 16-bit address input (`addr`), and an 8-bit data inout — the remaining of the code describes the content and the behavior of the memory.
717
+ The following is a more complete example: it is the code of a system describing an 8-bit data, 16-bit address memory whose interface includes a 1-bit input clock (`clk`), a 1-bit signal for selecting reading or writing access (`rwb`), a 16-bit address input (`addr`), and an 8-bit data inout — the remaining of the code describes the content and the behavior of the memory.
708
718
 
709
719
  ```ruby
710
720
  system :mem8_16 do
@@ -799,8 +809,7 @@ It is also possible to connect multiple signals of an instance using the call op
799
809
  <instance name>.(<signal name0>: <target0>, ...)
800
810
  ```
801
811
 
802
- For example, the following code connects signals `clk` and `rst` of instance
803
- `mem8_16I` to signals `clk` and `rst` of the current system. As seen in this example, this method allows partial connection since the address and the data buses are not connected yet.
812
+ For example, the following code connects signals `clk` and `rst` of instance `mem8_16I` to signals `clk` and `rst` of the current system. As seen in this example, this method allows partial connection since the address and the data buses are not connected yet.
804
813
 
805
814
  ```ruby
806
815
  mem8_16I.(clk: clk, rst: rst)
@@ -1321,7 +1330,7 @@ end
1321
1330
  #### About loops
1322
1331
 
1323
1332
  HDLRuby does not include any hardware construct for describing loops. This might look poor compared to the other HDL, but it is important to understand
1324
- that the current synthesis tools do not really synthesize hardware from such loops but instead preprocess them (e.g., unroll them) to synthesizable loop less hardware. In HDLRuby, such features are natively supported by the Ruby loop constructs (`for`, `while`, and so on), but also by advanced Ruby constructs like the enumerators (`each`, `times`, and so on).
1333
+ that the current synthesis tools do not really synthesize hardware from such loops but instead preprocess them (e.g., unroll them) to synthesizable loopless hardware. In HDLRuby, such features are natively supported by the Ruby loop constructs (`for`, `while`, and so on), but also by advanced Ruby constructs like the enumerators (`each`, `times`, and so on).
1325
1334
 
1326
1335
  __Notes__:
1327
1336
 
@@ -1487,9 +1496,9 @@ _o144
1487
1496
 
1488
1497
  __Notes__:
1489
1498
 
1490
- - `_01100100` used to be considered as equivalent to `_b01100100`, however due to compatibility troubles with recent version of Ruby it is considered deprecated.
1499
+ - `_01100100` used to be considered equivalent to `_b01100100`, however, due to compatibility troubles with a recent version of Ruby it is considered deprecated.
1491
1500
 
1492
- - Ruby immediate values can also be used, their bit width is automatically adjusted to match the data type of the expression they are used in. Please notice this adjusting may change the value of the immediate, for example, the following code will set `sig` to 4 instead of 100:
1501
+ - Ruby immediate values can also be used, their bit width is automatically adjusted to match the data type of the expression they are used in. Please notice this adjustment may change the value of the immediate, for example, the following code will set `sig` to 4 instead of 100:
1493
1502
 
1494
1503
  ```ruby
1495
1504
  [3..0].inner :sig
@@ -1615,7 +1624,7 @@ __Notes__:
1615
1624
 
1616
1625
  - The operator precedence is the one of Ruby.
1617
1626
 
1618
- - Ruby does not allow to override the `&&`, the `||` and the `?:` operators so that they are not present in HDLRuby. Instead of the `?:` operator, HDLRuby provides the more general multiplex operator `mux`. However, HDLRuby does not provide any replacement for the `&&` and the `||` operators, please refer to section [Logic operators](#logic-and-shift-operators) for a justification about this issue.
1627
+ - Ruby does not allow to override the `&&`, the `||`, and the `?:` operators so they are not present in HDLRuby. Instead of the `?:` operator, HDLRuby provides the more general multiplex operator `mux`. However, HDLRuby does not provide any replacement for the `&&` and the `||` operators, please refer to section [Logic operators](#logic-and-shift-operators) for a justification for this issue.
1619
1628
 
1620
1629
  #### Assignment operators
1621
1630
 
@@ -1628,7 +1637,7 @@ __Note__:
1628
1637
  #### Arithmetic operators
1629
1638
  <a name="arithmetic"></a>
1630
1639
 
1631
- The arithmetic operators can only be used on vectors of `bit`, `unsigned` or `signed` values, `integer` or `float` values. These operators are `+`, `-`, `*`, `%` and the unary arithmetic operators are `-` and `+`. They have the same meaning as their Ruby equivalents.
1640
+ The arithmetic operators can only be used on vectors of `bit`, `unsigned` or `signed` values, `integer`, or `float` values. These operators are `+`, `-`, `*`, `%` and the unary arithmetic operators are `-` and `+`. They have the same meaning as their Ruby equivalents.
1632
1641
 
1633
1642
  #### Comparison operators
1634
1643
  <a name="comparison"></a>
@@ -1669,8 +1678,7 @@ For example, for rotating the left signal `sig` 3 times, the following code can
1669
1678
  sig.rl(3)
1670
1679
  ```
1671
1680
 
1672
- It is possible to perform other kinds of shifts or rotations using the selection and the concatenation operators. Please refer to section [Concatenation and
1673
- selection operators](#concatenation-and-selection-operators) for more details about these operators.
1681
+ It is possible to perform other kinds of shifts or rotations using the selection and concatenation operators. Please refer to section [Concatenation and selection operators](#concatenation-and-selection-operators) for more details about these operators.
1674
1682
 
1675
1683
 
1676
1684
  #### Conversion operators
@@ -1678,7 +1686,7 @@ selection operators](#concatenation-and-selection-operators) for more details ab
1678
1686
  The conversion operators are used to change the type of an expression.
1679
1687
  There are two kinds of such operators: the type pun that does not change the raw value of the expression and the type cast that changes the raw value.
1680
1688
 
1681
- The type puns include `to_bit`, `to_unsigned` and `to_signed` that convert expressions of any type type to vectors of respectively `bit`, `unsigned` and `signed` elements. For example, the following code converts an expression of hierarchical type to an 8-bit signed vector:
1689
+ The type puns include `to_bit`, `to_unsigned`, and `to_signed` that convert expressions of any type to vectors of respectively `bit`, `unsigned`, and `signed` elements. For example, the following code converts an expression of hierarchical type to an 8-bit signed vector:
1682
1690
 
1683
1691
  ```ruby
1684
1692
  [ up: signed[3..0], down: unsigned[3..0] ].inner :sig
@@ -1733,7 +1741,7 @@ Concatenation and selection are done using the `[]` operator as follows:
1733
1741
  sig2 <= [sig0, sig1]
1734
1742
  ```
1735
1743
 
1736
- - when this operator is applied to an expression of `bit`, `unsigned` or `signed` vector type while taking as argument a range, it selects the bits corresponding to this range. If only one bit is to select, the offset of this bit can be used instead. For example, the following code selects bits from 3 to 1 of `sig0` and bit 4 of `sig1`:
1744
+ - when this operator is applied to an expression of `bit`, `unsigned`, or `signed` vector type while taking as argument a range, it selects the bits corresponding to this range. If only one bit is to be selected, the offset of this bit can be used instead. For example, the following code selects bits from 3 to 1 of `sig0` and bit 4 of `sig1`:
1737
1745
 
1738
1746
  ```ruby
1739
1747
  [7..0].inner :sig0
@@ -1825,7 +1833,7 @@ __Multiplicative operators:__
1825
1833
  Like Verilog HDL, HDLRuby provides function constructs for reusing code. HDLRuby functions are declared as follows:
1826
1834
 
1827
1835
  ```ruby
1828
- function :<function name> do |<arguments>|
1836
+ hdef :<function name> do |<arguments>|
1829
1837
  <code>
1830
1838
  end
1831
1839
  ```
@@ -1903,7 +1911,7 @@ system :sys do
1903
1911
  end
1904
1912
  ```
1905
1913
 
1906
- As another example, following function will add an alternative code that generates a reset to a condition statement (`hif` or `hcase`):
1914
+ As another example, the following function will add an alternative code that generates a reset to a condition statement (`hif` or `hcase`):
1907
1915
 
1908
1916
  ```ruby
1909
1917
  def too_bad
@@ -1933,7 +1941,7 @@ Ruby functions can be compared to the macros of the C languages: they are more f
1933
1941
  ### Time values
1934
1942
  <a name="time_val"></a>
1935
1943
 
1936
- In HDLRuby, time values can be created using the time operators: `s` for seconds, `ms` for a millisecond, `us` for microseconds, `ns` for nanoseconds, `ps` for picoseconds. For example, the followings are all indicating one second:
1944
+ In HDLRuby, time values can be created using the time operators: `s` for seconds, `ms` for a millisecond, `us` for microseconds, `ns` for nanoseconds, `ps` for picoseconds. For example, the following are all indicating one second:
1937
1945
 
1938
1946
  ```ruby
1939
1947
  1.s
@@ -1947,7 +1955,7 @@ In HDLRuby, time values can be created using the time operators: `s` for seconds
1947
1955
  ### Time behaviors and time statements
1948
1956
  <a name="time_beh"></a>
1949
1957
 
1950
- Like the other HDL, HDLRuby provides specific statements that model the advance of time. These statements are not synthesizable and are used for simulating the environment of a hardware component. For sake of clarity, such statements are only allowed in explicitly non-synthesizable behavior declared using the `timed` keyword as follows.
1958
+ Like the other HDL, HDLRuby provides specific statements that model the advance of time. These statements are not synthesizable and are used for simulating the environment of a hardware component. For the sake of clarity, such statements are only allowed in explicitly non-synthesizable behavior declared using the `timed` keyword as follows.
1951
1959
 
1952
1960
  ```ruby
1953
1961
  timed do
@@ -2057,7 +2065,7 @@ typedef :<type name> do |<list of generic parameters>|
2057
2065
  end
2058
2066
  ```
2059
2067
 
2060
- For example, the following code describes a bit-vector type with generic number of bits `width`:
2068
+ For example, the following code describes a bit-vector type with a generic number of bits `width`:
2061
2069
 
2062
2070
  ```ruby
2063
2071
  type(:bitvec) { |width| bit[width] }
@@ -2087,7 +2095,7 @@ system :subsys, sys(1,2) do
2087
2095
  end
2088
2096
  ```
2089
2097
 
2090
- This way of inheriting can only be done with fully specialized systems though. For partially specialized systems, `include` must be used instead. For example, if `sys` specialized with only one value, can be used in generic `subsys_gen` as follows:
2098
+ This way of inheriting can only be done with fully specialized systems though. For partially specialized systems, `include` must be used instead. For example, if `sys` is specialized with only one value, can be used in generic `subsys_gen` as follows:
2091
2099
 
2092
2100
  ```ruby
2093
2101
  system :subsys_gen do |param|
@@ -2348,7 +2356,7 @@ end
2348
2356
  Please notice, that in the code above, the left value has been cast to a plain bit-vector to avoid the infinite recursive call of the `*` operator.
2349
2357
 
2350
2358
  Operators can also be overloaded with generic types. However, in such a case, the generic argument must also be present in the list of arguments of the overloaded operators.
2351
- For instance, let us consider the following fixed-point type of variable width (and whose decimal point is set at the half of its bit range):
2359
+ For instance, let us consider the following fixed-point type of variable width (and whose decimal point is set at half of its bit range):
2352
2360
 
2353
2361
  ```ruby
2354
2362
  typedef(:fixed) do |width|
@@ -2396,7 +2404,7 @@ Several enumerators are also provided for accessing the internals of the current
2396
2404
 
2397
2405
  ### Global signals
2398
2406
 
2399
- HDLRuby allows to declare global signals the same way system's signals are declared, but outside the scope of any system. After being declared, these signals are accessible directly from within any hardware construct.
2407
+ HDLRuby allows the declaration of global signals the same way system's signals are declared but outside the scope of any system. After being declared, these signals are accessible directly from within any hardware construct.
2400
2408
 
2401
2409
  To ease the design of standardized libraries, the following global signals are defined by default:
2402
2410
 
@@ -2415,9 +2423,9 @@ __Note__:
2415
2423
  ### Defining and executing Ruby methods within HDLRuby constructs
2416
2424
  <a name="method"></a>
2417
2425
 
2418
- Like with any Ruby program it is possible to define and execute methods anywhere in HDLRuby using the standard Ruby syntax. When defined, a method is attached to the enclosing HDLRuby construct. For instance, when defining a method when declaring a system, it can be used within this system only, while when defining a method outside any construct, it can be used everywhere in the HDLRuby description.
2426
+ Like with any Ruby program, it is possible to define and execute methods anywhere in HDLRuby using the standard Ruby syntax. When defined, a method is attached to the enclosing HDLRuby construct. For instance, when defining a method when declaring a system, it can be used within this system only, while when defining a method outside any construct, it can be used everywhere in the HDLRuby description.
2419
2427
 
2420
- A method can include HDLRuby code in which case the resulting hardware is appended to the current construct. For example, the following code adds a connection between `sig0` and `sig1` in system `sys0`, and transmission between `sig0` and `sig1` in the behavior of `sys1`.
2428
+ A method can include HDLRuby code in which case the resulting hardware is appended to the current construct. For example, the following code adds a connection between `sig0` and `sig1` in the system `sys0`, and transmission between `sig0` and `sig1` in the behavior of `sys1`.
2421
2429
 
2422
2430
  ```ruby
2423
2431
  def some_arrow
@@ -2486,7 +2494,7 @@ end
2486
2494
  ```
2487
2495
 
2488
2496
 
2489
- While requiring care, properly designed method can be very useful for clean code reuse. For example, the following method allows to start the execution of a block after a given number of cycles:
2497
+ While requiring caution, a properly designed method can be very useful for clean code reuse. For example, the following method allows to start the execution of a block after a given number of cycles:
2490
2498
 
2491
2499
  ```ruby
2492
2500
  def after(cycles,rst = $rst, &code)
@@ -2541,7 +2549,7 @@ When describing a system, it is possible to disconnect or completely undefine a
2541
2549
 
2542
2550
  ## Extending HDLRuby
2543
2551
 
2544
- Like any Ruby classes, the constructs of HDLRuby can be dynamically extended. If it is not recommended to change their internal structure, it is possible to add methods to them for an extension.
2552
+ Like any Ruby class, the constructs of HDLRuby can be dynamically extended. If it is not recommended to change their internal structure, it is possible to add methods to them for an extension.
2545
2553
 
2546
2554
  ### Extending HDLRuby constructs globally
2547
2555
 
@@ -2683,7 +2691,7 @@ After the libraries are loaded, the module `Std` must be included as follows:
2683
2691
  include HDLRuby::High::Std
2684
2692
  ```
2685
2693
 
2686
- > However, `hdrcc` does load the stable components of the standard library by default, so that you do not need to require nor include anything more to use them. In the current version, the stable components are the followings:
2694
+ > However, `hdrcc` loads the stable components of the standard library by default, so you do not need to require nor include anything more to use them. In the current version, the stable components are the followings:
2687
2695
 
2688
2696
  - `std/clocks.rb`
2689
2697
 
@@ -2719,7 +2727,7 @@ system :dff_slow do
2719
2727
  end
2720
2728
  ```
2721
2729
 
2722
- __Note__: this library does generate all the RTL code for the circuit handling the division of the frequency.
2730
+ __Note__: this library generates all the RTL code for the circuit handling the frequency division.
2723
2731
 
2724
2732
  ## Counters: `std/counters.rb`
2725
2733
  <a name="counters"></a>
@@ -2754,13 +2762,13 @@ A decoder can be declared anywhere in the code describing a system using the `de
2754
2762
  decoder(<signal>) <block>
2755
2763
  ```
2756
2764
 
2757
- Where `signal` is the signal to decode and `block` is a procedure block (i.e., Ruby `proc`) describing the decoding procedure. This procedure block can contain any code supported by a standard behavior, but also supports the `entry` statement that describes a pattern of a bit vector to decode and the corresponding action to perform when the signal matches this pattern. The syntax of the `entry` statement is the following:
2765
+ Where `signal` is the signal to decode and `block` is a procedure block (i.e., Ruby `proc`) describing the decoding procedure. This procedure block can contain any code supported by a standard behavior but also supports the `entry` statement that describes a pattern of a bit vector to decode and the corresponding action to perform when the signal matches this pattern. The syntax of the `entry` statement is the following:
2758
2766
 
2759
2767
  ```ruby
2760
2768
  entry(<pattern>) <block>
2761
2769
  ```
2762
2770
 
2763
- Where `pattern` is a string describing the pattern to match the entry, and `block` is a procedure block describing the actions (some HDLRuby code) that are performed when the entry matches. The string describing the pattern can include `0` and `1` characters for specifying a specific value for the corresponding bit, or any alphabetical character for specifying a field in the pattern. The fields in the pattern can then be used by name in the block describing the action. When a letter is used several times within a pattern, the corresponding bits are concatenated and are used as a signal multi-bit signal in the block.
2771
+ Where `pattern` is a string describing the pattern to match the entry, and `block` is a procedure block describing the actions (some HDLRuby code) that are performed when the entry matches. The string describing the pattern can include `0` and `1` characters for specifying a specific value for the corresponding bit, or any alphabetical character for specifying a field in the pattern. The fields in the pattern can then be used by name in the block describing the action. When a letter is used several times within a pattern, the corresponding bits are concatenated and used as a multi-bit signal in the block.
2764
2772
 
2765
2773
  For example, the following code describes a decoder for signal `ir` with two entries, the first one computing the sum of fields `x` and `y` and assigning the result to signal `s` and the second one computing the sum of fields `x` `y` and `z` and assigning the result to signal `s`:
2766
2774
 
@@ -2864,7 +2872,7 @@ That is to say, for a conditional `goto` for `st_1` the code should have been wr
2864
2872
  end
2865
2873
  ```
2866
2874
 
2867
- The use of `goto` makes the design of FSM shorter for a majority of the cases, be sometimes, a finer control is required. For that purpose, it is also possible to configure the FSM is `static` mode where the `next_state` statement that indicates implicitly the next state. Putting in static mode is done by passing `:static` as an argument when declaring the FSM. For example, the following FSM uses `next_state` to specify explicitly the next states depending on some condition signals `cond0` and `cond1`:
2875
+ The use of `goto` makes the design of FSM shorter for a majority of the cases, be sometimes, a finer control is required. For that purpose, it is also possible to configure the FSM in `static` mode where the `next_state` statement indicates implicitly the next state. Putting in static mode is done by passing `:static` as an argument when declaring the FSM. For example, the following FSM uses `next_state` to specify explicitly the next states depending on some condition signals `cond0` and `cond1`:
2868
2876
 
2869
2877
  ```ruby
2870
2878
  fsm(clk.posedge,rst,:static)
@@ -2894,9 +2902,11 @@ A sequence is a specific case of a `seq` block that includes the following softw
2894
2902
 
2895
2903
  - `step`: wait until the next event (given argument `event` of the sequencer).
2896
2904
 
2905
+ - `steps(<num>)`: perform `num` times `step` (`num` can be any expression).
2906
+
2897
2907
  - `sif(<condition>) <block>`: executes `block` if `condition` is met.
2898
2908
 
2899
- - `selsif(<condition>) <block>`: executes `block` if previous `sif` or `selsif` condition is not met and if current `condition` is met.
2909
+ - `selsif(<condition>) <block>`: executes `block` if the previous `sif` or `selsif` condition is not met and if the current `condition` is met.
2900
2910
 
2901
2911
  - `selse <block>`: executes `block` if the condition of the previous `sif` statement is not met.
2902
2912
 
@@ -3026,7 +3036,7 @@ It is also possible to define a custom enumerator using the following command:
3026
3036
  <enum> = senumerator(<typ>,<size>) <block>
3027
3037
  ```
3028
3038
 
3029
- Where `enum` is a Ruby variable referring to the enumerator, `typ` is the data type and `size` is the number of the elements to enumerate and `block` is the block that implements the access to an element by index. For example, an enumerator on a memory could be defined as follows:
3039
+ Where `enum` is a Ruby variable referring to the enumerator, `typ` is the data type and `size` is the number of the elements to enumerate, and `block` is the block that implements the access to an element by index. For example, an enumerator on a memory could be defined as follows:
3030
3040
 
3031
3041
  ```ruby
3032
3042
  bit[8][-8].inner mem: [ _h01, _h02, _h03, _h04, _h30, _h30, _h30, _h30 ]
@@ -3042,7 +3052,7 @@ Where `enum` is a Ruby variable referring to the enumerator, `typ` is the data t
3042
3052
  end
3043
3053
  ```
3044
3054
 
3045
- In the code above, `mem_enum` is the variable referring to the resulting enumerator built for accessing memory `mem`. For the access, it is assumed that one cycle must be waited after the address is sets, and therefore a `step` command is added in the access procedure before `data` can be returned.
3055
+ In the code above, `mem_enum` is the variable referring to the resulting enumerator built for accessing memory `mem`. For the access, it is assumed that one cycle must be waited for after the address is set, and therefore a `step` command is added in the access procedure before `data` can be returned.
3046
3056
 
3047
3057
  With this basis, several algorithms have been implemented using enumerators and are usable for all the enumerable objects. All these algorithms are HW implantation of the Ruby Enumerable methods. They are accessible using the corresponding ruby method prefixed by character `s`. For example, the HW implementation of the ruby `all?` method is generated by the `sall?` method. In details:
3048
3058
 
@@ -3120,12 +3130,12 @@ With this basis, several algorithms have been implemented using enumerators and
3120
3130
 
3121
3131
 
3122
3132
 
3123
- ### Shared signals, arbiters and monitors: `std/sequencer_sync.rb`
3133
+ ### Shared signals, arbiters, and monitors: `std/sequencer_sync.rb`
3124
3134
  <a name="shared"></a>
3125
3135
 
3126
3136
  #### Shared signals
3127
3137
 
3128
- Like any other processes, It is not possible for several sequencers to write to the same signal. This is because there would be race competition that may destroy physically the device if such operations where authorized. In standard RTL design, this limitation is overcome by implementing three-state buses, multiplexers and arbiters. However, HDLRuby sequencers supports another kind of signals called the *shared signals* that abstract the implementation details for avoiding race competition.
3138
+ Like any other process, It is not possible for several sequencers to write to the same signal. This is because there would be race competition that may destroy physically the device if such operations were authorized. In standard RTL design, this limitation is overcome by implementing three-state buses, multiplexers, and arbiters. However, HDLRuby sequencers support another kind of signal called the *shared signals* that abstract the implementation details for avoiding race competition.
3129
3139
 
3130
3140
  The shared signals are declared like the other kind of signals from their type. The syntax is the following:
3131
3141
 
@@ -3139,14 +3149,14 @@ They can also have an initial (and default) value when declared as follows:
3139
3149
  <type>.shared <list of names with initialization>
3140
3150
  ```
3141
3151
 
3142
- For example the following code declare two 8-bit shared signals `x` and `y` and two signed 16-bit shared signals initialized to 0 `u` and `v`:
3152
+ For example, the following code declares two 8-bit shared signals `x` and `y` and two signed 16-bit shared signals initialized to 0 `u` and `v`:
3143
3153
 
3144
3154
  ```ruby
3145
3155
  [8].shared :x, :y
3146
3156
  signed[8].shared u: 0, v: 0
3147
3157
  ```
3148
3158
 
3149
- A shared signals can then be read and written to by any sequencer from anywhere in the subsequent code of the current scope. However, they cannot be written to outside a sequencer. For example, the following code is valid:
3159
+ A shared signal can then be read and written to by any sequencer from anywhere in the subsequent code of the current scope. However, they cannot be written to outside a sequencer. For example, the following code is valid:
3150
3160
 
3151
3161
  ```ruby
3152
3162
  input :clk, :start
@@ -3173,21 +3183,21 @@ But the following code is not valid:
3173
3183
  par(clk.posedge) { w <= w + 1 }
3174
3184
  ```
3175
3185
 
3176
- By default, a shared signal acknowledge writing from the first sequencer that access it in order of declaration, the others are ignored. In the first example given above, that means for signal `x` the value is always the one written by the first sequencer, i.e., from 0 to 9 changing once per clock cycle. However, the value of signal `y` is set by the second sequencer since it is this one only that writes to this signal.
3186
+ By default, a shared signal acknowledges writing from the first sequencer that accesses it in order of declaration, the others are ignored. In the first example given above, that means for signal `x` the value is always the one written by the first sequencer, i.e., from 0 to 9 changing once per clock cycle. However, the value of signal `y` is set by the second sequencer since it is this one only that writes to this signal.
3177
3187
 
3178
- This default behavior of shared signal avoids race competition, but is not very useful in practice. For a better control, it is possible to select which sequencer is to be acknowledged for writing. This is done by setting the number of the sequencer which can write the signal that controls the sharing accessed as follows:
3188
+ This default behavior of shared signal avoids race competition but is not very useful in practice. For better control, it is possible to select which sequencer is to be acknowledged for writing. This is done by setting the number of the sequencer which can write the signal that controls the sharing accessed as follows:
3179
3189
 
3180
3190
  ```ruby
3181
3191
  <shared signal>.select
3182
3192
  ```
3183
3193
 
3184
- The select value starts from 0 for the first sequencer writing to the shared signal, and is increased by one per writing sequencer. For example, in the first example, for selecting the second sequencer for writing to `x` the follow code can be added after this signal is declared:
3194
+ The select value starts from 0 for the first sequencer writing to the shared signal, and is increased by one per writing sequencer. For example, in the first example, for selecting the second sequencer for writing to `x` the following code can be added after this signal is declared:
3185
3195
 
3186
3196
  ```ruby
3187
3197
  x.select <= 1
3188
3198
  ```
3189
3199
 
3190
- This value can be changed at runtime too. For example, instead of setting the second sequencer, it is possible to switch sequencer every clock cycle as follows:
3200
+ This value can be changed at runtime too. For example, instead of setting the second sequencer, it is possible to switch the sequencer every clock cycle as follows:
3191
3201
 
3192
3202
  ```ruby
3193
3203
  par(clk.posedge) { x.select <= x.select + 1 }
@@ -3198,15 +3208,15 @@ __Note__: this select sub signal is a standard RTL signal that has the same prop
3198
3208
 
3199
3209
  #### Arbiters
3200
3210
 
3201
- Usually, it is not the signals that we want to share, but the resources they drives. For example, in a CPU, it is an ALU that is shared as a whole rather than each of its input separately. In order to support such cases and ease the handling of shared signals, the library also provides the *arbiter* components. This component is instantiated like a standard module as follows, where `name` is the name of the arbiter instance:
3211
+ Usually, it is not the signals that we want to share, but the resources they drive. For example, in a CPU, it is an ALU that is shared as a whole rather than each of its inputs separately. In order to support such cases and ease the handling of shared signals, the library also provides the *arbiter* components. This component is instantiated like a standard module as follows, where `name` is the name of the arbiter instance:
3202
3212
 
3203
3213
  ```ruby
3204
3214
  arbiter(:<name>).(<list of shared signal>)
3205
3215
  ```
3206
3216
 
3207
- When instantiated, an arbiter will take control of the select sub signals of the shared signals (hence, you cannot control the selection yourself for them any longer). In returns, it provides the possibility of requiring or releasing access to the shared signals. Requiring access is done by sending the value 1 to the arbiter, and releasing is done by sending the value 0. If a sequencer writes to a shared signal under arbitration without requiring access first, the write will simply be ignored.
3217
+ When instantiated, an arbiter will take control of the select sub-signals of the shared signals (hence, you cannot control the selection yourself for them any longer). In return, it provides the possibility of requiring or releasing access to the shared signals. Requiring access is done by sending the value 1 to the arbiter, and releasing is done by sending the value 0. If a sequencer writes to a shared signal under arbitration without requiring access first, the write will simply be ignored.
3208
3218
 
3209
- The following is an example of arbiter that controls access to shared signals `x` and `y` and two sequencers acquiring and releasing accesses to them:
3219
+ The following is an example of an arbiter that controls access to shared signals `x` and `y` and two sequencers acquiring and releasing accesses to them:
3210
3220
 
3211
3221
  ```ruby
3212
3222
  input :clk, :start
@@ -3236,20 +3246,20 @@ end
3236
3246
 
3237
3247
  In the example, both sequencers require access to signals `x` and `y` before accessing them and then releasing the access.
3238
3248
 
3239
- Requiring access does not guaranties that the access will be granted by the arbiter though. In the access is not granted, the write access will be ignored.
3240
- The default access granting policy of an arbiter is the priority in order of sequencer declaration. I.e., if several sequencer are requiring at the same time, then the one declared the earliest in the code gains write access. For example, with the code given about, the first sequencer have write access to `x` and `y`, and since after five write cycles it releases access, the second sequencer can then write to these signals. However, not obtaining write access does not block the execution of the sequencer, simply, its write access to the corresponding shared signals is simple ignored. In the example, the second sequencer will do its first five loop cycles without any effect, and have only its five last ones that change the shared signals. To avoid such a behavior, it is possible to check if the write access is granted using arbiter sub signal `acquired`: if this signal is one in current sequencer, that means the access is granted, otherwise its is 0. For example the following will increase signal `x` only if write access is granted:
3249
+ Requiring access does not guarantee that the access will be granted by the arbiter though. In the access is not granted, the write access will be ignored.
3250
+ The default access granting policy of an arbiter is the priority in the order of sequencer declaration. I.e., if several sequencers are requiring one at the same time, then the one declared the earliest in the code gains write access. For example, with the code given above, the first sequencer has to write access to `x` and `y`, and since after five write cycles it releases access, the second sequencer can then write to these signals. However, not obtaining write access does not block the execution of the sequencer, simply, its write access to the corresponding shared signals is simply ignored. In the example, the second sequencer will do its first five loop cycles without any effect and have only its five last ones that change the shared signals. To avoid such a behavior, it is possible to check if the write access is granted using arbiter sub signal `acquired`: if this signal is one in the current sequencer, that means the access is granted, otherwise it is 0. For example the following will increase signal `x` only if write access is granted:
3241
3251
 
3242
3252
  ```ruby
3243
3253
  hif(ctrl_xy.acquired) { x <= x + 1 }
3244
3254
  ```
3245
3255
 
3246
- The policy of an arbiter can be changed using command policy. You can either provide a new priority table, containing the number of the sequencers in order of priority (the first one having higher priority. The number of a sequencer is assign in order of declaration provided it uses the arbiter. For example, in the previous code, the second sequencer can be given higher priority by adding the following code after having declared the arbiter:
3256
+ The policy of an arbiter can be changed using command policy. You can either provide a new priority table, containing the number of the sequencers in order of priority (the first one having higher priority. The number of a sequencer is assigned in order of declaration provided it uses the arbiter. For example, in the previous code, the second sequencer can be given higher priority by adding the following code after having declared the arbiter:
3247
3257
 
3248
3258
  ```ruby
3249
3259
  ctrl_xy.policy([1,0])
3250
3260
  ```
3251
3261
 
3252
- It is also possible to set a more complex policy by providing to the policy method a block of code whose argument is a vector indicating which sequencer is currently requiring write access to the shared signals and whose result will be the number of the sequencer to grant the access. This code will be executing each time an write access is actually performed. For example, in the previous code, a policy switch priorities at each access can be implemented as follows:
3262
+ It is also possible to set a more complex policy by providing to the policy method a block of code whose argument is a vector indicating which sequencer is currently requiring write access to the shared signals and whose result will be the number of the sequencer to grant the access. This code will be executed each time write access is actually performed. For example, in the previous code, a policy switch priorities at each access can be implemented as follows:
3253
3263
 
3254
3264
  ```ruby
3255
3265
  inner priority_xy: 0
@@ -3272,26 +3282,26 @@ ctrl_xy.policy do |acq|
3272
3282
  end
3273
3283
  ```
3274
3284
 
3275
- As seen in the code above, each bit of the `acq` vector is one when the corresponding sequencer required an access or 0 otherwise, bit 0 corresponding to sequencer 0, bit 1 to sequencer 1 and so one.
3285
+ As seen in the code above, each bit of the `acq` vector is one when the corresponding sequencer required an access or 0 otherwise, bit 0 corresponds to sequencer 0, bit 1 to sequencer 1 and so on.
3276
3286
 
3277
3287
 
3278
3288
  #### Monitors
3279
3289
 
3280
- Arbiters a especially useful when we can ensure that the sequencers accessing the same resource do not overlap or when the do not need to synchronize with each other. If such synchronizations are required, instead of arbiters, it is possible to use the *monitor* components.
3290
+ Arbiters are especially useful when we can ensure that the sequencers accessing the same resource do not overlap or when they do not need to synchronize with each other. If such synchronizations are required, instead of arbiters, it is possible to use the *monitor* components.
3281
3291
 
3282
- The monitor component are instantiated like the arbiters as follows:
3292
+ The monitor component is instantiated like the arbiters as follows:
3283
3293
 
3284
3294
  ```ruby
3285
3295
  monitor(:<name>).(<list of shared signals>)
3286
3296
  ```
3287
3297
 
3288
- Monitors are used exactly the same ways as arbiters (including the write access granting policies), but blocks the execution of the sequencers that require a write access until the access is granted. If we take the example of code with two sequencers given as illustration of arbiter usage, replacing the arbiter by a monitor as follows will lock the second sequencer until it can write to shared variables `x` and `y` ensuring that all its loop cycles have the specified result:
3298
+ Monitors are used exactly the same ways as arbiters (including the write access granting policies) but block the execution of the sequencers that require write access until the access is granted. If we take the example of code with two sequencers given as an illustration of arbiter usage, replacing the arbiter with a monitor as follows will lock the second sequencer until it can write to shared variables `x` and `y` ensuring that all its loop cycles have the specified result:
3289
3299
 
3290
3300
  ```ruby
3291
3301
  monitor(:ctrl_xy).(x,y)
3292
3302
  ```
3293
3303
 
3294
- Since monitors locks processes, it automatically insert a step, hence to avoid confusion, aquiring access to a monitor is done by using method `lock` instead of assigning 1, and releasing is done by using method `unlock` instead of assigning 0. Hence, when using a monitor, the previous arbiter-based code should be rewriten as follows:
3304
+ Since monitors lock processes, they automatically insert a step. Hence to avoid confusion, acquiring access to a monitor is done by using the method `lock` instead of assigning 1, and releasing is done by using the method `unlock` instead of assigning 0. Hence, when using a monitor, the previous arbiter-based code should be rewritten as follows:
3295
3305
 
3296
3306
  ```ruby
3297
3307
  input :clk, :start
@@ -3319,6 +3329,66 @@ sequencer(clk.posedge,start) do
3319
3329
  end
3320
3330
  ```
3321
3331
 
3332
+ ### Sequencer-specific function: `std/sequencer_func.rb`
3333
+
3334
+ HDLRuby function defined by `hdef` can be used in sequencer like any other HDLRuyby construct. But like the process constructs `hif` and so on, the body of these functions cannot include any sequencer-specific constructs.
3335
+
3336
+ However, it is possible to define functions that do support the sequencer constructs using `sdef` instead of `hdef` as follows:
3337
+
3338
+ ```ruby
3339
+ sdef :<function name> do |<arguments>|
3340
+ <sequencer code>
3341
+ end
3342
+ ```
3343
+
3344
+ Such functions can be defined anywhere in a HDLRuby description, but can only be called within a sequencer.
3345
+
3346
+ As additional features, since the `sdef` function is made to support the software-like code description of the sequencers, it also supports recursion. For example, a function describing a factorial can be described as follows:
3347
+
3348
+ ```ruby
3349
+ sdef(:fact) do |n|
3350
+ sif(n > 1) { sreturn(n*fact(n-1)) }
3351
+ selse { sreturn(1) }
3352
+ end
3353
+ ```
3354
+
3355
+ As seen in the code above, a new construct `sreturn` can be used for returning a value from anywhere inside the function.
3356
+
3357
+ When a recursion is present, HDLRuby automatically defines a stack for storing the return state and the arguments of the function. The size of the stack is heuristically set to the maximum number of bits of the arguments of the function when it is recursively called. For example, for the previous `fact` function, if when called, `n` is 16-bit, the stack will be able to hold 16 recursions. If this heuristic does not match the circuit's needs, the size can be forced as a second argument when defining the function. For example, the following code set the size to 32 whatever the arguments are:
3358
+
3359
+ ```ruby
3360
+ sdef(:fact,32) do |n|
3361
+ sif(n > 1) { sreturn(n*fact(n-1)) }
3362
+ selse { sreturn(1) }
3363
+ end
3364
+ ```
3365
+
3366
+ __Notes__:
3367
+
3368
+ * A call to such a function and a return take respectively one and two cycles of the sequencer.
3369
+
3370
+ * For now, there is no tail call optimization.
3371
+
3372
+ * In case of stack overflow (the number of recursive calls exceeds the size of the sack), the current recursion is terminated and the sequencer goes on its execution. It is possible to add a process that is to be executed in such a case as follows:
3373
+
3374
+ ```ruby
3375
+ sdef(:<name>,<depth>, proc <block>) do
3376
+ <function code>
3377
+ end
3378
+ ```
3379
+
3380
+ Where `block` contains the code of the stack overflow process. For now, this process cannot contain a sequencer construct. For example, the previous factorial function can be modified as follows so that signal `stack_overflow` is set to 1 in case of overflow:
3381
+
3382
+ ```ruby
3383
+ sdef(:fact,32, proc { stack_overflow <= 1 }) do |n|
3384
+ sif(n > 1) { sreturn(n*fact(n-1)) }
3385
+ selse { sreturn(1) }
3386
+ end
3387
+ ```
3388
+
3389
+ With the code above, the only restriction is that the signal `stack_overflow` is declared before the function `fact` is called.
3390
+
3391
+
3322
3392
  ## Fixed-point (fixpoint): `std/fixpoint.rb`
3323
3393
  <a name="fixpoint"></a>
3324
3394