HDLRuby 2.11.12 → 3.1.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.html +3274 -0
  3. data/README.md +660 -128
  4. data/ext/hruby_sim/hruby_sim_calc.c +2 -0
  5. data/lib/HDLRuby/backend/hruby_allocator.rb +2 -2
  6. data/lib/HDLRuby/backend/hruby_c_allocator.rb +7 -7
  7. data/lib/HDLRuby/hdr_samples/constant_in_function.rb +2 -1
  8. data/lib/HDLRuby/hdr_samples/mei8_bench.rb +1 -1
  9. data/lib/HDLRuby/hdr_samples/with_bram.rb +3 -3
  10. data/lib/HDLRuby/hdr_samples/with_bram_frame_stack.rb +105 -0
  11. data/lib/HDLRuby/hdr_samples/with_bram_stack.rb +69 -0
  12. data/lib/HDLRuby/hdr_samples/with_ref_expr.rb +30 -0
  13. data/lib/HDLRuby/hdr_samples/with_sequencer.rb +185 -0
  14. data/lib/HDLRuby/hdr_samples/with_sequencer_deep.rb +91 -0
  15. data/lib/HDLRuby/hdr_samples/with_sequencer_enumerable.rb +439 -0
  16. data/lib/HDLRuby/hdr_samples/with_sequencer_enumerator.rb +89 -0
  17. data/lib/HDLRuby/hdr_samples/with_sequencer_func.rb +63 -0
  18. data/lib/HDLRuby/hdr_samples/with_sequencer_sync.rb +120 -0
  19. data/lib/HDLRuby/hdrcc.rb +16 -3
  20. data/lib/HDLRuby/hdrlib.rb +1 -1
  21. data/lib/HDLRuby/hruby_db.rb +2 -2
  22. data/lib/HDLRuby/hruby_high.rb +61 -25
  23. data/lib/HDLRuby/hruby_high_fullname.rb +3 -1
  24. data/lib/HDLRuby/hruby_low.rb +2 -2
  25. data/lib/HDLRuby/hruby_low2c.rb +58 -43
  26. data/lib/HDLRuby/hruby_low2hdr.rb +66 -40
  27. data/lib/HDLRuby/hruby_low2high.rb +86 -44
  28. data/lib/HDLRuby/hruby_low2seq.rb +26 -18
  29. data/lib/HDLRuby/hruby_low2sym.rb +14 -13
  30. data/lib/HDLRuby/hruby_low2vhd.rb +78 -43
  31. data/lib/HDLRuby/hruby_low_bool2select.rb +61 -46
  32. data/lib/HDLRuby/hruby_low_casts_without_expression.rb +56 -44
  33. data/lib/HDLRuby/hruby_low_cleanup.rb +18 -16
  34. data/lib/HDLRuby/hruby_low_fix_types.rb +64 -32
  35. data/lib/HDLRuby/hruby_low_mutable.rb +53 -118
  36. data/lib/HDLRuby/hruby_low_resolve.rb +26 -31
  37. data/lib/HDLRuby/hruby_low_with_bool.rb +33 -16
  38. data/lib/HDLRuby/hruby_low_with_port.rb +3 -3
  39. data/lib/HDLRuby/hruby_low_with_var.rb +23 -9
  40. data/lib/HDLRuby/hruby_low_without_concat.rb +19 -13
  41. data/lib/HDLRuby/hruby_low_without_namespace.rb +47 -32
  42. data/lib/HDLRuby/hruby_low_without_parinseq.rb +18 -12
  43. data/lib/HDLRuby/hruby_low_without_select.rb +36 -23
  44. data/lib/HDLRuby/hruby_low_without_subsignals.rb +79 -39
  45. data/lib/HDLRuby/hruby_rcsim.rb +79 -64
  46. data/lib/HDLRuby/hruby_rsim.rb +64 -15
  47. data/lib/HDLRuby/hruby_rsim_mute.rb +2 -3
  48. data/lib/HDLRuby/hruby_rsim_vcd.rb +28 -25
  49. data/lib/HDLRuby/hruby_types.rb +5 -5
  50. data/lib/HDLRuby/hruby_values.rb +19 -8
  51. data/lib/HDLRuby/hruby_verilog.rb +191 -65
  52. data/lib/HDLRuby/hruby_verilog_name.rb +49 -42
  53. data/lib/HDLRuby/soft/stacks.rb +219 -0
  54. data/lib/HDLRuby/std/bram.rb +9 -5
  55. data/lib/HDLRuby/std/clocks.rb +1 -1
  56. data/lib/HDLRuby/std/fsm.rb +39 -10
  57. data/lib/HDLRuby/std/sequencer.rb +2085 -0
  58. data/lib/HDLRuby/std/sequencer_func.rb +533 -0
  59. data/lib/HDLRuby/std/sequencer_sync.rb +400 -0
  60. data/lib/HDLRuby/std/std.rb +13 -0
  61. data/lib/HDLRuby/version.rb +1 -1
  62. data/tuto/adder_sat_flags_vcd.png +0 -0
  63. data/tuto/addsub_vcd.png +0 -0
  64. data/tuto/alu_vcd.png +0 -0
  65. data/tuto/bit_pong_vcd.png +0 -0
  66. data/tuto/checksum_vcd.png +0 -0
  67. data/tuto/circuit_hdr.odg +0 -0
  68. data/tuto/circuit_hdr.png +0 -0
  69. data/tuto/circuit_hie.odg +0 -0
  70. data/tuto/circuit_hie.png +0 -0
  71. data/tuto/circuit_view.odg +0 -0
  72. data/tuto/circuit_view.png +0 -0
  73. data/tuto/clock_counter_vcd.png +0 -0
  74. data/tuto/counter_ext_vcd.png +0 -0
  75. data/tuto/fact_vcd.png +0 -0
  76. data/tuto/hw_flow.odg +0 -0
  77. data/tuto/hw_flow.png +0 -0
  78. data/tuto/maxxer_vcd.png +0 -0
  79. data/tuto/pingpong0_vcd.png +0 -0
  80. data/tuto/pingpong1_vcd.png +0 -0
  81. data/tuto/pingpong2_vcd.png +0 -0
  82. data/tuto/ram_vcd.png +0 -0
  83. data/tuto/serializer_vcd.png +0 -0
  84. data/tuto/sw_flow.odg +0 -0
  85. data/tuto/sw_flow.png +0 -0
  86. data/tuto/the_counter_vcd.png +0 -0
  87. data/tuto/tutorial_sw.html +2359 -0
  88. data/tuto/tutorial_sw.md +2890 -0
  89. data/tuto/tutorial_sw.pdf +0 -0
  90. data/tuto/tutorial_sw_jp.md +417 -0
  91. metadata +46 -2
data/README.md CHANGED
@@ -3,6 +3,37 @@
3
3
  HDLRuby is a library for describing and simulating digital electronic
4
4
  systems.
5
5
 
6
+ __Note__:
7
+
8
+ If you are new to HDLRuby, it is recommended that you consult first the following tutorial (even if you are a hardware person):
9
+
10
+ * [HDLRuby tutorial for software people](tuto/tutorial_sw.md)
11
+
12
+ __What's new__
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
+
26
+ For HDLRuby version 3.0.0:
27
+
28
+ * This section;
29
+
30
+ * [The sequencers](#sequencer-software-like-hardware-coding-stdsequencerrb) for software-like hardware design;
31
+
32
+ * A [tutorial](tuto/tutorial_sw.md) for software people;
33
+
34
+ * The stable [standard libraries](#standard-libraries) are loaded by default.
35
+
36
+
6
37
  __Install__:
7
38
 
8
39
  The recommended installation method is from rubygem as follows:
@@ -27,7 +58,7 @@ __Warning__:
27
58
 
28
59
  ## Using the HDLRuby compiler
29
60
 
30
- 'hdrcc' is the HDLRuby compiler. It takes as input an HDLRuby file, checks it, and can produce as output a Verilog HDL, VHDL, or a YAML low-level descriptions of HW components but it can also simulate the input description.
61
+ 'hdrcc' is the HDLRuby compiler. It takes as input an HDLRuby file, checks it, and can produce as output a Verilog HDL, VHDL, or a YAML low-level description of HW components but it can also simulate the input description.
31
62
 
32
63
 
33
64
  __Usage__:
@@ -49,68 +80,76 @@ Where:
49
80
  | `-v, --verilog` | Output in Verilog HDL format |
50
81
  | `-V, --vhdl` | Output in VHDL format |
51
82
  | `-s, --syntax` | Output the Ruby syntax tree |
52
- | `-C, --clang` | Output the C code of the standalone simulator. |
53
- | `-S, --sim` | Perform the simulation with the default engine. |
54
- | `--csim` | Perform the simulation with the standalone engine. |
55
- | `--rsim` | Perform the simulation with the Ruby engine. |
56
- | `--rcsim` | Perform the simulation with the Hybris engine. |
83
+ | `-C, --clang` | Output the C code of the standalone simulator |
84
+ | `-S, --sim` | Perform the simulation with the default engine |
85
+ | `--csim` | Perform the simulation with the standalone engine |
86
+ | `--rsim` | Perform the simulation with the Ruby engine |
87
+ | `--rcsim` | Perform the simulation with the Hybrid engine |
57
88
  | `--vcd` | Make the simulator generate a VCD file |
58
89
  | `-d, --directory` | Specify the base directory for loading the HDLRuby files |
59
90
  | `-D, --debug` | Set the HDLRuby debug mode |
60
91
  | `-t, --top system`| Specify the top system describing the circuit to compile |
61
92
  | `-p, --param x,y,z` | Specify the generic parameters |
62
- | `--version ` | Print the version number, then exit |
93
+ | `--get-samples` | Copy the sample directory (hdr_samples) to current one, then exit |
94
+ | `--version` | Show the version number, then exit |
63
95
  | `-h, --help` | Show the help message |
64
96
 
65
97
  __Notes__:
66
98
 
67
99
  * If no top system is given, it is automatically looked for from the input file.
68
100
  * If no option is given, it simply checks the input file.
69
- * The simulator option (-S) requires a standard compiler (accessible through the command `cc`) to be available in the executable path.
101
+ * If you are new to HDLRuby, or if you want to see how new features work, we strongly encourage to get a local copy of the test HDLRuby sample using:
102
+
103
+ ```bash
104
+ hdrcc --get-samples
105
+ ```
106
+
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).
108
+
70
109
 
71
110
  __Examples__:
72
111
 
73
112
  * Compile system named `adder` from `adder.rb` input file and generate a low-level YAML description into directory `adder`:
74
113
 
75
- ```
114
+ ```bash
76
115
  hdrcc --yaml --top adder adder.rb adder
77
116
  ```
78
117
 
79
- * 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`:
80
119
 
81
- ```
120
+ ```bash
82
121
  hdrcc -v adder.rb adder
83
122
  ```
84
123
 
85
124
  * Compile system `adder` whose bit width is generic from `adder_gen.rb` input file to a 16-bit circuit low-level VHDL description into directory `adder`:
86
125
 
87
- ```
126
+ ```bash
88
127
  hdrcc -V -t adder --param 16 adder_gen.rb adder
89
128
  ```
90
129
 
91
130
  * Compile system `multer` with inputs and output bit width is generic from `multer_gen.rb` input file to a 16x16->32-bit circuit whose low-level YAML description into directory `multer`:
92
131
 
93
- ```
132
+ ```bash
94
133
  hdrcc -y -t multer -p 16,16,32 multer_gen.rb multer
95
134
  ```
96
135
 
97
- * Simulate the circuit described in file `counter_bench.rb` using the default simluation 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`:
98
137
 
99
- ```
138
+ ```bash
100
139
  hdrcc -S counter_bench.rb counter
101
140
  ```
102
141
 
103
- As a policy, the default simulation enigne is set to the fastest one (cuttently it is the hybrid engine).
142
+ As a policy, the default simulation engine is set to the fastest one (currently it is the hybrid engine).
104
143
 
105
144
  * Run in interactive mode.
106
145
 
107
- ```
146
+ ```bash
108
147
  hdrcc -I
109
148
  ```
110
149
 
111
150
  * Run in interactive mode using pry as UI.
112
151
 
113
- ```
152
+ ```bash
114
153
  hdrcc -I pry
115
154
  ```
116
155
 
@@ -166,13 +205,13 @@ The second specificity of HDLRuby is that it supports natively all the features
166
205
 
167
206
  __Notes__:
168
207
 
169
- - It is still possible to extend HDLRuby to support hardware descriptions of a higher level than RTL, please refer to section [Extending HDLRuby](#extend) for more details.
208
+ - It is still possible to extend HDLRuby to support hardware descriptions of a higher level than RTL, please refer to section [Extending HDLRuby](#extending-hdlruby) for more details.
170
209
  - In this document, HDLRuby constructs will often be compared to their Verilog HDL or VHDL equivalents for simpler explanations.
171
210
 
172
211
  ## Introduction
173
212
 
174
213
  This introduction gives a glimpse of the possibilities of the language.
175
- However, we do recommend consulting the section about the [high-level programming features](#highfeat) to have a more complete view of the advanced possibilities of this language.
214
+ However, we do recommend consulting the section about the [high-level programming features](#high-level-programming-features) to have a more complete view of the advanced possibilities of this language.
176
215
 
177
216
  At first glance, HDLRuby appears like any other HDL (like Verilog HDL or VHDL), for instance, the following code describes a simple D-FF:
178
217
 
@@ -187,7 +226,7 @@ system :dff do
187
226
  end
188
227
  ```
189
228
 
190
- As it can be seen in the code above, `system` is the keyword used for describing a digital circuit. This keyword is an equivalent of the Verilog HDL `module`. In such a system, signals are declared using a `<type>.<direction>` construct where `type` is the data type of the signal (e.g., `bit` as in the code above) and `direction` indicates if the signal is an input, an output, an inout or an inner one; and executable blocks (similar to `always` block of Verilog HDL) are described using the `par` keyword when they are parallel and `seq` when they are sequential (i.e., with respectively non-blocking and blocking assignments).
229
+ As can be seen in the code above, `system` is the keyword used for describing a digital circuit. This keyword is the equivalent of the Verilog HDL `module`. In such a system, signals are declared using a `<type>.<direction>` construct where `type` is the data type of the signal (e.g., `bit` as in the code above) and `direction` indicates if the signal is an input, an output, an inout or an inner one; and executable blocks (similar to `always` block of Verilog HDL) are described using the `par` keyword when they are parallel and `seq` when they are sequential (i.e., with respectively non-blocking and blocking assignments).
191
230
 
192
231
  After such a system has been defined, it can be instantiated. For example, a single instance of the `dff` system named `dff0` can be declared as follows:
193
232
 
@@ -195,7 +234,7 @@ After such a system has been defined, it can be instantiated. For example, a sin
195
234
  dff :dff0
196
235
  ```
197
236
 
198
- The ports of this instance can then be accessed to be used like any other signals, e.g., `dff0.d` for access the `d` input of the FF.
237
+ The ports of this instance can then be accessed to be used like any other signals, e.g., `dff0.d` for accessing the `d` input of the FF.
199
238
 
200
239
  Several instances can also be declared in a single statement. For example, a 2-bit counter based on the previous `dff` circuits can be described as follows:
201
240
 
@@ -230,7 +269,7 @@ system :counter2 do
230
269
  end
231
270
  ```
232
271
 
233
- 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.
234
273
 
235
274
  While a circuit can be generated from the code given above, a benchmark must
236
275
  be provided to test it. Such a benchmark is described by constructs called
@@ -285,8 +324,7 @@ end
285
324
  ```
286
325
 
287
326
  Then, it often happens that a system will end up with only one instance.
288
- In such a case, the system declaration can be omitted and an instance
289
- can be directly declared as follows:
327
+ In such a case, the system declaration can be omitted, and an instance can be directly declared as follows:
290
328
 
291
329
  ```ruby
292
330
  instance :dff_single do
@@ -297,8 +335,7 @@ instance :dff_single do
297
335
  end
298
336
  ```
299
337
 
300
- In the example above, `dff_single` is an instance describing, again, a
301
- 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.
302
339
 
303
340
  Furthermore, generic parameters can be used for anything in HDLRuby.
304
341
  For instance, the following code describes an 8-bit register without any parameterization:
@@ -395,7 +432,7 @@ system :shifter do |n|
395
432
  end
396
433
  ```
397
434
 
398
- As it can be seen in the above examples, in HDLRuby, any construct is an object and therefore include methods. For instance, declaring a signal of a given `type` and direction (input, output, or inout) is done as follows so that `direction` is a method of the type, and the signal names are the arguments of this method (symbols or string are supported.)
435
+ As can be seen in the above examples, in HDLRuby, any construct is an object and therefore include methods. For instance, declaring a signal of a given `type` and direction (input, output, or inout) is done as follows so that `direction` is a method of the type, and the signal names are the arguments of this method (symbols or string are supported.)
399
436
 
400
437
  ```ruby
401
438
  <type>.<direction> <list of symbols representing the signal>
@@ -430,7 +467,7 @@ system :sumprod_16_3456 do
430
467
  end
431
468
  ```
432
469
 
433
- The description above is straightforward, but it would be necessary to rewrite it if another circuit with different bit width or coefficients is to be designed. Moreover, if the number of coefficients is large an error in the expression will be easy to make and hard to find. A better approach would be to use a generic description of such a circuit as follows:
470
+ The description above is straightforward, but it would be necessary to rewrite it if another circuit with different bit widths or coefficients is to be designed. Moreover, if the number of coefficients is large an error in the expression will be easy to make and hard to find. A better approach would be to use a generic description of such a circuit as follows:
434
471
 
435
472
  ```ruby
436
473
  system :sumprod do |typ,coefs|
@@ -446,7 +483,7 @@ end
446
483
  In the code above, there are two generic parameters,
447
484
  `typ`, which indicates the data type of the circuit, and `coefs`, which is assumed to be an array of coefficients. Since the number of inputs depends on the number of provided coefficients, it is declared as an array of `width` bit signed whose size is equal to the number of coefficients.
448
485
 
449
- The description of the sum of products may be more difficult to understand for people not familiar with the Ruby language. The `each_with_index` method iterates over the coefficients adding their index as iteration variable, the resulting operation (i.e., the iteration loop) is then modified by the `reduce` method that accumulates the code passed as arguments. This code, starting by `|sum,coef,i|` simply performs the addition of the current accumulation result (`sum`) with the product of the current coefficient (`coef`) and input (`ins[i]`, where `i` is the index) in the iteration. The argument `_b0` initializes the sum to `0`.
486
+ The description of the sum of products may be more difficult to understand for people not familiar with the Ruby language. The `each_with_index` method iterates over the coefficients adding their index as an iteration variable, the resulting operation (i.e., the iteration loop) is then modified by the `reduce` method that accumulates the code passed as arguments. This code, starting by `|sum,coef,i|` simply performs the addition of the current accumulation result (`sum`) with the product of the current coefficient (`coef`) and input (`ins[i]`, where `i` is the index) in the iteration. The argument `_b0` initializes the sum to `0`.
450
487
 
451
488
  While slightly longer than the previous description, this description allows declaring a circuit implementing a sum of products with any bit width and any number of coefficients. For instance, the following code describes a signed 32-bit sum of products with 16 coefficients (just random numbers here).
452
489
 
@@ -456,7 +493,7 @@ sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit
456
493
 
457
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.
458
495
 
459
- While the description `sumprod` is already usable in a wide range of cases, it still uses the 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:
460
497
 
461
498
  ```ruby
462
499
  system :sumprod_func do |typ,coefs|
@@ -473,7 +510,7 @@ end
473
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:
474
511
 
475
512
  ```ruby
476
- function :add do |x,y|
513
+ hdef :add do |x,y|
477
514
  inner :res
478
515
  seq do
479
516
  res <= x + y
@@ -491,7 +528,7 @@ With HDLRuby functions, the result of the last statement in the return value, in
491
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:
492
529
 
493
530
  ```ruby
494
- function :add do |max, x, y|
531
+ hdef :add do |max, x, y|
495
532
  inner :res
496
533
  seq do
497
534
  res <= x + y
@@ -500,9 +537,9 @@ function :add do |max, x, y|
500
537
  end
501
538
  ```
502
539
 
503
- 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.
504
541
 
505
- 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:
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:
506
543
 
507
544
  ```ruby
508
545
  system :sumprod_proc do |add,mult,typ,coefs|
@@ -582,12 +619,7 @@ sumprod(sat(16,1000),
582
619
  ```
583
620
 
584
621
 
585
- Lastly note, HDLRuby is also a language with supports reflection for
586
- all its constructs. For example, the system of an instance can be accessed
587
- using the `systemT` method, and this latter can be used to create
588
- other instances. For example, previously, `dff_single` was declared with
589
- an anonymous system (i.e., it cannot be accessed by name). This system
590
- 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:
591
623
 
592
624
  ```ruby
593
625
  dff_single.systemT.instantiate(:dff_not_single)
@@ -596,12 +628,8 @@ dff_single.systemT.instantiate(:dff_not_single)
596
628
  In the above example, `dff_not_single` is declared to be an instance
597
629
  of the same system as `dff_single`.
598
630
 
599
- This reflection capability can also be used for instance, for accessing the
600
- data type of a signal (`sig.type`), but also the current basic block
601
- (`cur_block`), the current process (`cur_behavior`) and so on.
602
- The standard library of HDLRuby includes several hardware constructs
603
- like finite state machine descriptors and is mainly based on using these
604
- 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.
605
633
 
606
634
 
607
635
 
@@ -625,10 +653,10 @@ From there, we will describe in more detail each construct of HDLRuby.
625
653
  ## Naming rules
626
654
  <a name="names"></a>
627
655
 
628
- Several constructs in HDLRuby are referred to by name, e.g., systems and signals. When such constructs are declared, their names are to be specified by Ruby symbols starting with a lower case. For example, `:hello` is a valid name declaration, but `:Hello` is not.
656
+ Several constructs in HDLRuby are referred to by name, e.g., systems and signals. When such constructs are declared, their names are to be specified by Ruby symbols starting with a lowercase. For example, `:hello` is a valid name declaration, but `:Hello` is not.
629
657
 
630
658
  After being declared, the construct can be referred to by using the name directly (i.e., without the `:` of Ruby symbols). For example, if a construct
631
- has been declared with `:hello` as name, it will be afterward referred to by `hello`.
659
+ has been declared with `:hello` as the name, it will be afterward referred to by `hello`.
632
660
 
633
661
  ## Systems and signals
634
662
 
@@ -646,11 +674,10 @@ system(:box) {}
646
674
 
647
675
  __Notes__:
648
676
 
649
- - Since this is Ruby code, the body can also be delimited by the `do` and `end`
650
- 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:
651
678
 
652
679
  ```ruby
653
- system :box do
680
+ system :box does
654
681
  end
655
682
  ```
656
683
 
@@ -677,8 +704,7 @@ Now, since `bit` is the default data type in HDLRuby, it can be omitted as follo
677
704
  input :clk
678
705
  ```
679
706
 
680
- 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
681
- 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.
682
708
 
683
709
  ```ruby
684
710
  system :mem8_16 do
@@ -773,8 +799,7 @@ It is also possible to connect multiple signals of an instance using the call op
773
799
  <instance name>.(<signal name0>: <target0>, ...)
774
800
  ```
775
801
 
776
- For example, the following code connects signals `clk` and `rst` of instance
777
- `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.
778
803
 
779
804
  ```ruby
780
805
  mem8_16I.(clk: clk, rst: rst)
@@ -921,7 +946,7 @@ Where:
921
946
  * `<name>` is the name of the scope.
922
947
  * `<code>` is the code within the scope.
923
948
 
924
- Contrary to the case of scopes without a name, signals and instances declared within a named scope can be accessed outside using this name as a reference. For example, in the code below signal `sig` declared within scope named `scop` is accessed outside it using `scop.sig`:
949
+ Contrary to the case of scopes without a name, signals, and instances declared within a named scope can be accessed outside using this name as a reference. For example, in the code below signal `sig` declared within scope named `scop` is accessed outside it using `scop.sig`:
925
950
 
926
951
  ```ruby
927
952
  sub :scop do
@@ -948,7 +973,7 @@ end
948
973
  In addition, it is possible to declare inner signals within an execution block.
949
974
  While such signals will be physically linked to the system, they are only accessible within the block they are declared into. This permits a tighter scope for signals, which improves the readability of the code and make it possible to declare several signals with identical names provided their respective scopes are different.
950
975
 
951
- An event represents a specific change of state of a signal.
976
+ An event represents a specific change in the state of a signal.
952
977
  For example, a rising edge of a clock signal named `clk` will be represented by the event `clk.posedge`. In HDLRuby, events are obtained directly from
953
978
  expressions using the following methods: `posedge` for a rising edge, `negedge` for a falling edge, and `edge` for any edge.
954
979
  Events are described in more detail in section [Events](#events).
@@ -989,7 +1014,7 @@ system :with_sequential_behavior do
989
1014
  end
990
1015
  ```
991
1016
 
992
- A sub-block can also have a different execution mode if it is declared using `seq`, which will force sequential execution mode, and `par` which will force parallel execution mode. For example, in the following code a parallel sub-block is declared within a sequential one:
1017
+ A sub-block can also have a different execution mode if it is declared using `seq`, which will force sequential execution mode and `par` which will force parallel execution mode. For example, in the following code a parallel sub-block is declared within a sequential one:
993
1018
 
994
1019
  ```ruby
995
1020
  system :with_sequential_behavior do
@@ -1002,7 +1027,7 @@ system :with_sequential_behavior do
1002
1027
  end
1003
1028
  ```
1004
1029
 
1005
- Sub blocks have their scope so that it is possible to declare signals without colliding with existing ones. For example, it is possible to
1030
+ Sunblocks have their scope so that it is possible to declare signals without colliding with existing ones. For example, it is possible to
1006
1031
  declare three different inner signals all called `sig` as follows:
1007
1032
 
1008
1033
  ```ruby
@@ -1117,7 +1142,7 @@ unshift do
1117
1142
  end
1118
1143
  ```
1119
1144
 
1120
- For example the following code inserts two statements at the beginning of the current block:
1145
+ For example, the following code inserts two statements at the beginning of the current block:
1121
1146
 
1122
1147
  ```ruby
1123
1148
  par do
@@ -1129,7 +1154,7 @@ par do
1129
1154
  end
1130
1155
  ```
1131
1156
 
1132
- The code above will actually result in the following block:
1157
+ The code above will result in the following block:
1133
1158
 
1134
1159
  ```ruby
1135
1160
  par do
@@ -1151,7 +1176,7 @@ In HDLRuby, dynamically reconfigurable devices are modeled by instances having m
1151
1176
  <instance>.choice(<list of named systems>)
1152
1177
  ```
1153
1178
 
1154
- For example, assuming systems `sys0`, `sys1` and `sys2` have been previously declared a device named `dev012` able to be reconfigured to one of these three systems would be declared as follows (the connections of the instance, omitted in the example, can be done as usual):
1179
+ For example, assuming systems `sys0`, `sys1`, and `sys2` have been previously declared a device named `dev012` able to be reconfigured to one of these three systems would be declared as follows (the connections of the instance, omitted in the example, can be done as usual):
1155
1180
 
1156
1181
  ```ruby
1157
1182
  sys0 :dev012 # dev012 is at first a standard instance of sys0
@@ -1183,9 +1208,8 @@ These reconfiguration commands are treated as regular RTL statements in HDLRuby
1183
1208
 
1184
1209
 
1185
1210
  ## Events
1186
- <a name="events"></a>
1187
1211
 
1188
- Each behavior of a system is associated with a list of events, called a sensitivity list, that specifies when the behavior is to be executed. An event is associated with a signal and represents the instants when the signal reaches a given state.
1212
+ Each behavior of a system is associated with a list of events, called a sensitivity list, that specifies when the behavior is to be executed. An event is associated with a signal and represents the instant when the signal reaches a given state.
1189
1213
 
1190
1214
  There are three kinds of events: positive edge events represent the instants when their corresponding signals vary from 0 to 1, and negative edge events
1191
1215
  represent the instants when their corresponding signals vary from 1 to 0 and the change events represent the instants when their corresponding signals vary.
@@ -1211,7 +1235,6 @@ __Note:__
1211
1235
  - The `change` keyword can be omitted.
1212
1236
 
1213
1237
  ## Statements
1214
- <a name="statements"></a>
1215
1238
 
1216
1239
  Statements are the basic elements of a behavioral description. They are regrouped in blocks that specify their execution mode (parallel or sequential).
1217
1240
  There are four kinds of statements: the transmit statement which computes expressions and sends the result to the target signals, the control statement
@@ -1224,7 +1247,7 @@ __Note__:
1224
1247
 
1225
1248
  ### Transmit statement
1226
1249
 
1227
- A transmit statement is declared using the arrow operator `<=` within a behavior. Its right value is the expression to compute and its left value is a reference to the target signals (or parts of signals), i.e., the signals (or part of signals) that receive the computation result.
1250
+ A transmit statement is declared using the arrow operator `<=` within a behavior. Its right value is the expression to compute and its left value is a reference to the target signals (or parts of signals), i.e., the signals (or parts of signals) that receive the computation result.
1228
1251
 
1229
1252
  For example, the following code transmits the value `3` to signal `s0` and the sum of the values of signals `i0` and `i1` to the first four bits of signal `s1`:
1230
1253
 
@@ -1282,7 +1305,7 @@ end
1282
1305
 
1283
1306
  ### helsif
1284
1307
 
1285
- In addition to `helse` it is possible to set additional conditions to an `hif` using the `helsif` keyword as follows:
1308
+ In addition to `helse`, it is possible to set additional conditions to an `hif` using the `helsif` keyword as follows:
1286
1309
 
1287
1310
  ```ruby
1288
1311
  hif <condition 0> do
@@ -1297,7 +1320,7 @@ end
1297
1320
  #### About loops
1298
1321
 
1299
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
1300
- 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).
1301
1324
 
1302
1325
  __Notes__:
1303
1326
 
@@ -1416,11 +1439,10 @@ While the underlying structure of any HDLRuby type is the bit vector, complex ty
1416
1439
  <a name="expressions"></a>
1417
1440
 
1418
1441
  Expressions are any construct that represents a value associated with a type.
1419
- They include [immediate values](#values), [reference to signals](#references) and operations among other expressions using [expression operators](#operators).
1442
+ They include [immediate values](#immediate-values), [reference to signals](#references) and operations among other expressions using [expression operators](#expression-operators).
1420
1443
 
1421
1444
 
1422
1445
  ### Immediate values
1423
- <a name="values"></a>
1424
1446
 
1425
1447
  The immediate values of HDLRuby can represent vectors of `bit`, `unsigned`, and `signed`, and integer or floating-point numbers. They are prefixed by a `_` character and include a header that indicates the vector type and the base used for representing the value, followed by a numeral representing the value. The bit width of a value is obtained by default from the width of the numeral, but it is also possible to specify it in the header. In addition, the character `_` can be put anywhere in the number for increasing the readability, it will be ignored.
1426
1448
 
@@ -1464,9 +1486,9 @@ _o144
1464
1486
 
1465
1487
  __Notes__:
1466
1488
 
1467
- - `_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.
1468
1490
 
1469
- - 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:
1470
1492
 
1471
1493
  ```ruby
1472
1494
  [3..0].inner :sig
@@ -1475,7 +1497,6 @@ __Notes__:
1475
1497
 
1476
1498
 
1477
1499
  ### References
1478
- <a name="references"></a>
1479
1500
 
1480
1501
  References are expressions used to designate signals or a part of signals.
1481
1502
 
@@ -1517,7 +1538,6 @@ end
1517
1538
  ```
1518
1539
 
1519
1540
  ### Expression operators
1520
- <a name="operators"></a>
1521
1541
 
1522
1542
  The following table gives a summary of the operators available in HDLRuby.
1523
1543
  More details are given for each group of operators in the subsequent sections.
@@ -1594,10 +1614,9 @@ __Notes__:
1594
1614
 
1595
1615
  - The operator precedence is the one of Ruby.
1596
1616
 
1597
- - 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) 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.
1598
1618
 
1599
1619
  #### Assignment operators
1600
- <a name="assignment"></a>
1601
1620
 
1602
1621
  The assignment operators can be used with any type. They are the connection and the transmission operators both being represented by `<=`.
1603
1622
 
@@ -1608,7 +1627,7 @@ __Note__:
1608
1627
  #### Arithmetic operators
1609
1628
  <a name="arithmetic"></a>
1610
1629
 
1611
- 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.
1612
1631
 
1613
1632
  #### Comparison operators
1614
1633
  <a name="comparison"></a>
@@ -1625,7 +1644,6 @@ __Notes__:
1625
1644
 
1626
1645
 
1627
1646
  #### Logic and shift operators
1628
- <a name="logic"></a>
1629
1647
 
1630
1648
  In HDLRuby, the logic operators are all bitwise. For performing Boolean computations, it is necessary to use single-bit values. The bitwise logic binary operators are `&`, `|`, and `^`, and the unary one is `~`. They have the same meaning as their Ruby equivalents.
1631
1649
 
@@ -1650,24 +1668,22 @@ For example, for rotating the left signal `sig` 3 times, the following code can
1650
1668
  sig.rl(3)
1651
1669
  ```
1652
1670
 
1653
- It is possible to perform other kinds of shifts or rotations using the selection and the concatenation operators. Please refer to section [Concatenation and
1654
- selection operators](#concat) 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.
1655
1672
 
1656
1673
 
1657
1674
  #### Conversion operators
1658
- <a name="conversion"></a>
1659
1675
 
1660
1676
  The conversion operators are used to change the type of an expression.
1661
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.
1662
1678
 
1663
- 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:
1664
1680
 
1665
1681
  ```ruby
1666
1682
  [ up: signed[3..0], down: unsigned[3..0] ].inner :sig
1667
1683
  sig.to_bit <= _b01010011
1668
1684
  ```
1669
1685
 
1670
- The type casts change both the type and the value and are used to adjust the width of the types. They can only be applied to vectors of `bit`, `signed`, or `unsinged` and can only increase the bit width (bit width can be truncated using the selection operator, please refer to the [next section](#concat)).
1686
+ The type casts change both the type and the value and are used to adjust the width of the types. They can only be applied to vectors of `bit`, `signed`, or `unsinged` and can only increase the bit width (bit width can be truncated using the selection operator, please refer to the next section).
1671
1687
  These operators comprise the bit width conversions: `ljust`, `rjust`, `zext` and `sext`.
1672
1688
 
1673
1689
  More precisely, the bit width conversions operate as follows:
@@ -1701,7 +1717,6 @@ More precisely, the bit width conversions operate as follows:
1701
1717
 
1702
1718
 
1703
1719
  #### Concatenation and selection operators
1704
- <a name="concat"></a>
1705
1720
 
1706
1721
  Concatenation and selection are done using the `[]` operator as follows:
1707
1722
 
@@ -1716,7 +1731,7 @@ Concatenation and selection are done using the `[]` operator as follows:
1716
1731
  sig2 <= [sig0, sig1]
1717
1732
  ```
1718
1733
 
1719
- - 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`:
1720
1735
 
1721
1736
  ```ruby
1722
1737
  [7..0].inner :sig0
@@ -1808,7 +1823,7 @@ __Multiplicative operators:__
1808
1823
  Like Verilog HDL, HDLRuby provides function constructs for reusing code. HDLRuby functions are declared as follows:
1809
1824
 
1810
1825
  ```ruby
1811
- function :<function name> do |<arguments>|
1826
+ hdef :<function name> do |<arguments>|
1812
1827
  <code>
1813
1828
  end
1814
1829
  ```
@@ -1886,7 +1901,7 @@ system :sys do
1886
1901
  end
1887
1902
  ```
1888
1903
 
1889
- 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`):
1890
1905
 
1891
1906
  ```ruby
1892
1907
  def too_bad
@@ -1912,12 +1927,11 @@ Ruby functions can be compared to the macros of the C languages: they are more f
1912
1927
 
1913
1928
 
1914
1929
  ## Time
1915
- <a name="time"></a>
1916
1930
 
1917
1931
  ### Time values
1918
1932
  <a name="time_val"></a>
1919
1933
 
1920
- 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:
1921
1935
 
1922
1936
  ```ruby
1923
1937
  1.s
@@ -1931,7 +1945,7 @@ In HDLRuby, time values can be created using the time operators: `s` for seconds
1931
1945
  ### Time behaviors and time statements
1932
1946
  <a name="time_beh"></a>
1933
1947
 
1934
- 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.
1935
1949
 
1936
1950
  ```ruby
1937
1951
  timed do
@@ -1987,7 +2001,6 @@ sequential blocks. The execution semantic is the following:
1987
2001
 
1988
2002
 
1989
2003
  ## High-level programming features
1990
- <a name="highfeat"></a>
1991
2004
 
1992
2005
  ### Using Ruby in HDLRuby
1993
2006
 
@@ -2042,7 +2055,7 @@ typedef :<type name> do |<list of generic parameters>|
2042
2055
  end
2043
2056
  ```
2044
2057
 
2045
- 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`:
2046
2059
 
2047
2060
  ```ruby
2048
2061
  type(:bitvec) { |width| bit[width] }
@@ -2072,7 +2085,7 @@ system :subsys, sys(1,2) do
2072
2085
  end
2073
2086
  ```
2074
2087
 
2075
- 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:
2076
2089
 
2077
2090
  ```ruby
2078
2091
  system :subsys_gen do |param|
@@ -2333,7 +2346,7 @@ end
2333
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.
2334
2347
 
2335
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.
2336
- 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):
2337
2350
 
2338
2351
  ```ruby
2339
2352
  typedef(:fixed) do |width|
@@ -2381,7 +2394,7 @@ Several enumerators are also provided for accessing the internals of the current
2381
2394
 
2382
2395
  ### Global signals
2383
2396
 
2384
- 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.
2385
2398
 
2386
2399
  To ease the design of standardized libraries, the following global signals are defined by default:
2387
2400
 
@@ -2400,9 +2413,9 @@ __Note__:
2400
2413
  ### Defining and executing Ruby methods within HDLRuby constructs
2401
2414
  <a name="method"></a>
2402
2415
 
2403
- 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.
2404
2417
 
2405
- 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`.
2406
2419
 
2407
2420
  ```ruby
2408
2421
  def some_arrow
@@ -2471,7 +2484,7 @@ end
2471
2484
  ```
2472
2485
 
2473
2486
 
2474
- 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:
2475
2488
 
2476
2489
  ```ruby
2477
2490
  def after(cycles,rst = $rst, &code)
@@ -2525,9 +2538,8 @@ When describing a system, it is possible to disconnect or completely undefine a
2525
2538
 
2526
2539
 
2527
2540
  ## Extending HDLRuby
2528
- <a name="extend"></a>
2529
2541
 
2530
- 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.
2531
2543
 
2532
2544
  ### Extending HDLRuby constructs globally
2533
2545
 
@@ -2653,8 +2665,7 @@ This way, calling directly `to_low` will automatically use `my_generation`.
2653
2665
 
2654
2666
 
2655
2667
 
2656
- # Standard library
2657
- <a name="library"></a>
2668
+ # Standard libraries
2658
2669
 
2659
2670
  The standard libraries are included in the module `Std`.
2660
2671
  They can be loaded as follows, where `<library name>` is the name of the
@@ -2670,9 +2681,23 @@ After the libraries are loaded, the module `Std` must be included as follows:
2670
2681
  include HDLRuby::High::Std
2671
2682
  ```
2672
2683
 
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:
2685
+
2686
+ - `std/clocks.rb`
2687
+
2688
+ - `std/fixpoint.rb`
2689
+
2690
+ - `std/decoder.rb`
2691
+
2692
+ - `std/fsm.rb`
2693
+
2694
+ - `std/sequencer.rb`
2695
+
2696
+ - `std/sequencer_sync.rb`
2673
2697
 
2674
2698
 
2675
- ## Clocks
2699
+
2700
+ ## Clocks: `std/clocks.rb`
2676
2701
  <a name="clocks"></a>
2677
2702
 
2678
2703
  The `clocks` library provides utilities for easier handling of clock synchronizations.
@@ -2692,9 +2717,9 @@ system :dff_slow do
2692
2717
  end
2693
2718
  ```
2694
2719
 
2695
- __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.
2696
2721
 
2697
- ## Counters
2722
+ ## Counters: `std/counters.rb`
2698
2723
  <a name="counters"></a>
2699
2724
 
2700
2725
  This library provides two new constructs for implementing synthesizable wait statements.
@@ -2711,12 +2736,12 @@ Where:
2711
2736
  * `<clock>` is the clock to use, this argument can be omitted.
2712
2737
  * `<reset>` is the signal used to reset the counter used for waiting, this argument can be omitted.
2713
2738
 
2714
- This statement can be used either inside or outside a clocked behavior. When used within a clocked behavior, the clock event of the behavior is used for the counter unless specified otherwise. When used outside such a behavior, the clock is the global default clock `$clk`. In both cases, the reset is the global reset `$rst` unless specified otherwise.
2739
+ This statement can be used either inside or outside a clocked behavior. When used within a clocked behavior, the clock event of the behavior is used for the counter unless specified otherwise. When used outside such behavior, the clock is the global default clock `$clk`. In both cases, the reset is the global reset `$rst` unless specified otherwise.
2715
2740
 
2716
2741
  The second construct is the `before` statement that activates a block until a given number of clock cycles is passed. Its syntax and usage are identical to the `after` statement.
2717
2742
 
2718
2743
 
2719
- ## Decoder
2744
+ ## Decoder: `std/decoder.rb`
2720
2745
  <a name="decoder"></a>
2721
2746
 
2722
2747
  This library provides a new set of control statements for easily describing an instruction decoder.
@@ -2727,13 +2752,13 @@ A decoder can be declared anywhere in the code describing a system using the `de
2727
2752
  decoder(<signal>) <block>
2728
2753
  ```
2729
2754
 
2730
- 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:
2731
2756
 
2732
2757
  ```ruby
2733
2758
  entry(<pattern>) <block>
2734
2759
  ```
2735
2760
 
2736
- Where `pattern` is a string describing the pattern to match for 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.
2737
2762
 
2738
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`:
2739
2764
 
@@ -2746,12 +2771,12 @@ end
2746
2771
 
2747
2772
  It can be noticed for field `z` in the example above that the bits are not required to be contiguous.
2748
2773
 
2749
- ## FSM
2774
+ ## FSM: `std/fsm.rb`
2750
2775
  <a name="fsm"></a>
2751
2776
 
2752
2777
  This library provides a new set of control statements for easily describing a finite state machine (FSM).
2753
2778
 
2754
- A finite state machine can be declared anywhere provided it is outside a behavior using the `fsm` keyword as follows:
2779
+ A finite state machine can be declared anywhere in a system provided it is outside a behavior using the `fsm` keyword as follows:
2755
2780
 
2756
2781
  ```ruby
2757
2782
  fsm(<event>,<reset>,<mode>) <block>
@@ -2794,7 +2819,7 @@ goto(cond,:st_a,:st_b,:st_c)
2794
2819
 
2795
2820
  Several goto statements can be used, the last one having priority provided it is taken (i.e., its condition corresponds to one of the target states). If no goto is taken, the next transition is the next declared one.
2796
2821
 
2797
- For example, the following code describes a FSM describing a circuit that checks if two buttons (`but_a` and `but_b`) are pressed and released in sequence for activating an output signal (`ok`):
2822
+ For example, the following code describes an FSM describing a circuit that checks if two buttons (`but_a` and `but_b`) are pressed and released in sequence for activating an output signal (`ok`):
2798
2823
 
2799
2824
  ```ruby
2800
2825
  fsm(clk.posedge,rst,:sync) do
@@ -2818,7 +2843,7 @@ fsm(clk.posedge,rst,:sync) do
2818
2843
  end
2819
2844
  ```
2820
2845
 
2821
- __Note__: the goto statements acts globally, i.e., they are independant of the place where they are declared within the state. For example for both following statements, the next state will always be `st_a` whatever `cond` maybe:
2846
+ __Note__: the goto statements act globally, i.e., they are independent of the place where they are declared within the state. For example for both following statements, the next state will always be `st_a` whatever `cond` maybe:
2822
2847
 
2823
2848
  ```ruby
2824
2849
  state(:st_0) do
@@ -2837,7 +2862,7 @@ That is to say, for a conditional `goto` for `st_1` the code should have been wr
2837
2862
  end
2838
2863
  ```
2839
2864
 
2840
- 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 is static mode is done by passing `:static` as 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`:
2841
2866
 
2842
2867
  ```ruby
2843
2868
  fsm(clk.posedge,rst,:static)
@@ -2850,8 +2875,511 @@ fsm(clk.posedge,rst,:static)
2850
2875
  end
2851
2876
  ```
2852
2877
 
2878
+ ## Sequencer (software-like hardware coding):: `std/sequencer.rb`
2879
+ <a name="sequencer"></a>
2880
+
2881
+ This library provides a new set of control statements for describing the behavior of a circuit. Behind the curtain, these constructs build a finite state machine where states are deduced from the control points within the description.
2882
+
2883
+ A sequencer can be declared anywhere in a system provided it is outside a behavior using the `sequencer` keyword as follows:
2884
+
2885
+ ```ruby
2886
+ sequencer(<clock>,<start>) <block>
2887
+ ```
2888
+
2889
+ Where `clock` is the clock signal advancing the execution of the sequence, `start` is the signal starting the execution, and `block` is the description of the sequence to be executed. Both `clock` and `start` can also be events (i.e., `posedge` or `negedge`).
2890
+
2891
+ A sequence is a specific case of a `seq` block that includes the following software-like additional constructs:
2892
+
2893
+ - `step`: wait until the next event (given argument `event` of the sequencer).
2894
+
2895
+ - `steps(<num>)`: perform `num` times `step` (`num` can be any expression).
2896
+
2897
+ - `sif(<condition>) <block>`: executes `block` if `condition` is met.
2898
+
2899
+ - `selsif(<condition>) <block>`: executes `block` if the previous `sif` or `selsif` condition is not met and if the current `condition` is met.
2900
+
2901
+ - `selse <block>`: executes `block` if the condition of the previous `sif` statement is not met.
2902
+
2903
+ - `swait(<condition>)`: waits until that `condition` is met.
2904
+
2905
+ - `swhile(<condition>) <block>`: executes `block` while `condition` is met.
2906
+
2907
+ - `sfor(<enumerable>) <block>`: executes `block` on each element of `enumerable`. This latter can be any enumerable Ruby object or any signal. If the signal is not hierarchical (e.g., bit vector), the iteration will be over each bit.
2908
+
2909
+ - `sbreak`: ends current iteration.
2910
+
2911
+ - `scontinue`: goes to the next step of the iteration.
2912
+
2913
+ - `sterminate`: ends the execution of the sequence.
2914
+
2915
+ It is also possible to use enumerators (iterators) similar to the Ruby `each` using the following methods within sequences:
2916
+
2917
+ - `<object>.seach`: `object` any enumerable Ruby object or any signal. If a block is given, it works like `sfor`, otherwise, it returns a HDLRuby enumerator (please see [enumerator](#hdlruby-enumerators-and-enumerable-objects-stdsequencerrb) for details about them).
2918
+
2919
+ - `<object>.stimes`: can be used on integers and is equivalent to `seach` on each integer from 0 up to `object-1`.
2920
+
2921
+ - `<object>.supto(<last>)`: can be used on integers and is equivalent to `seach` on each integer from `object` up to `last`.
2922
+
2923
+ - `<object>.sdownto(<last>)`: can be used on an integer and is equivalent to `seach` on each integer from `object` down to `last`.
2924
+
2925
+ The objects that support these methods are called _enumerable_ objects. They include the HDLRuby signals, the HDLRuby enumerators, and all the Ruby enumerable objects (e.g., ranges, arrays).
2926
+
2927
+
2928
+ Here are a few examples of sequencers synchronized in the positive edge of `clk` and starting when `start` becomes one. The first one computes the Fibonacci series until 100, producing a new term in signal `v` at each cycle:
2929
+
2930
+ ```ruby
2931
+ require 'std/sequencer.rb'
2932
+ include HDLRuby::High::Std
2933
+
2934
+ system :a_circuit do
2935
+ inner :clk, :start
2936
+ [16].inner :a, :b
2937
+
2938
+ sequencer(clk.posedge,start) do
2939
+ a <= 0
2940
+ b <= 1
2941
+ swhile(v < 100) do
2942
+ b <= a + b
2943
+ a <= b - a
2944
+ end
2945
+ end
2946
+ end
2947
+ ```
2948
+
2949
+ The second one computes the square of the integers from 10 to 100, producing one result per cycle in signal `a`:
2950
+
2951
+ ```ruby
2952
+ inner :clk, :start
2953
+ [16].inner :a
2954
+
2955
+ sequencer(clk.posedge,start) do
2956
+ 10.supto(100) { |i| a <= i*i }
2957
+ end
2958
+ ```
2959
+
2960
+ The third one reverses the content of memory `mem` (the result will be "!dlrow olleH"):
2961
+
2962
+ ```ruby
2963
+ inner :clk, :start
2964
+ bit[8][-12].inner mem: "Hello world!"
2965
+
2966
+ sequencer(clk.posedge,start) do
2967
+ mem.size.stimes do |i|
2968
+ [8].inner :tmp
2969
+ tmp <= mem[i]
2970
+ mem[i] <= mem[-i-1]
2971
+ mem[-i-1] <= tmp
2972
+ end
2973
+ end
2974
+ ```
2975
+
2976
+ The fourth one computes the sum of all the elements of memory `mem` but stops if the sum is larger than 16:
2977
+
2978
+ ```ruby
2979
+ inner :clk, :start
2980
+ bit[8][-8].inner mem: [ _h02, _h04, _h06, _h08, _h0A, _h0C, _h0E ]
2981
+ bit[8] :sum
2982
+
2983
+ sequencer(clk.posedge,start) do
2984
+ sum <= 0
2985
+ sfor(mem) do |elem|
2986
+ sum <= sum + elem
2987
+ sif(sum > 16) { sterminate }
2988
+ end
2989
+ end
2990
+ ```
2991
+
2992
+
2993
+ ### HDLRuby enumerators and enumerable objects: `std/sequencer.rb`
2994
+
2995
+ HDLRuby enumerators are objects for generating iterations within sequencers. They are created using the method `seach` on enumerable objects as presented in the previous section.
2996
+
2997
+ The enumerators can be controlled using the following methods:
2998
+
2999
+ - `size`: returns the number of elements the enumerator can access.
3000
+
3001
+ - `type`: returns the type of the elements accessed by the enumerator.
3002
+
3003
+ - `seach`: returns the current enumerator. If a block is given, performs the iteration instead of returning an enumerator.
3004
+
3005
+ - `seach_with_index`: returns an enumerator over the elements of the current enumerator associated with their index position. If a block is given, performs the iteration instead of returning an enumerator.
3006
+
3007
+ - `seach_with_object(<obj>)`: returns an enumerator over the elements of the current enumerator associated with object `obj` (any object, HDLRuby or not, can be used). If a block is given, performs the iteration instead of returning an enumerator.
3008
+
3009
+ - `with_index`: identical to `seach_with_index`.
3010
+
3011
+ - `with_object(<obj>)`: identical to `seach_with_object`.
3012
+
3013
+ - `clone`: create a new enumerator on the same elements.
3014
+
3015
+ - `speek`: returns the current element pointed by the enumerator without advancing it.
3016
+
3017
+ - `snext`: returns the current element pointed by the enumerator and goes to the next one.
3018
+
3019
+ - `srewind`: restart the enumeration.
3020
+
3021
+ - `+`: concatenation of enumerators.
3022
+
3023
+ It is also possible to define a custom enumerator using the following command:
3024
+
3025
+ ```ruby
3026
+ <enum> = senumerator(<typ>,<size>) <block>
3027
+ ```
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:
3030
+
3031
+ ```ruby
3032
+ bit[8][-8].inner mem: [ _h01, _h02, _h03, _h04, _h30, _h30, _h30, _h30 ]
3033
+ [3].inner :addr
3034
+ [8].inner :data
3035
+
3036
+ data <= mem[addr]
3037
+
3038
+ mem_enum = senumerator(bit[8],8) do |i|
3039
+ addr <= i
3040
+ step
3041
+ data
3042
+ end
3043
+ ```
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 for after the address is set, and therefore a `step` command is added in the access procedure before `data` can be returned.
3046
+
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
+
3049
+ - `sall?`: HW implementation of the Ruby `all?` method. Returns a single-bit signal. When 0 this value means false and when 1 it means true.
3050
+
3051
+ - `sany?`: HW implementation of the Ruby `any?` method. Returns a single-bit signal. When 0 this value means false and when 1 it means true.
3052
+
3053
+ - `schain`: HW implementation of the Ruby `chain`.
3054
+
3055
+ - `smap`: HW implementation of the Ruby `map` method. When used with a block returns a vector signal containing each computation result.
3056
+
3057
+ - `scompact`: HW implementation of the Ruby `compact` method. However, since there is no nil value in HW, use 0 instead for compacting. Returns a vector signal containing the compaction result.
3058
+
3059
+ - `scount`: HW implementation of the Ruby `count` method. Returns a signal whose bit width matches the size of the enumerator containing the count result.
3060
+
3061
+ - `scycle`: HW implementation of the Ruby `cycle` method.
3062
+
3063
+ - `sfind`: HW implementation of the Ruby `find` method. Returns a signal containing the found element, or 0 if not found.
3064
+
3065
+ - `sdrop`: HW implementation of the Ruby `drop` method. Returns a vector signal containing the remaining elements.
3066
+
3067
+ - `sdrop_while`: HW implementation of the Ruby `drop_while` method. Returns a vector signal containing the remaining elements.
3068
+
3069
+ - `seach_cons`: HW implementation of the Ruby `each_cons` method.
3070
+
3071
+ - `seach_slice`: HW implementation of the Ruby `each_slice` method.
3072
+
3073
+ - `seach_with_index`: HW implementation of the Ruby `each_with_index` method.
3074
+
3075
+ - `seach_with_object`: HW implementation of the Ruby `each_with_object` method.
3076
+
3077
+ - `sto_a`: HW implementation of the Ruby `to_a` method. Returns a vector signal containing all the elements of the enumerator.
3078
+
3079
+ - `sselect`: HW implementation of the Ruby `select` method. Returns a vector signal containing the selected elements.
3080
+
3081
+ - `sfind_index`: HW implementation of the Ruby `find_index` method. Returns the index of the found element or -1 if not.
3082
+
3083
+ - `sfirst`: HW implementation of the Ruby `first` method. Returns a vector signal containing the first elements.
3084
+
3085
+ - `sinclude?`: HW implementation of the Ruby `include?` method. Returns a single-bit signal. When 0 this value means false and when 1 it means true.
3086
+
3087
+ - `sinject`: HW implementation of the Ruby `inject` method. Return a signal of the type of elements containing the computation result.
3088
+
3089
+ - `smax`: HW implementation of the Ruby `max` method. Return a vector signal containing the found max values.
3090
+
3091
+ - `smax_by`: HW implementation of the Ruby `max_by` method. Return a vector signal containing the found max values.
3092
+
3093
+ - `smin`: HW implementation of the Ruby `min` method. Return a vector signal containing the found min values.
3094
+
3095
+ - `smin_by`: HW implementation of the Ruby `min_by` method. Return a vector signal containing the found min values.
3096
+
3097
+ - `sminmax`: HW implementation of the Ruby `minmax` method. Returns a 2-element vector signal containing the resulting min and max values.
3098
+
3099
+ - `sminmax_by`: HW implementation of the Ruby `minmax_by` method. Returns a 2-element vector signal containing the resulting min and max values.
3100
+
3101
+ - `snone?`: HW implementation of the Ruby `none?` method. Returns a single-bit signal. When 0 this value means false and when 1 it means true.
3102
+
3103
+ - `sone?`: HW implementation of the Ruby `one?` method. Returns a single-bit signal. When 0 this value means false and when 1 it means true.
3104
+
3105
+ - `sreject`: HW implementation of the Ruby `reject` method. Returns a vector signal containing the remaining elements.
3106
+
3107
+ - `sreverse_each`: HW implementation of the Ruby `reverse_each` method.
3108
+
3109
+ - `ssort`: HW implementation of the Ruby `sort` method. Returns a vector signal containing the sorted elements.
3110
+
3111
+ - `ssort_by`: HW implementation of the Ruby `sort_by` method. Returns a vector signal containing the sorted elements.
3112
+
3113
+ - `ssum`: HW implementation of the Ruby `sum` method. Returns a signal with the type of elements containing the sum result.
3114
+
3115
+ - `stake`: HW implementation of the Ruby `take` method. Returns a vector signal containing the taken elements.
3116
+
3117
+ - `stake_while`: HW implementation of the Ruby `take_while` method. Returns a vector signal containing the taken elements.
3118
+
3119
+ - `suniq`: HW implementation the Ruby `uniq` method. Returns a vector signal containing the selected elements.
3120
+
3121
+
3122
+
3123
+ ### Shared signals, arbiters, and monitors: `std/sequencer_sync.rb`
3124
+ <a name="shared"></a>
3125
+
3126
+ #### Shared signals
3127
+
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
+
3130
+ The shared signals are declared like the other kind of signals from their type. The syntax is the following:
3131
+
3132
+ ```ruby
3133
+ <type>.shared <list of names>
3134
+ ```
3135
+
3136
+ They can also have an initial (and default) value when declared as follows:
3137
+
3138
+ ```ruby
3139
+ <type>.shared <list of names with initialization>
3140
+ ```
3141
+
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
+
3144
+ ```ruby
3145
+ [8].shared :x, :y
3146
+ signed[8].shared u: 0, v: 0
3147
+ ```
3148
+
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
+
3151
+ ```ruby
3152
+ input :clk, :start
3153
+ [8].inner :val0, :val1
3154
+ [8].shared :x, :y
3155
+
3156
+ val0 <= x+y
3157
+ par(clk.posedge) { val1 <= x+y }
3158
+
3159
+ sequencer(clk.posedge,start) do
3160
+ 10.stimes { |i| x <= i }
3161
+ end
3162
+
3163
+ sequencer(clk.posedge,start) do
3164
+ 5.stimes { |i| x <= i*2 ; y <= i*2 }
3165
+ end
3166
+ ```
3167
+
3168
+ But the following code is not valid:
3169
+
3170
+ ```ruby
3171
+ [8].shared w: 0
3172
+
3173
+ par(clk.posedge) { w <= w + 1 }
3174
+ ```
3175
+
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
+
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
+
3180
+ ```ruby
3181
+ <shared signal>.select
3182
+ ```
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 following code can be added after this signal is declared:
3185
+
3186
+ ```ruby
3187
+ x.select <= 1
3188
+ ```
3189
+
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
+
3192
+ ```ruby
3193
+ par(clk.posedge) { x.select <= x.select + 1 }
3194
+ ```
3195
+
3196
+ __Note__: this select sub signal is a standard RTL signal that has the same properties and limitations as the other ones, i.e., this is not a shared signal itself.
3197
+
3198
+
3199
+ #### Arbiters
3200
+
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
+
3203
+ ```ruby
3204
+ arbiter(:<name>).(<list of shared signal>)
3205
+ ```
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 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
+
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
+
3211
+ ```ruby
3212
+ input :clk, :start
3213
+ [8].shared x, y
3214
+ arbiter(:ctrl_xy).(x,y)
3215
+
3216
+ sequencer(clk.posedge,start) do
3217
+ ctrl_xy <= 1
3218
+ x <= 0 ; y <= 0
3219
+ 5.stime do |i|
3220
+ x <= x + 1
3221
+ y <= y + 2
3222
+ end
3223
+ ctrl_xy <= 0
3224
+ end
3225
+
3226
+ sequencer(clk.posedge,start) do
3227
+ ctrl_xy <= 1
3228
+ x <= 2; y <= 1
3229
+ 10.stime do |i|
3230
+ x <= x + 2
3231
+ y <= y + 1
3232
+ end
3233
+ ctrl_xy <= 0
3234
+ end
3235
+ ```
3236
+
3237
+ In the example, both sequencers require access to signals `x` and `y` before accessing them and then releasing the access.
3238
+
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
+
3242
+ ```ruby
3243
+ hif(ctrl_xy.acquired) { x <= x + 1 }
3244
+ ```
2853
3245
 
2854
- ## Fixed-point (fixpoint)
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
+
3248
+ ```ruby
3249
+ ctrl_xy.policy([1,0])
3250
+ ```
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 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
+
3254
+ ```ruby
3255
+ inner priority_xy: 0
3256
+ inner grant_xy
3257
+ ctrl_xy.policy do |acq|
3258
+ hcase(acq)
3259
+ hwhen(_b01) do
3260
+ grant_xy <= 0
3261
+ priority_xy <= ~priority_xy
3262
+ end
3263
+ hwhen(_b10) do
3264
+ grant_xy <= 1
3265
+ priority_xy <= ~priority_xy
3266
+ end
3267
+ hwhen(_b11) do
3268
+ grant_xy <= priority_xy
3269
+ priority_xy <= ~priority_xy
3270
+ end
3271
+ grant_xy
3272
+ end
3273
+ ```
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 corresponds to sequencer 0, bit 1 to sequencer 1 and so on.
3276
+
3277
+
3278
+ #### Monitors
3279
+
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
+
3282
+ The monitor component is instantiated like the arbiters as follows:
3283
+
3284
+ ```ruby
3285
+ monitor(:<name>).(<list of shared signals>)
3286
+ ```
3287
+
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
+
3290
+ ```ruby
3291
+ monitor(:ctrl_xy).(x,y)
3292
+ ```
3293
+
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
+
3296
+ ```ruby
3297
+ input :clk, :start
3298
+ [8].shared x, y
3299
+ monitor(:ctrl_xy).(x,y)
3300
+
3301
+ sequencer(clk.posedge,start) do
3302
+ ctrl_xy.lock
3303
+ x <= 0 ; y <= 0
3304
+ 5.stime do |i|
3305
+ x <= x + 1
3306
+ y <= y + 2
3307
+ end
3308
+ ctrl_xy.unlock
3309
+ end
3310
+
3311
+ sequencer(clk.posedge,start) do
3312
+ ctrl_xy.lock
3313
+ x <= 2; y <= 1
3314
+ 10.stime do |i|
3315
+ x <= x + 2
3316
+ y <= y + 1
3317
+ end
3318
+ ctrl_xy.unlock
3319
+ end
3320
+ ```
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
+
3382
+ ## Fixed-point (fixpoint): `std/fixpoint.rb`
2855
3383
  <a name="fixpoint"></a>
2856
3384
 
2857
3385
  This library provides a new fixed point set of data types. These new data types can be bit vectors, unsigned or signed values and are declared respectively as follows:
@@ -2876,14 +3404,14 @@ In addition to the fixed point data type, a method is added to the literal objec
2876
3404
  <litteral>.to_fix(<number of bits after the decimal point>)
2877
3405
  ```
2878
3406
 
2879
- For example, the following code converts a floating-point value to a fixed point value with 16 bits after the decimal point:
3407
+ For example, the following code converts a floating-point value to a fixed-point value with 16 bits after the decimal point:
2880
3408
 
2881
3409
  ```
2882
3410
  3.178.to_fix(16)
2883
3411
  ```
2884
3412
 
2885
3413
 
2886
- ## Channel
3414
+ ## Channel: `std/channel.rb`
2887
3415
  <a name="channel"></a>
2888
3416
 
2889
3417
  This library provides a unified interface to complex communication protocols through a new kind of component called the channels that abstract the details of communication protocols. The channels can be used similarly to the ports of a system and are used through a unified interface so that changing the kind of channel, i.e., the communication protocol, does not require any modification of the code.
@@ -2923,9 +3451,9 @@ The access points to a channel can also be handled individually by declaring por
2923
3451
  * `output <name>`: declares a port for writing to the channel and associates them to `name` if any
2924
3452
  * `inout <name>`: declares a port for reading and writing to the channel and associates them to `name` if any
2925
3453
 
2926
- Such port can then be accessed using the same `read` and `write` method of a channel, the difference being that they can also be configured for new access procedures using the `wrap` method:
3454
+ Such a port can then be accessed using the same `read` and `write` method of a channel, the difference being that they can also be configured for new access procedures using the `wrap` method:
2927
3455
 
2928
- * `wrap(<args>) <code>`: creates a new port whose read or write procedure has the elements of `<args>` and the ones produced by `<code>` assign to the arguments of the read or write procedure.
3456
+ * `wrap(<args>) <code>`: creates a new port whose read or write procedure has the elements of `<args>` and the ones produced by `<code>` assigned to the arguments of the read or write procedure.
2929
3457
 
2930
3458
  For example, assuming `mem` is a channel whose read and write access have as argument the target address and data signals, the following code creates a port for always accessing at address 0:
2931
3459
 
@@ -2939,7 +3467,7 @@ Some channels may include several branches, they are accessed by name using the
2939
3467
 
2940
3468
  * `branch(<name>)`: gets branch named `name` from the channel. This name can be any ruby object (e.g., a number) but it will be converted internally to a ruby symbol.
2941
3469
 
2942
- A branch is a full-fledge channel and is used identically. For instance, the following code gets access to branch number 0 of channel `ch`, gets its inputs port, reads it, and put the result in signal `val` on the rising edges of signal `clk`:
3470
+ A branch is a full-fledged channel and is used identically. For instance, the following code gets access to branch number 0 of channel `ch`, gets its inputs port, reads it, and put the result in signal `val` on the rising edges of signal `clk`:
2943
3471
 
2944
3472
  ```ruby
2945
3473
  br = ch.branch(0)
@@ -3061,17 +3589,18 @@ end
3061
3589
 
3062
3590
  __Note__:
3063
3591
 
3064
- * The code of the circuits, in the examples `producer8`, `consumer8`, and `producer_consummer8` is independent of the content of the channel. For example, the sample `with_channel.rb` (please see [sample](#sample)) use the same circuits with a channel implementing handshaking.
3592
+ * The code of the circuits, in the examples `producer8`, `consumer8`, and `producer_consummer8` is independent of the content of the channel. For example, the sample `with_channel.rb` (please see [samples](#sample-hdlruby-descriptions)) uses the same circuits with a channel implementing handshaking.
3065
3593
 
3594
+ <!---
3066
3595
 
3067
3596
  ## Pipeline
3068
3597
  <a name="pipeline"></a>
3069
3598
 
3070
3599
  This library provides a construct for an easy description of pipeline architectures.
3071
3600
 
3601
+ -->
3072
3602
 
3073
3603
  # Sample HDLRuby descriptions
3074
- <a name="sample"></a>
3075
3604
 
3076
3605
  Several samples HDLRuby descriptions are available in the following directory:
3077
3606
 
@@ -3079,15 +3608,22 @@ path/to/HDLRuby/lib/HDLRuby/hdr\_samples
3079
3608
 
3080
3609
  For the gem install, the path to HDLRuby can be found using the following:
3081
3610
 
3082
- ```
3611
+ ```bash
3083
3612
  gem which HDLRuby
3084
3613
  ```
3085
3614
 
3615
+ But you can also import the samples to your local directory with the following command (recommended):
3616
+
3617
+ ```bash
3618
+ hdrcc --get-samples
3619
+ ```
3620
+
3086
3621
  The naming convention of the samples is the following:
3087
3622
 
3088
3623
  * `<name>.rb`: default type of sample.
3089
3624
  * `<name>_gen.rb`: generic parameters are required for processing the sample.
3090
3625
  * `<name>_bench.rb`: sample including a simulation benchmark, these are the only samples that can be simulated using `hdrcc -S`. Please notice that such a sample cannot be converted to VHDL or Verilog HDL yet.
3626
+ * `with_<name>.rb`: sample illustrating a single aspect of HDLRuby or one of its library, usually includes a benchmark.
3091
3627
 
3092
3628
 
3093
3629
  # Contributing
@@ -3097,10 +3633,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/civol/
3097
3633
 
3098
3634
  # To do
3099
3635
 
3100
- * Test the compatibility of the HDLRuby framework with the Microsoft Windows environments.
3101
- * Add the generation of VHDL and Verilog code for the time behaviors.
3102
- * Provide targets for the `Reconf` library.
3103
- * Add a standard wave output for the simulator.
3104
3636
  * Find and fix the (maybe) terrifying number of bugs.
3105
3637
  * Add a GUI (any volunteer to do it?).
3106
3638