HDLRuby 2.11.12 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/README.html +3274 -0
  3. data/README.md +556 -84
  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/mei8_bench.rb +1 -1
  8. data/lib/HDLRuby/hdr_samples/with_bram.rb +3 -3
  9. data/lib/HDLRuby/hdr_samples/with_bram_frame_stack.rb +105 -0
  10. data/lib/HDLRuby/hdr_samples/with_bram_stack.rb +69 -0
  11. data/lib/HDLRuby/hdr_samples/with_register_stack.rb +150 -0
  12. data/lib/HDLRuby/hdr_samples/with_sequencer.rb +190 -0
  13. data/lib/HDLRuby/hdr_samples/with_sequencer_deep.rb +91 -0
  14. data/lib/HDLRuby/hdr_samples/with_sequencer_enumerable.rb +405 -0
  15. data/lib/HDLRuby/hdr_samples/with_sequencer_enumerator.rb +89 -0
  16. data/lib/HDLRuby/hdr_samples/with_sequencer_sync.rb +120 -0
  17. data/lib/HDLRuby/hdrcc.rb +15 -2
  18. data/lib/HDLRuby/hdrlib.rb +1 -1
  19. data/lib/HDLRuby/hruby_db.rb +2 -2
  20. data/lib/HDLRuby/hruby_high.rb +38 -20
  21. data/lib/HDLRuby/hruby_high_fullname.rb +3 -1
  22. data/lib/HDLRuby/hruby_low.rb +2 -2
  23. data/lib/HDLRuby/hruby_low2c.rb +58 -43
  24. data/lib/HDLRuby/hruby_low2hdr.rb +66 -40
  25. data/lib/HDLRuby/hruby_low2high.rb +86 -44
  26. data/lib/HDLRuby/hruby_low2seq.rb +26 -18
  27. data/lib/HDLRuby/hruby_low2sym.rb +14 -13
  28. data/lib/HDLRuby/hruby_low2vhd.rb +78 -43
  29. data/lib/HDLRuby/hruby_low_bool2select.rb +61 -46
  30. data/lib/HDLRuby/hruby_low_casts_without_expression.rb +56 -44
  31. data/lib/HDLRuby/hruby_low_cleanup.rb +18 -16
  32. data/lib/HDLRuby/hruby_low_fix_types.rb +64 -32
  33. data/lib/HDLRuby/hruby_low_mutable.rb +53 -118
  34. data/lib/HDLRuby/hruby_low_resolve.rb +26 -31
  35. data/lib/HDLRuby/hruby_low_with_bool.rb +33 -16
  36. data/lib/HDLRuby/hruby_low_with_port.rb +3 -3
  37. data/lib/HDLRuby/hruby_low_with_var.rb +23 -9
  38. data/lib/HDLRuby/hruby_low_without_concat.rb +19 -13
  39. data/lib/HDLRuby/hruby_low_without_namespace.rb +47 -32
  40. data/lib/HDLRuby/hruby_low_without_parinseq.rb +18 -12
  41. data/lib/HDLRuby/hruby_low_without_select.rb +36 -23
  42. data/lib/HDLRuby/hruby_low_without_subsignals.rb +29 -28
  43. data/lib/HDLRuby/hruby_rcsim.rb +79 -64
  44. data/lib/HDLRuby/hruby_rsim.rb +64 -15
  45. data/lib/HDLRuby/hruby_rsim_mute.rb +2 -3
  46. data/lib/HDLRuby/hruby_rsim_vcd.rb +28 -25
  47. data/lib/HDLRuby/hruby_values.rb +13 -2
  48. data/lib/HDLRuby/hruby_verilog.rb +90 -48
  49. data/lib/HDLRuby/soft/stacks.rb +219 -0
  50. data/lib/HDLRuby/std/bram.rb +9 -5
  51. data/lib/HDLRuby/std/clocks.rb +1 -1
  52. data/lib/HDLRuby/std/fsm.rb +29 -9
  53. data/lib/HDLRuby/std/sequencer.rb +1857 -0
  54. data/lib/HDLRuby/std/sequencer_sync.rb +400 -0
  55. data/lib/HDLRuby/std/std.rb +12 -0
  56. data/lib/HDLRuby/version.rb +1 -1
  57. data/tuto/adder_sat_flags_vcd.png +0 -0
  58. data/tuto/addsub_vcd.png +0 -0
  59. data/tuto/alu_vcd.png +0 -0
  60. data/tuto/bit_pong_vcd.png +0 -0
  61. data/tuto/checksum_vcd.png +0 -0
  62. data/tuto/circuit_hdr.odg +0 -0
  63. data/tuto/circuit_hdr.png +0 -0
  64. data/tuto/circuit_hie.odg +0 -0
  65. data/tuto/circuit_hie.png +0 -0
  66. data/tuto/circuit_view.odg +0 -0
  67. data/tuto/circuit_view.png +0 -0
  68. data/tuto/clock_counter_vcd.png +0 -0
  69. data/tuto/counter_ext_vcd.png +0 -0
  70. data/tuto/fact_vcd.png +0 -0
  71. data/tuto/hw_flow.odg +0 -0
  72. data/tuto/hw_flow.png +0 -0
  73. data/tuto/maxxer_vcd.png +0 -0
  74. data/tuto/pingpong0_vcd.png +0 -0
  75. data/tuto/pingpong1_vcd.png +0 -0
  76. data/tuto/pingpong2_vcd.png +0 -0
  77. data/tuto/ram_vcd.png +0 -0
  78. data/tuto/serializer_vcd.png +0 -0
  79. data/tuto/sw_flow.odg +0 -0
  80. data/tuto/sw_flow.png +0 -0
  81. data/tuto/the_counter_vcd.png +0 -0
  82. data/tuto/tutorial_sw.html +2359 -0
  83. data/tuto/tutorial_sw.md +2684 -0
  84. data/tuto/tutorial_sw.pdf +0 -0
  85. data/tuto/tutorial_sw_jp.md +417 -0
  86. metadata +44 -2
data/README.md CHANGED
@@ -3,6 +3,25 @@
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.0.0:
15
+
16
+ * This section;
17
+
18
+ * [The sequencers](#sequencer-software-like-hardware-coding-stdsequencerrb) for software-like hardware design;
19
+
20
+ * A [tutorial](tuto/tutorial_sw.md) for software people;
21
+
22
+ * The stable [standard libraries](#standard-libraries) are loaded by default.
23
+
24
+
6
25
  __Install__:
7
26
 
8
27
  The recommended installation method is from rubygem as follows:
@@ -20,14 +39,14 @@ git clone HDLRuby
20
39
  __Warning__:
21
40
 
22
41
  - This is still preliminary work which may change before we release a stable version.
23
- - It is highly recommended to have both basic knowledges of the Ruby language and hardware description languages before using HDLRuby.
42
+ - It is highly recommended to have both basic knowledge of the Ruby language and hardware description languages before using HDLRuby.
24
43
 
25
44
 
26
45
  # Compiling HDLRuby descriptions
27
46
 
28
47
  ## Using the HDLRuby compiler
29
48
 
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.
49
+ '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
50
 
32
51
 
33
52
  __Usage__:
@@ -49,68 +68,76 @@ Where:
49
68
  | `-v, --verilog` | Output in Verilog HDL format |
50
69
  | `-V, --vhdl` | Output in VHDL format |
51
70
  | `-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. |
71
+ | `-C, --clang` | Output the C code of the standalone simulator |
72
+ | `-S, --sim` | Perform the simulation with the default engine |
73
+ | `--csim` | Perform the simulation with the standalone engine |
74
+ | `--rsim` | Perform the simulation with the Ruby engine |
75
+ | `--rcsim` | Perform the simulation with the Hybris engine |
57
76
  | `--vcd` | Make the simulator generate a VCD file |
58
77
  | `-d, --directory` | Specify the base directory for loading the HDLRuby files |
59
78
  | `-D, --debug` | Set the HDLRuby debug mode |
60
79
  | `-t, --top system`| Specify the top system describing the circuit to compile |
61
80
  | `-p, --param x,y,z` | Specify the generic parameters |
62
- | `--version ` | Print the version number, then exit |
81
+ | `--get-samples` | Copy the sample directory (hdr_samples) to current one, then exit |
82
+ | `--version` | Show the version number, then exit |
63
83
  | `-h, --help` | Show the help message |
64
84
 
65
85
  __Notes__:
66
86
 
67
87
  * If no top system is given, it is automatically looked for from the input file.
68
88
  * 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.
89
+ * 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:
90
+
91
+ ```bash
92
+ hdrcc --get-samples
93
+ ```
94
+
95
+ Then in your current directory (folder) the `hdr_samples` subdirectory will appear that contains several HDLRuby example files. For details about the samples can be found there: [samples](#sample-hdlruby-descriptions).
96
+
70
97
 
71
98
  __Examples__:
72
99
 
73
100
  * Compile system named `adder` from `adder.rb` input file and generate a low-level YAML description into directory `adder`:
74
101
 
75
- ```
102
+ ```bash
76
103
  hdrcc --yaml --top adder adder.rb adder
77
104
  ```
78
105
 
79
106
  * Compile `adder.rb` input file and generate a low-level Verilog HDL description into directory `adder`:
80
107
 
81
- ```
108
+ ```bash
82
109
  hdrcc -v adder.rb adder
83
110
  ```
84
111
 
85
112
  * 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
113
 
87
- ```
114
+ ```bash
88
115
  hdrcc -V -t adder --param 16 adder_gen.rb adder
89
116
  ```
90
117
 
91
118
  * 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
119
 
93
- ```
120
+ ```bash
94
121
  hdrcc -y -t multer -p 16,16,32 multer_gen.rb multer
95
122
  ```
96
123
 
97
- * Simulate the circuit described in file `counter_bench.rb` using the default simluation engine and putting the simulator's files in directory `counter`:
124
+ * Simulate the circuit described in file `counter_bench.rb` using the default simulation engine and putting the simulator's files in directory `counter`:
98
125
 
99
- ```
126
+ ```bash
100
127
  hdrcc -S counter_bench.rb counter
101
128
  ```
102
129
 
103
- As a policy, the default simulation enigne is set to the fastest one (cuttently it is the hybrid engine).
130
+ As a policy, the default simulation engine is set to the fastest one (currently it is the hybrid engine).
104
131
 
105
132
  * Run in interactive mode.
106
133
 
107
- ```
134
+ ```bash
108
135
  hdrcc -I
109
136
  ```
110
137
 
111
138
  * Run in interactive mode using pry as UI.
112
139
 
113
- ```
140
+ ```bash
114
141
  hdrcc -I pry
115
142
  ```
116
143
 
@@ -166,13 +193,13 @@ The second specificity of HDLRuby is that it supports natively all the features
166
193
 
167
194
  __Notes__:
168
195
 
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.
196
+ - 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
197
  - In this document, HDLRuby constructs will often be compared to their Verilog HDL or VHDL equivalents for simpler explanations.
171
198
 
172
199
  ## Introduction
173
200
 
174
201
  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.
202
+ 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
203
 
177
204
  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
205
 
@@ -187,7 +214,7 @@ system :dff do
187
214
  end
188
215
  ```
189
216
 
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).
217
+ 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
218
 
192
219
  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
220
 
@@ -195,7 +222,7 @@ After such a system has been defined, it can be instantiated. For example, a sin
195
222
  dff :dff0
196
223
  ```
197
224
 
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.
225
+ 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
226
 
200
227
  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
228
 
@@ -230,7 +257,7 @@ system :counter2 do
230
257
  end
231
258
  ```
232
259
 
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.
260
+ In the code above, two possible connection methods are shown: for `dff0` ports are connected by name, and for `dff1` ports are connected by declaration order. Please notice that it is also possible to connect only a subset of the ports while declaring, and to reconnect already connected ports in further statements.
234
261
 
235
262
  While a circuit can be generated from the code given above, a benchmark must
236
263
  be provided to test it. Such a benchmark is described by constructs called
@@ -285,8 +312,7 @@ end
285
312
  ```
286
313
 
287
314
  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:
315
+ In such a case, the system declaration can be omitted, and an instance can be directly declared as follows:
290
316
 
291
317
  ```ruby
292
318
  instance :dff_single do
@@ -395,7 +421,7 @@ system :shifter do |n|
395
421
  end
396
422
  ```
397
423
 
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.)
424
+ 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
425
 
400
426
  ```ruby
401
427
  <type>.<direction> <list of symbols representing the signal>
@@ -430,7 +456,7 @@ system :sumprod_16_3456 do
430
456
  end
431
457
  ```
432
458
 
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:
459
+ 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
460
 
435
461
  ```ruby
436
462
  system :sumprod do |typ,coefs|
@@ -446,7 +472,7 @@ end
446
472
  In the code above, there are two generic parameters,
447
473
  `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
474
 
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`.
475
+ 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
476
 
451
477
  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
478
 
@@ -456,7 +482,7 @@ sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit
456
482
 
457
483
  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
484
 
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:
485
+ While the description `sumprod` is already usable in a wide range of cases, it still uses standard addition and multiplication. However, there are cases where specific components are to be used for these operations, either for sake of performance, compliance with constraints, or because functionally different operations are required (e.g., saturated computations). This can be solved by using functions implementing such computation in place of operators, for example as follows:
460
486
 
461
487
  ```ruby
462
488
  system :sumprod_func do |typ,coefs|
@@ -502,7 +528,7 @@ end
502
528
 
503
529
  It would however be necessary to add this argument when invoking the function, e.g., `add(1000,sum,mult(...))`. While this argument is relevant for addition with saturation, it is not for the other kind of addition operations, and hence, the code of `sumprod` is not general-purpose any longer.
504
530
 
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:
531
+ 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
532
 
507
533
  ```ruby
508
534
  system :sumprod_proc do |add,mult,typ,coefs|
@@ -625,10 +651,10 @@ From there, we will describe in more detail each construct of HDLRuby.
625
651
  ## Naming rules
626
652
  <a name="names"></a>
627
653
 
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.
654
+ 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
655
 
630
656
  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`.
657
+ has been declared with `:hello` as the name, it will be afterward referred to by `hello`.
632
658
 
633
659
  ## Systems and signals
634
660
 
@@ -650,7 +676,7 @@ __Notes__:
650
676
  Ruby keywords (in which case the parentheses can be omitted) are as follows:
651
677
 
652
678
  ```ruby
653
- system :box do
679
+ system :box does
654
680
  end
655
681
  ```
656
682
 
@@ -921,7 +947,7 @@ Where:
921
947
  * `<name>` is the name of the scope.
922
948
  * `<code>` is the code within the scope.
923
949
 
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`:
950
+ 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
951
 
926
952
  ```ruby
927
953
  sub :scop do
@@ -948,7 +974,7 @@ end
948
974
  In addition, it is possible to declare inner signals within an execution block.
949
975
  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
976
 
951
- An event represents a specific change of state of a signal.
977
+ An event represents a specific change in the state of a signal.
952
978
  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
979
  expressions using the following methods: `posedge` for a rising edge, `negedge` for a falling edge, and `edge` for any edge.
954
980
  Events are described in more detail in section [Events](#events).
@@ -989,7 +1015,7 @@ system :with_sequential_behavior do
989
1015
  end
990
1016
  ```
991
1017
 
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:
1018
+ 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
1019
 
994
1020
  ```ruby
995
1021
  system :with_sequential_behavior do
@@ -1002,7 +1028,7 @@ system :with_sequential_behavior do
1002
1028
  end
1003
1029
  ```
1004
1030
 
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
1031
+ Sunblocks have their scope so that it is possible to declare signals without colliding with existing ones. For example, it is possible to
1006
1032
  declare three different inner signals all called `sig` as follows:
1007
1033
 
1008
1034
  ```ruby
@@ -1117,7 +1143,7 @@ unshift do
1117
1143
  end
1118
1144
  ```
1119
1145
 
1120
- For example the following code inserts two statements at the beginning of the current block:
1146
+ For example, the following code inserts two statements at the beginning of the current block:
1121
1147
 
1122
1148
  ```ruby
1123
1149
  par do
@@ -1129,7 +1155,7 @@ par do
1129
1155
  end
1130
1156
  ```
1131
1157
 
1132
- The code above will actually result in the following block:
1158
+ The code above will result in the following block:
1133
1159
 
1134
1160
  ```ruby
1135
1161
  par do
@@ -1151,7 +1177,7 @@ In HDLRuby, dynamically reconfigurable devices are modeled by instances having m
1151
1177
  <instance>.choice(<list of named systems>)
1152
1178
  ```
1153
1179
 
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):
1180
+ 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
1181
 
1156
1182
  ```ruby
1157
1183
  sys0 :dev012 # dev012 is at first a standard instance of sys0
@@ -1183,9 +1209,8 @@ These reconfiguration commands are treated as regular RTL statements in HDLRuby
1183
1209
 
1184
1210
 
1185
1211
  ## Events
1186
- <a name="events"></a>
1187
1212
 
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.
1213
+ 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
1214
 
1190
1215
  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
1216
  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 +1236,6 @@ __Note:__
1211
1236
  - The `change` keyword can be omitted.
1212
1237
 
1213
1238
  ## Statements
1214
- <a name="statements"></a>
1215
1239
 
1216
1240
  Statements are the basic elements of a behavioral description. They are regrouped in blocks that specify their execution mode (parallel or sequential).
1217
1241
  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 +1248,7 @@ __Note__:
1224
1248
 
1225
1249
  ### Transmit statement
1226
1250
 
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.
1251
+ 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
1252
 
1229
1253
  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
1254
 
@@ -1282,7 +1306,7 @@ end
1282
1306
 
1283
1307
  ### helsif
1284
1308
 
1285
- In addition to `helse` it is possible to set additional conditions to an `hif` using the `helsif` keyword as follows:
1309
+ In addition to `helse`, it is possible to set additional conditions to an `hif` using the `helsif` keyword as follows:
1286
1310
 
1287
1311
  ```ruby
1288
1312
  hif <condition 0> do
@@ -1416,11 +1440,10 @@ While the underlying structure of any HDLRuby type is the bit vector, complex ty
1416
1440
  <a name="expressions"></a>
1417
1441
 
1418
1442
  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).
1443
+ They include [immediate values](#immediate-values), [reference to signals](#references) and operations among other expressions using [expression operators](#expression-operators).
1420
1444
 
1421
1445
 
1422
1446
  ### Immediate values
1423
- <a name="values"></a>
1424
1447
 
1425
1448
  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
1449
 
@@ -1475,7 +1498,6 @@ __Notes__:
1475
1498
 
1476
1499
 
1477
1500
  ### References
1478
- <a name="references"></a>
1479
1501
 
1480
1502
  References are expressions used to designate signals or a part of signals.
1481
1503
 
@@ -1517,7 +1539,6 @@ end
1517
1539
  ```
1518
1540
 
1519
1541
  ### Expression operators
1520
- <a name="operators"></a>
1521
1542
 
1522
1543
  The following table gives a summary of the operators available in HDLRuby.
1523
1544
  More details are given for each group of operators in the subsequent sections.
@@ -1594,10 +1615,9 @@ __Notes__:
1594
1615
 
1595
1616
  - The operator precedence is the one of Ruby.
1596
1617
 
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.
1618
+ - Ruby does not allow to override the `&&`, the `||` and the `?:` operators so that they are not present in HDLRuby. Instead of the `?:` operator, HDLRuby provides the more general multiplex operator `mux`. However, HDLRuby does not provide any replacement for the `&&` and the `||` operators, please refer to section [Logic operators](#logic-and-shift-operators) for a justification about this issue.
1598
1619
 
1599
1620
  #### Assignment operators
1600
- <a name="assignment"></a>
1601
1621
 
1602
1622
  The assignment operators can be used with any type. They are the connection and the transmission operators both being represented by `<=`.
1603
1623
 
@@ -1625,7 +1645,6 @@ __Notes__:
1625
1645
 
1626
1646
 
1627
1647
  #### Logic and shift operators
1628
- <a name="logic"></a>
1629
1648
 
1630
1649
  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
1650
 
@@ -1651,11 +1670,10 @@ sig.rl(3)
1651
1670
  ```
1652
1671
 
1653
1672
  It is possible to perform other kinds of shifts or rotations using the selection and the concatenation operators. Please refer to section [Concatenation and
1654
- selection operators](#concat) for more details about these operators.
1673
+ selection operators](#concatenation-and-selection-operators) for more details about these operators.
1655
1674
 
1656
1675
 
1657
1676
  #### Conversion operators
1658
- <a name="conversion"></a>
1659
1677
 
1660
1678
  The conversion operators are used to change the type of an expression.
1661
1679
  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.
@@ -1667,7 +1685,7 @@ The type puns include `to_bit`, `to_unsigned` and `to_signed` that convert expre
1667
1685
  sig.to_bit <= _b01010011
1668
1686
  ```
1669
1687
 
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)).
1688
+ 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
1689
  These operators comprise the bit width conversions: `ljust`, `rjust`, `zext` and `sext`.
1672
1690
 
1673
1691
  More precisely, the bit width conversions operate as follows:
@@ -1701,7 +1719,6 @@ More precisely, the bit width conversions operate as follows:
1701
1719
 
1702
1720
 
1703
1721
  #### Concatenation and selection operators
1704
- <a name="concat"></a>
1705
1722
 
1706
1723
  Concatenation and selection are done using the `[]` operator as follows:
1707
1724
 
@@ -1912,7 +1929,6 @@ Ruby functions can be compared to the macros of the C languages: they are more f
1912
1929
 
1913
1930
 
1914
1931
  ## Time
1915
- <a name="time"></a>
1916
1932
 
1917
1933
  ### Time values
1918
1934
  <a name="time_val"></a>
@@ -1987,7 +2003,6 @@ sequential blocks. The execution semantic is the following:
1987
2003
 
1988
2004
 
1989
2005
  ## High-level programming features
1990
- <a name="highfeat"></a>
1991
2006
 
1992
2007
  ### Using Ruby in HDLRuby
1993
2008
 
@@ -2525,7 +2540,6 @@ When describing a system, it is possible to disconnect or completely undefine a
2525
2540
 
2526
2541
 
2527
2542
  ## Extending HDLRuby
2528
- <a name="extend"></a>
2529
2543
 
2530
2544
  Like any Ruby classes, the constructs of HDLRuby can be dynamically extended. If it is not recommended to change their internal structure, it is possible to add methods to them for an extension.
2531
2545
 
@@ -2653,8 +2667,7 @@ This way, calling directly `to_low` will automatically use `my_generation`.
2653
2667
 
2654
2668
 
2655
2669
 
2656
- # Standard library
2657
- <a name="library"></a>
2670
+ # Standard libraries
2658
2671
 
2659
2672
  The standard libraries are included in the module `Std`.
2660
2673
  They can be loaded as follows, where `<library name>` is the name of the
@@ -2670,9 +2683,23 @@ After the libraries are loaded, the module `Std` must be included as follows:
2670
2683
  include HDLRuby::High::Std
2671
2684
  ```
2672
2685
 
2686
+ > However, `hdrcc` does load the stable components of the standard library by default, so that you do not need to require nor include anything more to use them. In the current version, the stable components are the followings:
2687
+
2688
+ - `std/clocks.rb`
2689
+
2690
+ - `std/fixpoint.rb`
2691
+
2692
+ - `std/decoder.rb`
2673
2693
 
2694
+ - `std/fsm.rb`
2674
2695
 
2675
- ## Clocks
2696
+ - `std/sequencer.rb`
2697
+
2698
+ - `std/sequencer_sync.rb`
2699
+
2700
+
2701
+
2702
+ ## Clocks: `std/clocks.rb`
2676
2703
  <a name="clocks"></a>
2677
2704
 
2678
2705
  The `clocks` library provides utilities for easier handling of clock synchronizations.
@@ -2694,7 +2721,7 @@ end
2694
2721
 
2695
2722
  __Note__: this library does generate all the RTL code for the circuit handling the division of the frequency.
2696
2723
 
2697
- ## Counters
2724
+ ## Counters: `std/counters.rb`
2698
2725
  <a name="counters"></a>
2699
2726
 
2700
2727
  This library provides two new constructs for implementing synthesizable wait statements.
@@ -2711,12 +2738,12 @@ Where:
2711
2738
  * `<clock>` is the clock to use, this argument can be omitted.
2712
2739
  * `<reset>` is the signal used to reset the counter used for waiting, this argument can be omitted.
2713
2740
 
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.
2741
+ 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
2742
 
2716
2743
  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
2744
 
2718
2745
 
2719
- ## Decoder
2746
+ ## Decoder: `std/decoder.rb`
2720
2747
  <a name="decoder"></a>
2721
2748
 
2722
2749
  This library provides a new set of control statements for easily describing an instruction decoder.
@@ -2733,7 +2760,7 @@ Where `signal` is the signal to decode and `block` is a procedure block (i.e., R
2733
2760
  entry(<pattern>) <block>
2734
2761
  ```
2735
2762
 
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.
2763
+ Where `pattern` is a string describing the pattern to match the entry, and `block` is a procedure block describing the actions (some HDLRuby code) that are performed when the entry matches. The string describing the pattern can include `0` and `1` characters for specifying a specific value for the corresponding bit, or any alphabetical character for specifying a field in the pattern. The fields in the pattern can then be used by name in the block describing the action. When a letter is used several times within a pattern, the corresponding bits are concatenated and are used as a signal multi-bit signal in the block.
2737
2764
 
2738
2765
  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
2766
 
@@ -2746,12 +2773,12 @@ end
2746
2773
 
2747
2774
  It can be noticed for field `z` in the example above that the bits are not required to be contiguous.
2748
2775
 
2749
- ## FSM
2776
+ ## FSM: `std/fsm.rb`
2750
2777
  <a name="fsm"></a>
2751
2778
 
2752
2779
  This library provides a new set of control statements for easily describing a finite state machine (FSM).
2753
2780
 
2754
- A finite state machine can be declared anywhere provided it is outside a behavior using the `fsm` keyword as follows:
2781
+ A finite state machine can be declared anywhere in a system provided it is outside a behavior using the `fsm` keyword as follows:
2755
2782
 
2756
2783
  ```ruby
2757
2784
  fsm(<event>,<reset>,<mode>) <block>
@@ -2794,7 +2821,7 @@ goto(cond,:st_a,:st_b,:st_c)
2794
2821
 
2795
2822
  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
2823
 
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`):
2824
+ 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
2825
 
2799
2826
  ```ruby
2800
2827
  fsm(clk.posedge,rst,:sync) do
@@ -2818,7 +2845,7 @@ fsm(clk.posedge,rst,:sync) do
2818
2845
  end
2819
2846
  ```
2820
2847
 
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:
2848
+ __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
2849
 
2823
2850
  ```ruby
2824
2851
  state(:st_0) do
@@ -2837,7 +2864,7 @@ That is to say, for a conditional `goto` for `st_1` the code should have been wr
2837
2864
  end
2838
2865
  ```
2839
2866
 
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`:
2867
+ The use of `goto` makes the design of FSM shorter for a majority of the cases, be sometimes, a finer control is required. For that purpose, it is also possible to configure the FSM is `static` mode where the `next_state` statement that indicates implicitly the next state. Putting in static mode is done by passing `:static` as an argument when declaring the FSM. For example, the following FSM uses `next_state` to specify explicitly the next states depending on some condition signals `cond0` and `cond1`:
2841
2868
 
2842
2869
  ```ruby
2843
2870
  fsm(clk.posedge,rst,:static)
@@ -2850,8 +2877,449 @@ fsm(clk.posedge,rst,:static)
2850
2877
  end
2851
2878
  ```
2852
2879
 
2880
+ ## Sequencer (software-like hardware coding):: `std/sequencer.rb`
2881
+ <a name="sequencer"></a>
2882
+
2883
+ 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.
2884
+
2885
+ A sequencer can be declared anywhere in a system provided it is outside a behavior using the `sequencer` keyword as follows:
2886
+
2887
+ ```ruby
2888
+ sequencer(<clock>,<start>) <block>
2889
+ ```
2890
+
2891
+ 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`).
2892
+
2893
+ A sequence is a specific case of a `seq` block that includes the following software-like additional constructs:
2894
+
2895
+ - `step`: wait until the next event (given argument `event` of the sequencer).
2896
+
2897
+ - `sif(<condition>) <block>`: executes `block` if `condition` is met.
2898
+
2899
+ - `selsif(<condition>) <block>`: executes `block` if previous `sif` or `selsif` condition is not met and if 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 after the address is sets, 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 processes, It is not possible for several sequencers to write to the same signal. This is because there would be race competition that may destroy physically the device if such operations where authorized. In standard RTL design, this limitation is overcome by implementing three-state buses, multiplexers and arbiters. However, HDLRuby sequencers supports another kind of signals called the *shared signals* that abstract the implementation details for avoiding race competition.
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 declare 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 signals can then be read and written to by any sequencer from anywhere in the subsequent code of the current scope. However, they cannot be written to outside a sequencer. For example, the following code is valid:
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 acknowledge writing from the first sequencer that access it in order of declaration, the others are ignored. In the first example given above, that means for signal `x` the value is always the one written by the first sequencer, i.e., from 0 to 9 changing once per clock cycle. However, the value of signal `y` is set by the second sequencer since it is this one only that writes to this signal.
3177
+
3178
+ This default behavior of shared signal avoids race competition, but is not very useful in practice. For a better control, it is possible to select which sequencer is to be acknowledged for writing. This is done by setting the number of the sequencer which can write the signal that controls the sharing accessed as follows:
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 follow 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 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 drives. For example, in a CPU, it is an ALU that is shared as a whole rather than each of its input separately. In order to support such cases and ease the handling of shared signals, the library also provides the *arbiter* components. This component is instantiated like a standard module as follows, where `name` is the name of the arbiter instance:
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 returns, it provides the possibility of requiring or releasing access to the shared signals. Requiring access is done by sending the value 1 to the arbiter, and releasing is done by sending the value 0. If a sequencer writes to a shared signal under arbitration without requiring access first, the write will simply be ignored.
3208
+
3209
+ The following is an example of arbiter that controls access to shared signals `x` and `y` and two sequencers acquiring and releasing accesses to them:
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 guaranties that the access will be granted by the arbiter though. In the access is not granted, the write access will be ignored.
3240
+ The default access granting policy of an arbiter is the priority in order of sequencer declaration. I.e., if several sequencer are requiring at the same time, then the one declared the earliest in the code gains write access. For example, with the code given about, the first sequencer have write access to `x` and `y`, and since after five write cycles it releases access, the second sequencer can then write to these signals. However, not obtaining write access does not block the execution of the sequencer, simply, its write access to the corresponding shared signals is simple ignored. In the example, the second sequencer will do its first five loop cycles without any effect, and have only its five last ones that change the shared signals. To avoid such a behavior, it is possible to check if the write access is granted using arbiter sub signal `acquired`: if this signal is one in current sequencer, that means the access is granted, otherwise its is 0. For example the following will increase signal `x` only if write access is granted:
3241
+
3242
+ ```ruby
3243
+ hif(ctrl_xy.acquired) { x <= x + 1 }
3244
+ ```
3245
+
3246
+ The policy of an arbiter can be changed using command policy. You can either provide a new priority table, containing the number of the sequencers in order of priority (the first one having higher priority. The number of a sequencer is assign in order of declaration provided it uses the arbiter. For example, in the previous code, the second sequencer can be given higher priority by adding the following code after having declared the arbiter:
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 executing each time an write access is actually performed. For example, in the previous code, a policy switch priorities at each access can be implemented as follows:
2853
3253
 
2854
- ## Fixed-point (fixpoint)
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 corresponding to sequencer 0, bit 1 to sequencer 1 and so one.
3276
+
3277
+
3278
+ #### Monitors
3279
+
3280
+ Arbiters a especially useful when we can ensure that the sequencers accessing the same resource do not overlap or when the do not need to synchronize with each other. If such synchronizations are required, instead of arbiters, it is possible to use the *monitor* components.
3281
+
3282
+ The monitor component are 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 blocks the execution of the sequencers that require a write access until the access is granted. If we take the example of code with two sequencers given as illustration of arbiter usage, replacing the arbiter by a monitor as follows will lock the second sequencer until it can write to shared variables `x` and `y` ensuring that all its loop cycles have the specified result:
3289
+
3290
+ ```ruby
3291
+ monitor(:ctrl_xy).(x,y)
3292
+ ```
3293
+
3294
+ Since monitors locks processes, it automatically insert a step, hence to avoid confusion, aquiring access to a monitor is done by using method `lock` instead of assigning 1, and releasing is done by using method `unlock` instead of assigning 0. Hence, when using a monitor, the previous arbiter-based code should be rewriten as follows:
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
+ ## Fixed-point (fixpoint): `std/fixpoint.rb`
2855
3323
  <a name="fixpoint"></a>
2856
3324
 
2857
3325
  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 +3344,14 @@ In addition to the fixed point data type, a method is added to the literal objec
2876
3344
  <litteral>.to_fix(<number of bits after the decimal point>)
2877
3345
  ```
2878
3346
 
2879
- For example, the following code converts a floating-point value to a fixed point value with 16 bits after the decimal point:
3347
+ For example, the following code converts a floating-point value to a fixed-point value with 16 bits after the decimal point:
2880
3348
 
2881
3349
  ```
2882
3350
  3.178.to_fix(16)
2883
3351
  ```
2884
3352
 
2885
3353
 
2886
- ## Channel
3354
+ ## Channel: `std/channel.rb`
2887
3355
  <a name="channel"></a>
2888
3356
 
2889
3357
  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 +3391,9 @@ The access points to a channel can also be handled individually by declaring por
2923
3391
  * `output <name>`: declares a port for writing to the channel and associates them to `name` if any
2924
3392
  * `inout <name>`: declares a port for reading and writing to the channel and associates them to `name` if any
2925
3393
 
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:
3394
+ 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
3395
 
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.
3396
+ * `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
3397
 
2930
3398
  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
3399
 
@@ -2939,7 +3407,7 @@ Some channels may include several branches, they are accessed by name using the
2939
3407
 
2940
3408
  * `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
3409
 
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`:
3410
+ 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
3411
 
2944
3412
  ```ruby
2945
3413
  br = ch.branch(0)
@@ -3061,17 +3529,18 @@ end
3061
3529
 
3062
3530
  __Note__:
3063
3531
 
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.
3532
+ * 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
3533
 
3534
+ <!---
3066
3535
 
3067
3536
  ## Pipeline
3068
3537
  <a name="pipeline"></a>
3069
3538
 
3070
3539
  This library provides a construct for an easy description of pipeline architectures.
3071
3540
 
3541
+ -->
3072
3542
 
3073
3543
  # Sample HDLRuby descriptions
3074
- <a name="sample"></a>
3075
3544
 
3076
3545
  Several samples HDLRuby descriptions are available in the following directory:
3077
3546
 
@@ -3079,15 +3548,22 @@ path/to/HDLRuby/lib/HDLRuby/hdr\_samples
3079
3548
 
3080
3549
  For the gem install, the path to HDLRuby can be found using the following:
3081
3550
 
3082
- ```
3551
+ ```bash
3083
3552
  gem which HDLRuby
3084
3553
  ```
3085
3554
 
3555
+ But you can also import the samples to your local directory with the following command (recommended):
3556
+
3557
+ ```bash
3558
+ hdrcc --get-samples
3559
+ ```
3560
+
3086
3561
  The naming convention of the samples is the following:
3087
3562
 
3088
3563
  * `<name>.rb`: default type of sample.
3089
3564
  * `<name>_gen.rb`: generic parameters are required for processing the sample.
3090
3565
  * `<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.
3566
+ * `with_<name>.rb`: sample illustrating a single aspect of HDLRuby or one of its library, usually includes a benchmark.
3091
3567
 
3092
3568
 
3093
3569
  # Contributing
@@ -3097,10 +3573,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/civol/
3097
3573
 
3098
3574
  # To do
3099
3575
 
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
3576
  * Find and fix the (maybe) terrifying number of bugs.
3105
3577
  * Add a GUI (any volunteer to do it?).
3106
3578