HDLRuby 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c90429c20c142c33c21c15d9891e11715b0b1df9c19c7a2d78f72e5fec961fa3
4
- data.tar.gz: b7b2dd40436619a4e46103f9432e0dd4c996da9382be7f6a60c7cbf02fb2adeb
3
+ metadata.gz: 6f491222adce0600f9d4ba58e748d4a72fd913adb50952fff71e5e67937f6b54
4
+ data.tar.gz: ffdb34990f8dabcb0e38c3a7189e7f99c07c351cd86de6411f7eaa64314147f9
5
5
  SHA512:
6
- metadata.gz: 50b372f8a40d6434607ac5334e4049d2282213c95bcc847d831ec0dd305ea847438312ea64e1cd3950ca5241d98a2bea90c0f678be09e6a83ed210bda5f38a3d
7
- data.tar.gz: 15588d7eb520f6b016003e682e94729dab8a530bb3e63d55a22833a2d1d3ce4abe8393f975ba0f408f4f3d178fe581a26e7762184986733fc77ea638b9c89643
6
+ metadata.gz: 854a95c8b73d27c9673997cb138ebdceba87546bbd6d585d201110a9b8f0ae0be67f2c197a13a6e864c235fefb4a59ca99a4dc6f7311758becea639aadd3c0e6
7
+ data.tar.gz: 60d260809614010f31e484c85e907b575518670770e4069da9216ba00e3b0a8502ef173dd260cf773e47d5ebd20d343ef00b815a840efbf7346c86b7b5b8c0cd
data/README.md CHANGED
@@ -11,6 +11,18 @@ 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.1.0:
15
+
16
+ * [Functions for sequencers](#sequencer-specific-function-std-sequencer_func-rb) supporting recursion;
17
+
18
+ * The `function` keyword was replaced with `hdef` for better consistency with the new functions for sequencers;
19
+
20
+ * The `steps` command was added for waiting several steps in a sequencer;
21
+
22
+ * Verilog HDL code generation was improved to preserve as much as possible the original names of the signals;
23
+
24
+ * Several bug fixes for the sequencers.
25
+
14
26
  For HDLRuby version 3.0.0:
15
27
 
16
28
  * This section;
@@ -39,7 +51,7 @@ git clone HDLRuby
39
51
  __Warning__:
40
52
 
41
53
  - 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.
54
+ - It is highly recommended to have both basic knowledges of the Ruby language and hardware description languages before using HDLRuby.
43
55
 
44
56
 
45
57
  # Compiling HDLRuby descriptions
@@ -72,7 +84,7 @@ Where:
72
84
  | `-S, --sim` | Perform the simulation with the default engine |
73
85
  | `--csim` | Perform the simulation with the standalone engine |
74
86
  | `--rsim` | Perform the simulation with the Ruby engine |
75
- | `--rcsim` | Perform the simulation with the Hybris engine |
87
+ | `--rcsim` | Perform the simulation with the Hybrid engine |
76
88
  | `--vcd` | Make the simulator generate a VCD file |
77
89
  | `-d, --directory` | Specify the base directory for loading the HDLRuby files |
78
90
  | `-D, --debug` | Set the HDLRuby debug mode |
@@ -92,7 +104,7 @@ __Notes__:
92
104
  hdrcc --get-samples
93
105
  ```
94
106
 
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).
107
+ 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
108
 
97
109
 
98
110
  __Examples__:
@@ -103,7 +115,7 @@ __Examples__:
103
115
  hdrcc --yaml --top adder adder.rb adder
104
116
  ```
105
117
 
106
- * Compile `adder.rb` input file and generate a low-level Verilog HDL description into directory `adder`:
118
+ * Compile `adder.rb` input file and generate a low-level Verilog HDL description into the directory `adder`:
107
119
 
108
120
  ```bash
109
121
  hdrcc -v adder.rb adder
@@ -121,7 +133,7 @@ hdrcc -V -t adder --param 16 adder_gen.rb adder
121
133
  hdrcc -y -t multer -p 16,16,32 multer_gen.rb multer
122
134
  ```
123
135
 
124
- * Simulate the circuit described in file `counter_bench.rb` using the default simulation engine and putting the simulator's files in directory `counter`:
136
+ * 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
137
 
126
138
  ```bash
127
139
  hdrcc -S counter_bench.rb counter
@@ -257,7 +269,7 @@ system :counter2 do
257
269
  end
258
270
  ```
259
271
 
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.
272
+ 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
273
 
262
274
  While a circuit can be generated from the code given above, a benchmark must
263
275
  be provided to test it. Such a benchmark is described by constructs called
@@ -323,8 +335,7 @@ instance :dff_single do
323
335
  end
324
336
  ```
325
337
 
326
- In the example above, `dff_single` is an instance describing, again, a
327
- D-FF, but whose system is anonymous.
338
+ In the example above, `dff_single` is an instance describing, again, a D-FF, but whose system is anonymous.
328
339
 
329
340
  Furthermore, generic parameters can be used for anything in HDLRuby.
330
341
  For instance, the following code describes an 8-bit register without any parameterization:
@@ -482,7 +493,7 @@ sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit
482
493
 
483
494
  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
495
 
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:
496
+ 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
497
 
487
498
  ```ruby
488
499
  system :sumprod_func do |typ,coefs|
@@ -499,7 +510,7 @@ end
499
510
  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
511
 
501
512
  ```ruby
502
- function :add do |x,y|
513
+ hdef :add do |x,y|
503
514
  inner :res
504
515
  seq do
505
516
  res <= x + y
@@ -517,7 +528,7 @@ With HDLRuby functions, the result of the last statement in the return value, in
517
528
  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
529
 
519
530
  ```ruby
520
- function :add do |max, x, y|
531
+ hdef :add do |max, x, y|
521
532
  inner :res
522
533
  seq do
523
534
  res <= x + y
@@ -526,7 +537,7 @@ function :add do |max, x, y|
526
537
  end
527
538
  ```
528
539
 
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.
540
+ 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
541
 
531
542
  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
543
 
@@ -608,12 +619,7 @@ sumprod(sat(16,1000),
608
619
  ```
609
620
 
610
621
 
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:
622
+ 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
623
 
618
624
  ```ruby
619
625
  dff_single.systemT.instantiate(:dff_not_single)
@@ -622,12 +628,8 @@ dff_single.systemT.instantiate(:dff_not_single)
622
628
  In the above example, `dff_not_single` is declared to be an instance
623
629
  of the same system as `dff_single`.
624
630
 
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.
631
+ 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.
632
+ The standard library of HDLRuby includes several hardware constructs like finite state machine descriptors and is mainly based on using these reflection features.
631
633
 
632
634
 
633
635
 
@@ -672,8 +674,7 @@ system(:box) {}
672
674
 
673
675
  __Notes__:
674
676
 
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:
677
+ - 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
678
 
678
679
  ```ruby
679
680
  system :box does
@@ -703,8 +704,7 @@ Now, since `bit` is the default data type in HDLRuby, it can be omitted as follo
703
704
  input :clk
704
705
  ```
705
706
 
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.
707
+ 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
708
 
709
709
  ```ruby
710
710
  system :mem8_16 do
@@ -799,8 +799,7 @@ It is also possible to connect multiple signals of an instance using the call op
799
799
  <instance name>.(<signal name0>: <target0>, ...)
800
800
  ```
801
801
 
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.
802
+ 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
803
 
805
804
  ```ruby
806
805
  mem8_16I.(clk: clk, rst: rst)
@@ -1321,7 +1320,7 @@ end
1321
1320
  #### About loops
1322
1321
 
1323
1322
  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).
1323
+ 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
1324
 
1326
1325
  __Notes__:
1327
1326
 
@@ -1487,9 +1486,9 @@ _o144
1487
1486
 
1488
1487
  __Notes__:
1489
1488
 
1490
- - `_01100100` used to be considered as equivalent to `_b01100100`, however due to compatibility troubles with recent version of Ruby it is considered deprecated.
1489
+ - `_01100100` used to be considered equivalent to `_b01100100`, however, due to compatibility troubles with a recent version of Ruby it is considered deprecated.
1491
1490
 
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:
1491
+ - 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
1492
 
1494
1493
  ```ruby
1495
1494
  [3..0].inner :sig
@@ -1615,7 +1614,7 @@ __Notes__:
1615
1614
 
1616
1615
  - The operator precedence is the one of Ruby.
1617
1616
 
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.
1617
+ - 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
1618
 
1620
1619
  #### Assignment operators
1621
1620
 
@@ -1628,7 +1627,7 @@ __Note__:
1628
1627
  #### Arithmetic operators
1629
1628
  <a name="arithmetic"></a>
1630
1629
 
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.
1630
+ 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
1631
 
1633
1632
  #### Comparison operators
1634
1633
  <a name="comparison"></a>
@@ -1669,8 +1668,7 @@ For example, for rotating the left signal `sig` 3 times, the following code can
1669
1668
  sig.rl(3)
1670
1669
  ```
1671
1670
 
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.
1671
+ 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
1672
 
1675
1673
 
1676
1674
  #### Conversion operators
@@ -1678,7 +1676,7 @@ selection operators](#concatenation-and-selection-operators) for more details ab
1678
1676
  The conversion operators are used to change the type of an expression.
1679
1677
  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
1678
 
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:
1679
+ 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
1680
 
1683
1681
  ```ruby
1684
1682
  [ up: signed[3..0], down: unsigned[3..0] ].inner :sig
@@ -1733,7 +1731,7 @@ Concatenation and selection are done using the `[]` operator as follows:
1733
1731
  sig2 <= [sig0, sig1]
1734
1732
  ```
1735
1733
 
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`:
1734
+ - 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
1735
 
1738
1736
  ```ruby
1739
1737
  [7..0].inner :sig0
@@ -1825,7 +1823,7 @@ __Multiplicative operators:__
1825
1823
  Like Verilog HDL, HDLRuby provides function constructs for reusing code. HDLRuby functions are declared as follows:
1826
1824
 
1827
1825
  ```ruby
1828
- function :<function name> do |<arguments>|
1826
+ hdef :<function name> do |<arguments>|
1829
1827
  <code>
1830
1828
  end
1831
1829
  ```
@@ -1903,7 +1901,7 @@ system :sys do
1903
1901
  end
1904
1902
  ```
1905
1903
 
1906
- As another example, following function will add an alternative code that generates a reset to a condition statement (`hif` or `hcase`):
1904
+ As another example, the following function will add an alternative code that generates a reset to a condition statement (`hif` or `hcase`):
1907
1905
 
1908
1906
  ```ruby
1909
1907
  def too_bad
@@ -1933,7 +1931,7 @@ Ruby functions can be compared to the macros of the C languages: they are more f
1933
1931
  ### Time values
1934
1932
  <a name="time_val"></a>
1935
1933
 
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:
1934
+ 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
1935
 
1938
1936
  ```ruby
1939
1937
  1.s
@@ -1947,7 +1945,7 @@ In HDLRuby, time values can be created using the time operators: `s` for seconds
1947
1945
  ### Time behaviors and time statements
1948
1946
  <a name="time_beh"></a>
1949
1947
 
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.
1948
+ 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
1949
 
1952
1950
  ```ruby
1953
1951
  timed do
@@ -2057,7 +2055,7 @@ typedef :<type name> do |<list of generic parameters>|
2057
2055
  end
2058
2056
  ```
2059
2057
 
2060
- For example, the following code describes a bit-vector type with generic number of bits `width`:
2058
+ For example, the following code describes a bit-vector type with a generic number of bits `width`:
2061
2059
 
2062
2060
  ```ruby
2063
2061
  type(:bitvec) { |width| bit[width] }
@@ -2087,7 +2085,7 @@ system :subsys, sys(1,2) do
2087
2085
  end
2088
2086
  ```
2089
2087
 
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:
2088
+ 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
2089
 
2092
2090
  ```ruby
2093
2091
  system :subsys_gen do |param|
@@ -2348,7 +2346,7 @@ end
2348
2346
  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
2347
 
2350
2348
  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):
2349
+ 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
2350
 
2353
2351
  ```ruby
2354
2352
  typedef(:fixed) do |width|
@@ -2396,7 +2394,7 @@ Several enumerators are also provided for accessing the internals of the current
2396
2394
 
2397
2395
  ### Global signals
2398
2396
 
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.
2397
+ 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
2398
 
2401
2399
  To ease the design of standardized libraries, the following global signals are defined by default:
2402
2400
 
@@ -2415,9 +2413,9 @@ __Note__:
2415
2413
  ### Defining and executing Ruby methods within HDLRuby constructs
2416
2414
  <a name="method"></a>
2417
2415
 
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.
2416
+ 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
2417
 
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`.
2418
+ 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
2419
 
2422
2420
  ```ruby
2423
2421
  def some_arrow
@@ -2486,7 +2484,7 @@ end
2486
2484
  ```
2487
2485
 
2488
2486
 
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:
2487
+ 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
2488
 
2491
2489
  ```ruby
2492
2490
  def after(cycles,rst = $rst, &code)
@@ -2541,7 +2539,7 @@ When describing a system, it is possible to disconnect or completely undefine a
2541
2539
 
2542
2540
  ## Extending HDLRuby
2543
2541
 
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.
2542
+ 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
2543
 
2546
2544
  ### Extending HDLRuby constructs globally
2547
2545
 
@@ -2683,7 +2681,7 @@ After the libraries are loaded, the module `Std` must be included as follows:
2683
2681
  include HDLRuby::High::Std
2684
2682
  ```
2685
2683
 
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:
2684
+ > 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
2685
 
2688
2686
  - `std/clocks.rb`
2689
2687
 
@@ -2719,7 +2717,7 @@ system :dff_slow do
2719
2717
  end
2720
2718
  ```
2721
2719
 
2722
- __Note__: this library does generate all the RTL code for the circuit handling the division of the frequency.
2720
+ __Note__: this library generates all the RTL code for the circuit handling the frequency division.
2723
2721
 
2724
2722
  ## Counters: `std/counters.rb`
2725
2723
  <a name="counters"></a>
@@ -2754,13 +2752,13 @@ A decoder can be declared anywhere in the code describing a system using the `de
2754
2752
  decoder(<signal>) <block>
2755
2753
  ```
2756
2754
 
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:
2755
+ 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
2756
 
2759
2757
  ```ruby
2760
2758
  entry(<pattern>) <block>
2761
2759
  ```
2762
2760
 
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.
2761
+ 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
2762
 
2765
2763
  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
2764
 
@@ -2864,7 +2862,7 @@ That is to say, for a conditional `goto` for `st_1` the code should have been wr
2864
2862
  end
2865
2863
  ```
2866
2864
 
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`:
2865
+ 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
2866
 
2869
2867
  ```ruby
2870
2868
  fsm(clk.posedge,rst,:static)
@@ -2894,9 +2892,11 @@ A sequence is a specific case of a `seq` block that includes the following softw
2894
2892
 
2895
2893
  - `step`: wait until the next event (given argument `event` of the sequencer).
2896
2894
 
2895
+ - `steps(<num>)`: perform `num` times `step` (`num` can be any expression).
2896
+
2897
2897
  - `sif(<condition>) <block>`: executes `block` if `condition` is met.
2898
2898
 
2899
- - `selsif(<condition>) <block>`: executes `block` if previous `sif` or `selsif` condition is not met and if current `condition` is met.
2899
+ - `selsif(<condition>) <block>`: executes `block` if the previous `sif` or `selsif` condition is not met and if the current `condition` is met.
2900
2900
 
2901
2901
  - `selse <block>`: executes `block` if the condition of the previous `sif` statement is not met.
2902
2902
 
@@ -3026,7 +3026,7 @@ It is also possible to define a custom enumerator using the following command:
3026
3026
  <enum> = senumerator(<typ>,<size>) <block>
3027
3027
  ```
3028
3028
 
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:
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:
3030
3030
 
3031
3031
  ```ruby
3032
3032
  bit[8][-8].inner mem: [ _h01, _h02, _h03, _h04, _h30, _h30, _h30, _h30 ]
@@ -3042,7 +3042,7 @@ Where `enum` is a Ruby variable referring to the enumerator, `typ` is the data t
3042
3042
  end
3043
3043
  ```
3044
3044
 
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.
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 for after the address is set, and therefore a `step` command is added in the access procedure before `data` can be returned.
3046
3046
 
3047
3047
  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
3048
 
@@ -3120,12 +3120,12 @@ With this basis, several algorithms have been implemented using enumerators and
3120
3120
 
3121
3121
 
3122
3122
 
3123
- ### Shared signals, arbiters and monitors: `std/sequencer_sync.rb`
3123
+ ### Shared signals, arbiters, and monitors: `std/sequencer_sync.rb`
3124
3124
  <a name="shared"></a>
3125
3125
 
3126
3126
  #### Shared signals
3127
3127
 
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.
3128
+ 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
3129
 
3130
3130
  The shared signals are declared like the other kind of signals from their type. The syntax is the following:
3131
3131
 
@@ -3139,14 +3139,14 @@ They can also have an initial (and default) value when declared as follows:
3139
3139
  <type>.shared <list of names with initialization>
3140
3140
  ```
3141
3141
 
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`:
3142
+ 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
3143
 
3144
3144
  ```ruby
3145
3145
  [8].shared :x, :y
3146
3146
  signed[8].shared u: 0, v: 0
3147
3147
  ```
3148
3148
 
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:
3149
+ 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
3150
 
3151
3151
  ```ruby
3152
3152
  input :clk, :start
@@ -3173,21 +3173,21 @@ But the following code is not valid:
3173
3173
  par(clk.posedge) { w <= w + 1 }
3174
3174
  ```
3175
3175
 
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.
3176
+ 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
3177
 
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:
3178
+ 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
3179
 
3180
3180
  ```ruby
3181
3181
  <shared signal>.select
3182
3182
  ```
3183
3183
 
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:
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 following code can be added after this signal is declared:
3185
3185
 
3186
3186
  ```ruby
3187
3187
  x.select <= 1
3188
3188
  ```
3189
3189
 
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:
3190
+ 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
3191
 
3192
3192
  ```ruby
3193
3193
  par(clk.posedge) { x.select <= x.select + 1 }
@@ -3198,15 +3198,15 @@ __Note__: this select sub signal is a standard RTL signal that has the same prop
3198
3198
 
3199
3199
  #### Arbiters
3200
3200
 
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:
3201
+ 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
3202
 
3203
3203
  ```ruby
3204
3204
  arbiter(:<name>).(<list of shared signal>)
3205
3205
  ```
3206
3206
 
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.
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 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
3208
 
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:
3209
+ 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
3210
 
3211
3211
  ```ruby
3212
3212
  input :clk, :start
@@ -3236,20 +3236,20 @@ end
3236
3236
 
3237
3237
  In the example, both sequencers require access to signals `x` and `y` before accessing them and then releasing the access.
3238
3238
 
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:
3239
+ 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.
3240
+ 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
3241
 
3242
3242
  ```ruby
3243
3243
  hif(ctrl_xy.acquired) { x <= x + 1 }
3244
3244
  ```
3245
3245
 
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:
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 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
3247
 
3248
3248
  ```ruby
3249
3249
  ctrl_xy.policy([1,0])
3250
3250
  ```
3251
3251
 
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:
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 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
3253
 
3254
3254
  ```ruby
3255
3255
  inner priority_xy: 0
@@ -3272,26 +3272,26 @@ ctrl_xy.policy do |acq|
3272
3272
  end
3273
3273
  ```
3274
3274
 
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.
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 corresponds to sequencer 0, bit 1 to sequencer 1 and so on.
3276
3276
 
3277
3277
 
3278
3278
  #### Monitors
3279
3279
 
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.
3280
+ 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
3281
 
3282
- The monitor component are instantiated like the arbiters as follows:
3282
+ The monitor component is instantiated like the arbiters as follows:
3283
3283
 
3284
3284
  ```ruby
3285
3285
  monitor(:<name>).(<list of shared signals>)
3286
3286
  ```
3287
3287
 
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:
3288
+ 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
3289
 
3290
3290
  ```ruby
3291
3291
  monitor(:ctrl_xy).(x,y)
3292
3292
  ```
3293
3293
 
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:
3294
+ 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
3295
 
3296
3296
  ```ruby
3297
3297
  input :clk, :start
@@ -3319,6 +3319,66 @@ sequencer(clk.posedge,start) do
3319
3319
  end
3320
3320
  ```
3321
3321
 
3322
+ ### Sequencer-specific function: `std/sequencer_func.rb`
3323
+
3324
+ 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.
3325
+
3326
+ However, it is possible to define functions that do support the sequencer constructs using `sdef` instead of `hdef` as follows:
3327
+
3328
+ ```ruby
3329
+ sdef :<function name> do |<arguments>|
3330
+ <sequencer code>
3331
+ end
3332
+ ```
3333
+
3334
+ Such functions can be defined anywhere in a HDLRuby description, but can only be called within a sequencer.
3335
+
3336
+ 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:
3337
+
3338
+ ```ruby
3339
+ sdef(:fact) do |n|
3340
+ sif(n > 1) { sreturn(n*fact(n-1)) }
3341
+ selse { sreturn(1) }
3342
+ end
3343
+ ```
3344
+
3345
+ As seen in the code above, a new construct `sreturn` can be used for returning a value from anywhere inside the function.
3346
+
3347
+ 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:
3348
+
3349
+ ```ruby
3350
+ sdef(:fact,32) do |n|
3351
+ sif(n > 1) { sreturn(n*fact(n-1)) }
3352
+ selse { sreturn(1) }
3353
+ end
3354
+ ```
3355
+
3356
+ __Notes__:
3357
+
3358
+ * A call to such a function and a return take respectively one and two cycles of the sequencer.
3359
+
3360
+ * For now, there is no tail call optimization.
3361
+
3362
+ * 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:
3363
+
3364
+ ```ruby
3365
+ sdef(:<name>,<depth>, proc <block>) do
3366
+ <function code>
3367
+ end
3368
+ ```
3369
+
3370
+ 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:
3371
+
3372
+ ```ruby
3373
+ sdef(:fact,32, proc { stack_overflow <= 1 }) do |n|
3374
+ sif(n > 1) { sreturn(n*fact(n-1)) }
3375
+ selse { sreturn(1) }
3376
+ end
3377
+ ```
3378
+
3379
+ With the code above, the only restriction is that the signal `stack_overflow` is declared before the function `fact` is called.
3380
+
3381
+
3322
3382
  ## Fixed-point (fixpoint): `std/fixpoint.rb`
3323
3383
  <a name="fixpoint"></a>
3324
3384