HDLRuby 2.9.0 → 2.10.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +250 -230
- data/lib/HDLRuby/hdr_samples/dff_bench.rb +4 -1
- data/lib/HDLRuby/hdr_samples/dff_override.rb +76 -0
- data/lib/HDLRuby/hdr_samples/with_delay.rb +72 -0
- data/lib/HDLRuby/hdr_samples/with_handshake.rb +110 -0
- data/lib/HDLRuby/hdr_samples/with_values.rb +14 -0
- data/lib/HDLRuby/hdrcc.rb +73 -17
- data/lib/HDLRuby/hdrlib.rb +592 -0
- data/lib/HDLRuby/hruby_high.rb +172 -47
- data/lib/HDLRuby/hruby_low.rb +74 -50
- data/lib/HDLRuby/hruby_low2c.rb +1 -1
- data/lib/HDLRuby/hruby_low_mutable.rb +1 -1
- data/lib/HDLRuby/hruby_low_without_connection.rb +1 -0
- data/lib/HDLRuby/hruby_low_without_namespace.rb +2 -1
- data/lib/HDLRuby/sim/hruby_sim_calc.c +3 -2
- data/lib/HDLRuby/std/delays.rb +92 -0
- data/lib/HDLRuby/std/handshakes.rb +60 -0
- data/lib/HDLRuby/version.rb +1 -1
- metadata +8 -2
data/README.md
CHANGED
@@ -11,7 +11,7 @@ The recommended installation method is from rubygem as follows:
|
|
11
11
|
gem install HDLRuby
|
12
12
|
```
|
13
13
|
|
14
|
-
Developers willing to contribute to HDLRuby can install the sources from
|
14
|
+
Developers willing to contribute to HDLRuby can install the sources from GitHub as follows:
|
15
15
|
|
16
16
|
```
|
17
17
|
git clone HDLRuby
|
@@ -19,15 +19,15 @@ git clone HDLRuby
|
|
19
19
|
|
20
20
|
__Warning__:
|
21
21
|
|
22
|
-
- This is still preliminary work which may change
|
23
|
-
- It is highly recommended to have both basic
|
22
|
+
- 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.
|
24
24
|
|
25
25
|
|
26
26
|
# Compiling HDLRuby descriptions
|
27
27
|
|
28
28
|
## Using the HDLRuby compiler
|
29
29
|
|
30
|
-
'hdrcc' is the HDLRuby compiler. It takes as input
|
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.
|
31
31
|
|
32
32
|
|
33
33
|
__Usage__:
|
@@ -44,13 +44,14 @@ Where:
|
|
44
44
|
|
45
45
|
| Options | |
|
46
46
|
|:------------------|:-----------------------------------------------------|
|
47
|
+
| `-I, --interactive` | Run in interactive mode |
|
47
48
|
| `-y, --yaml` | Output in YAML format |
|
48
49
|
| `-v, --verilog` | Output in Verilog HDL format |
|
49
50
|
| `-V, --vhdl` | Output in VHDL format |
|
50
51
|
| `-s, --syntax` | Output the Ruby syntax tree |
|
51
52
|
| `-C, --clang` | Output the C code of the simulator |
|
52
53
|
| `-S, --sim` | Output the executable simulator and execute it |
|
53
|
-
| `--vcd` | Make the simulator generate a
|
54
|
+
| `--vcd` | Make the simulator generate a VCD file |
|
54
55
|
| `-d, --directory` | Specify the base directory for loading the HDLRuby files |
|
55
56
|
| `-D, --debug` | Set the HDLRuby debug mode |
|
56
57
|
| `-t, --top system`| Specify the top system describing the circuit to compile |
|
@@ -61,7 +62,7 @@ Where:
|
|
61
62
|
__Notes__:
|
62
63
|
|
63
64
|
* If no top system is given, it is automatically looked for from the input file.
|
64
|
-
* If no option is given, simply checks the input file.
|
65
|
+
* If no option is given, it simply checks the input file.
|
65
66
|
* The simulator option (-S) requires a standard compiler (accessible through the command `cc`) to be available in the executable path.
|
66
67
|
|
67
68
|
__Examples__:
|
@@ -97,68 +98,58 @@ hdrcc -y -t multer -p 16,16,32 multer_gen.rb multer
|
|
97
98
|
hdrcc -S counter_bench.rb counter
|
98
99
|
```
|
99
100
|
|
101
|
+
* Run in interactive mode.
|
100
102
|
|
101
|
-
|
103
|
+
```
|
104
|
+
hdrcc -I
|
105
|
+
```
|
102
106
|
|
103
|
-
|
107
|
+
* Run in interactive mode using pry as UI.
|
104
108
|
|
105
|
-
```
|
106
|
-
|
109
|
+
```
|
110
|
+
hdrcc -I pry
|
107
111
|
```
|
108
112
|
|
109
|
-
|
113
|
+
## Using HDLRuby in interactive mode
|
110
114
|
|
111
|
-
|
112
|
-
configure_high
|
113
|
-
```
|
115
|
+
When running in interactive mode, the HDLRuby framework starts a REPL prompt and creates a working directory called 'HDLRubyWorkspace'. By default, the REPL is 'irb', but it can be set to 'pry'. Within this prompt, HDLRuby code can be written like in an HDLRuby description file. However, to process this code the following commands are added:
|
114
116
|
|
115
|
-
|
116
|
-
from an instance of an HW module (*system* in HDLRuby).
|
117
|
-
For example, assuming system 'circuitT' has been described in your Ruby program, an instance named 'circuitI' can be declared as follows:
|
117
|
+
* Compile an HDLRuby module:
|
118
118
|
|
119
119
|
```ruby
|
120
|
-
|
120
|
+
hdr_make(<module>)
|
121
121
|
```
|
122
122
|
|
123
|
-
|
123
|
+
* Generate and display the IR of the compiled module in YAML form:
|
124
124
|
|
125
125
|
```ruby
|
126
|
-
|
126
|
+
hdr_yaml
|
127
127
|
```
|
128
128
|
|
129
|
-
|
129
|
+
* Regenerate and display the HDLRuby description of the compiled module:
|
130
130
|
|
131
131
|
```ruby
|
132
|
-
|
133
|
-
circuitV = circuitL.to_vhdl
|
132
|
+
hdr_hdr
|
134
133
|
```
|
135
134
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
## Handling the low-level HDLRuby representation
|
140
|
-
|
141
|
-
You can include `HDLRuby::Low` for gaining access to the classes used for low-level description of hardware components.
|
135
|
+
* Generate and output in the working directory the Verilog HDL RTL of the compiled module:
|
142
136
|
|
143
137
|
```ruby
|
144
|
-
|
138
|
+
hdr_verilog
|
145
139
|
```
|
146
140
|
|
147
|
-
|
141
|
+
* Generate and output in the working directory the Verilog HDL RTL of the compiled module:
|
148
142
|
|
149
143
|
```ruby
|
150
|
-
|
144
|
+
hdr_vhdl
|
151
145
|
```
|
152
146
|
|
153
|
-
|
147
|
+
* Simulate the compiled module:
|
154
148
|
|
155
149
|
```ruby
|
156
|
-
|
150
|
+
hdr_sim
|
157
151
|
```
|
158
152
|
|
159
|
-
__Note__:
|
160
|
-
|
161
|
-
- A `HDLRuby::Low` description of hardware can only be built through standard Ruby class constructors and does not include any validity check of the resulting hardware.
|
162
153
|
|
163
154
|
|
164
155
|
|
@@ -171,7 +162,7 @@ The second specificity of HDLRuby is that it supports natively all the features
|
|
171
162
|
|
172
163
|
__Notes__:
|
173
164
|
|
174
|
-
- It is still possible to extend HDLRuby to support hardware descriptions of higher level than RTL, please refer to section [Extending HDLRuby](#extend) for more details.
|
165
|
+
- 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.
|
175
166
|
- In this document, HDLRuby constructs will often be compared to their Verilog HDL or VHDL equivalents for simpler explanations.
|
176
167
|
|
177
168
|
## Introduction
|
@@ -179,7 +170,7 @@ __Notes__:
|
|
179
170
|
This introduction gives a glimpse of the possibilities of the language.
|
180
171
|
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.
|
181
172
|
|
182
|
-
At first glance, HDLRuby appears like any other HDL
|
173
|
+
At first glance, HDLRuby appears like any other HDL (like Verilog HDL or VHDL), for instance, the following code describes a simple D-FF:
|
183
174
|
|
184
175
|
```ruby
|
185
176
|
system :dff do
|
@@ -238,11 +229,11 @@ end
|
|
238
229
|
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.
|
239
230
|
|
240
231
|
While a circuit can be generated from the code given above, a benchmark must
|
241
|
-
be provided to test it. Such benchmark
|
242
|
-
timed behavior that give the evolution of signals depending
|
232
|
+
be provided to test it. Such a benchmark is described by constructs called
|
233
|
+
timed behavior that give the evolution of signals depending on the time.
|
243
234
|
For example, the following code simulates the previous D-FF for 4 cycles
|
244
|
-
of 20ns each, with reset on the first cycle, set of signal `d` to 1 for
|
245
|
-
the third cycle and set
|
235
|
+
of 20ns each, with a reset on the first cycle, set of signal `d` to 1 for
|
236
|
+
the third cycle and set this signal to 0 for the last.
|
246
237
|
|
247
238
|
```ruby
|
248
239
|
system :dff_bench do
|
@@ -276,9 +267,9 @@ end
|
|
276
267
|
|
277
268
|
---
|
278
269
|
|
279
|
-
The code describing a `dff` given above is not much different from its equivalent in any other HDL. However, HDLRuby provides several features for achieving
|
270
|
+
The code describing a `dff` given above is not much different from its equivalent in any other HDL. However, HDLRuby provides several features for achieving higher productivity when describing hardware. We will now describe a few of them.
|
280
271
|
|
281
|
-
First, several syntactic sugars exist that allow shorter code, for instance the following code is strictly equivalent to the previous description of `dff`:
|
272
|
+
First, several syntactic sugars exist that allow shorter code, for instance, the following code is strictly equivalent to the previous description of `dff`:
|
282
273
|
|
283
274
|
```ruby
|
284
275
|
system :dff do
|
@@ -342,7 +333,7 @@ system :reg do |typ|
|
|
342
333
|
end
|
343
334
|
```
|
344
335
|
|
345
|
-
Wait... I have just realized
|
336
|
+
Wait... I have just realized that D-FF without any inverted output does not look very serious. So, let us extend the existing `dff` to provide an inverted output. There are three ways for doing this. First, inheritance can be used: a new system is built inheriting from `dff` as it is done in the following code.
|
346
337
|
|
347
338
|
```ruby
|
348
339
|
system :dff_full, dff do
|
@@ -351,7 +342,7 @@ system :dff_full, dff do
|
|
351
342
|
end
|
352
343
|
```
|
353
344
|
|
354
|
-
The second possibility is to modify `dff` afterward. In HDLRuby, this achieved using the `open` method as it is done the following code:
|
345
|
+
The second possibility is to modify `dff` afterward. In HDLRuby, this is achieved using the `open` method as it is done in the following code:
|
355
346
|
|
356
347
|
```ruby
|
357
348
|
dff.open do
|
@@ -360,7 +351,7 @@ dff.open do
|
|
360
351
|
end
|
361
352
|
```
|
362
353
|
|
363
|
-
The third possibility is to modify directly a single instance of `dff` which
|
354
|
+
The third possibility is to modify directly a single instance of `dff` which requires an inverted output, using again the `open` method, as in the following code:
|
364
355
|
|
365
356
|
```ruby
|
366
357
|
# Declare dff0 as an instance of dff
|
@@ -373,10 +364,10 @@ dff0.open do
|
|
373
364
|
end
|
374
365
|
```
|
375
366
|
|
376
|
-
In this
|
367
|
+
In this latter case, only `dff0` will have an inverted output, the other instances of `dff` will not change.
|
377
368
|
|
378
|
-
Now assuming we opted for the first solution, we have now `dff_full`, a highly advanced D-FF with such unique features as an inverted output. So, we would like to use it in other designs, for example a shift register of `n` bits. Such a system will include a generic number of `dff_full` instances
|
379
|
-
described as follows making use of the native Ruby method `each_cons` for connecting them
|
369
|
+
Now assuming we opted for the first solution, we have now `dff_full`, a highly advanced D-FF with such unique features as an inverted output. So, we would like to use it in other designs, for example, a shift register of `n` bits. Such a system will include a generic number of `dff_full` instances and can be
|
370
|
+
described as follows making use of the native Ruby method `each_cons` for connecting them:
|
380
371
|
|
381
372
|
```ruby
|
382
373
|
system :shifter do |n|
|
@@ -400,7 +391,7 @@ system :shifter do |n|
|
|
400
391
|
end
|
401
392
|
```
|
402
393
|
|
403
|
-
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
|
394
|
+
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.)
|
404
395
|
|
405
396
|
```ruby
|
406
397
|
<type>.<direction> <list of symbols representing the signal>
|
@@ -424,7 +415,7 @@ system :shifter do |n|
|
|
424
415
|
end
|
425
416
|
```
|
426
417
|
|
427
|
-
Now, let us assume you want to design a circuit that performs a sum of products of several inputs with constant coefficients. For the case of 4 16-bit signed inputs and given
|
418
|
+
Now, let us assume you want to design a circuit that performs a sum of products of several inputs with constant coefficients. For the case of 4 16-bit signed inputs and given coefficients as 3, 4, 5, and 6. The corresponding basic code could be as follows:
|
428
419
|
|
429
420
|
```ruby
|
430
421
|
system :sumprod_16_3456 do
|
@@ -435,7 +426,7 @@ system :sumprod_16_3456 do
|
|
435
426
|
end
|
436
427
|
```
|
437
428
|
|
438
|
-
The description above is
|
429
|
+
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:
|
439
430
|
|
440
431
|
```ruby
|
441
432
|
system :sumprod do |typ,coefs|
|
@@ -449,19 +440,19 @@ end
|
|
449
440
|
```
|
450
441
|
|
451
442
|
In the code above, there are two generic parameters,
|
452
|
-
`typ
|
443
|
+
`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.
|
453
444
|
|
454
|
-
The description of the sum of
|
445
|
+
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 `_0` initializes the sum to `0`.
|
455
446
|
|
456
|
-
While slightly longer than the previous description, this description allows
|
447
|
+
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).
|
457
448
|
|
458
449
|
```ruby
|
459
450
|
sumprod(signed[32], [3,78,43,246, 3,67,1,8, 47,82,99,13, 5,77,2,4]).(:my_circuit)
|
460
451
|
```
|
461
452
|
|
462
|
-
As seen in the code above, when passing generic argument for instantiating a generic system, the name of the instance is put between brackets for avoiding confusion.
|
453
|
+
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.
|
463
454
|
|
464
|
-
While 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:
|
455
|
+
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:
|
465
456
|
|
466
457
|
```ruby
|
467
458
|
system :sumprod_func do |typ,coefs|
|
@@ -487,13 +478,13 @@ function :add do |x,y|
|
|
487
478
|
end
|
488
479
|
```
|
489
480
|
|
490
|
-
With HDLRuby functions, the result of the last statement in the return value, in this case that will be the value of res. The code above is also an example of the usage of the postfixed if statement, it an equivalent of the following code:
|
481
|
+
With HDLRuby functions, the result of the last statement in the return value, in this case, that will be the value of res. The code above is also an example of the usage of the postfixed if statement, it is an equivalent of the following code:
|
491
482
|
|
492
483
|
```ruby
|
493
484
|
hif(res>1000) { res <= 1000 }
|
494
485
|
```
|
495
486
|
|
496
|
-
With functions, it is enough to change their content to obtain a new kind of circuit without
|
487
|
+
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:
|
497
488
|
|
498
489
|
```ruby
|
499
490
|
function :add do |max, x, y|
|
@@ -505,9 +496,9 @@ function :add do |max, x, y|
|
|
505
496
|
end
|
506
497
|
```
|
507
498
|
|
508
|
-
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 any longer.
|
499
|
+
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.
|
509
500
|
|
510
|
-
HDLRuby provides two ways to address such issues. First, it is possible to pass code as 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:
|
501
|
+
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:
|
511
502
|
|
512
503
|
```ruby
|
513
504
|
system :sumprod_proc do |add,mult,typ,coefs|
|
@@ -523,7 +514,7 @@ end
|
|
523
514
|
|
524
515
|
__Note__:
|
525
516
|
|
526
|
-
- With HDLRuby, when some code is passed as argument, it is invoked using the `.()` operator, and not simple parenthesis
|
517
|
+
- With HDLRuby, when some code is passed as an argument, it is invoked using the `.()` operator, and not simple parenthesis-like functions.
|
527
518
|
|
528
519
|
Assuming the addition with saturation is now implemented by a function named `add_sat` and a multiplication with saturation is implemented by a function named `mult_sat` (with similar arguments), a circuit implementing a signed 16-bit sum of product saturating at 1000 with 16 coefficients could be described as follows:
|
529
520
|
|
@@ -536,7 +527,7 @@ sumprod_proc(
|
|
536
527
|
47,82,99,13, 5,77,2,4]).(:my_circuit)
|
537
528
|
```
|
538
529
|
|
539
|
-
As seen in the example above, a piece of code is passed as argument using the proc keyword.
|
530
|
+
As seen in the example above, a piece of code is passed as an argument using the proc keyword.
|
540
531
|
|
541
532
|
A second possible approach provided by HDLRuby is to declare a new data type with redefined addition and multiplication operators. For the case of a 16-bit saturated addition and multiplication the following generic data type can be defined (for signed computations):
|
542
533
|
|
@@ -591,7 +582,7 @@ sumprod(sat(16,1000),
|
|
591
582
|
```
|
592
583
|
|
593
584
|
|
594
|
-
|
585
|
+
Lastly note, HDLRuby is also a language with supports reflection for
|
595
586
|
all its constructs. For example, the system of an instance can be accessed
|
596
587
|
using the `systemT` method, and this latter can be used to create
|
597
588
|
other instances. For example, previously, `dff_single` was declared with
|
@@ -608,28 +599,28 @@ of the same system as `dff_single`.
|
|
608
599
|
This reflection capability can also be used for instance, for accessing the
|
609
600
|
data type of a signal (`sig.type`), but also the current basic block
|
610
601
|
(`cur_block`), the current process (`cur_behavior`) and so on.
|
611
|
-
The standard library of HDLRuby
|
612
|
-
like finite state machine descriptors
|
602
|
+
The standard library of HDLRuby includes several hardware constructs
|
603
|
+
like finite state machine descriptors and is mainly based on using these
|
613
604
|
reflection features.
|
614
605
|
|
615
606
|
|
616
607
|
|
617
608
|
## How does HDLRuby work
|
618
609
|
|
619
|
-
Contrary to descriptions in high-level HDL like SystemVerilog, VHDL or SystemC, HDLRuby descriptions are not software-like
|
610
|
+
Contrary to descriptions in high-level HDL like SystemVerilog, VHDL, or SystemC, HDLRuby descriptions are not software-like descriptions of hardware but are programs meant to produce hardware descriptions. In other words, while the execution of a common HDL code will result in some simulation of the described hardware, the execution of HDLRuby code will result in some low-level hardware description. This low-level description is synthesizable and can also be simulated like any standard hardware description.
|
620
611
|
This decoupling of the representation of the hardware from the point of view of the user (HDLRuby), and the actual hardware description (HDLRuby::Low) makes it possible to provide the user with any advanced software features without jeopardizing the synthesizability of the actual hardware description.
|
621
612
|
|
622
|
-
For that purpose, each construct in HDLRuby is not a direct description of some hardware construct, but a program
|
613
|
+
For that purpose, each construct in HDLRuby is not a direct description of some hardware construct, but a program that generates the corresponding description. For example, let us consider the following line of code of HDLRuby describing the connection between signal `a` and signal `b`:
|
623
614
|
|
624
615
|
```ruby
|
625
616
|
a <= b
|
626
617
|
```
|
627
618
|
|
628
|
-
Its execution will produce the actual hardware description of this connection as an object of the HDLRuby::Low library — in this case an instance of the `HDLRuby::Low::Connection` class. Concretely,
|
619
|
+
Its execution will produce the actual hardware description of this connection as an object of the HDLRuby::Low library — in this case, an instance of the `HDLRuby::Low::Connection` class. Concretely, an HDLRuby system is described by a Ruby block, and the instantiation of this system is performed by executing this block. The actual synthesizable description of this hardware is the execution result of this instantiation.
|
629
620
|
|
630
621
|
|
631
622
|
|
632
|
-
From there, we will describe
|
623
|
+
From there, we will describe in more detail each construct of HDLRuby.
|
633
624
|
|
634
625
|
## Naming rules
|
635
626
|
<a name="names"></a>
|
@@ -637,17 +628,17 @@ From there, we will describe into more details each construct of HDLRuby.
|
|
637
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.
|
638
629
|
|
639
630
|
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
|
640
|
-
has been declared with `:hello` as name, it will be afterward referred by `hello`.
|
631
|
+
has been declared with `:hello` as name, it will be afterward referred to by `hello`.
|
641
632
|
|
642
633
|
## Systems and signals
|
643
634
|
|
644
|
-
A system represents a digital system and corresponds to a Verilog HDL module. A system has an interface comprising input, output, and inout signals, and includes
|
635
|
+
A system represents a digital system and corresponds to a Verilog HDL module. A system has an interface comprising input, output, and inout signals, and includes structural and behavioral descriptions.
|
645
636
|
|
646
|
-
A signal represents a state in a system. It has a data type and a value, the latter varying with time. HDLRuby signals can be viewed as abstractions of both wires and registers in a digital circuit. As general rule, a signal whose value is explicitly set all the time models a wire, otherwise it models a register.
|
637
|
+
A signal represents a state in a system. It has a data type and a value, the latter varying with time. HDLRuby signals can be viewed as abstractions of both wires and registers in a digital circuit. As a general rule, a signal whose value is explicitly set all the time models a wire, otherwise it models a register.
|
647
638
|
|
648
639
|
### Declaring an empty system
|
649
640
|
|
650
|
-
A system is declared using the keyword `system`. It must be given a Ruby symbol for name and a block that describe its content. For instance, the following code describes an empty system named `box`:
|
641
|
+
A system is declared using the keyword `system`. It must be given a Ruby symbol for its name and a block that describe its content. For instance, the following code describes an empty system named `box`:
|
651
642
|
|
652
643
|
```ruby
|
653
644
|
system(:box) {}
|
@@ -656,7 +647,7 @@ system(:box) {}
|
|
656
647
|
__Notes__:
|
657
648
|
|
658
649
|
- Since this is Ruby code, the body can also be delimited by the `do` and `end`
|
659
|
-
Ruby keywords (in which case the parentheses can be omitted) as follows:
|
650
|
+
Ruby keywords (in which case the parentheses can be omitted) are as follows:
|
660
651
|
|
661
652
|
```ruby
|
662
653
|
system :box do
|
@@ -668,7 +659,7 @@ end
|
|
668
659
|
|
669
660
|
### Declaring a system with an interface
|
670
661
|
|
671
|
-
The interface of a system can be described anywhere in its body, but it is recommended to do it at its beginning. This is done by declaring input, output or inout signals of given data types as follows:
|
662
|
+
The interface of a system can be described anywhere in its body, but it is recommended to do it at its beginning. This is done by declaring input, output, or inout signals of given data types as follows:
|
672
663
|
|
673
664
|
```ruby
|
674
665
|
<data type>.<direction> <list of colon-preceded names>
|
@@ -687,7 +678,7 @@ input :clk
|
|
687
678
|
```
|
688
679
|
|
689
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
|
690
|
-
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.
|
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.
|
691
682
|
|
692
683
|
```ruby
|
693
684
|
system :mem8_16 do
|
@@ -720,7 +711,7 @@ For example, system `mem8_16` declared in the previous section can be instantiat
|
|
720
711
|
mem8_16 :mem8_16I
|
721
712
|
```
|
722
713
|
|
723
|
-
It is also possible to declare multiple instances of
|
714
|
+
It is also possible to declare multiple instances of the same system at a time as follows:
|
724
715
|
|
725
716
|
```ruby
|
726
717
|
<system name> [list of colon-separated instance names]
|
@@ -741,7 +732,7 @@ inner :w1
|
|
741
732
|
[1..0].inner :w2
|
742
733
|
```
|
743
734
|
|
744
|
-
If the signal is not meant to be changed,
|
735
|
+
If the signal is not meant to be changed, it can be declared using the `constant` keyword instead of `inner`.
|
745
736
|
|
746
737
|
A connection between signals is done using the arrow operator `<=` as follows:
|
747
738
|
|
@@ -764,7 +755,7 @@ As another example, the following code connects to the second bit of `w2` the ou
|
|
764
755
|
w2[1] <= clk & rst
|
765
756
|
```
|
766
757
|
|
767
|
-
The signals of an instance can be connected through the arrow operator too, provided they are properly referred to. One way to refer them is to use the dot operator `.` on the instance as follows:
|
758
|
+
The signals of an instance can be connected through the arrow operator too, provided they are properly referred to. One way to refer to them is to use the dot operator `.` on the instance as follows:
|
768
759
|
|
769
760
|
```ruby
|
770
761
|
<instance name>.<signal name>
|
@@ -834,19 +825,19 @@ end
|
|
834
825
|
### Initialization of signals
|
835
826
|
<a name="initialization"></a>
|
836
827
|
|
837
|
-
Output, inner and constant signals of a system can be
|
828
|
+
Output, inner and constant signals of a system can be initialized when declared using the following syntax in place of the usual name of the signal:
|
838
829
|
|
839
830
|
```ruby
|
840
831
|
<signal name>: <intial value>
|
841
832
|
```
|
842
833
|
|
843
|
-
For example a single
|
834
|
+
For example, a single-bit inner signal named `sig` can be initialized to 0 as follows:
|
844
835
|
|
845
836
|
```ruby
|
846
837
|
inner sig: 0
|
847
838
|
```
|
848
839
|
|
849
|
-
As
|
840
|
+
As another example, an 8-bit 8-word ROM could be declared and initialized as follows:
|
850
841
|
|
851
842
|
```ruby
|
852
843
|
bit[8][-8] rom: [ 0,1,2,3,4,5,6,7 ]
|
@@ -857,9 +848,9 @@ bit[8][-8] rom: [ 0,1,2,3,4,5,6,7 ]
|
|
857
848
|
|
858
849
|
#### General scopes
|
859
850
|
|
860
|
-
The signals of the interface of signals are accessible from anywhere in
|
851
|
+
The signals of the interface of signals are accessible from anywhere in an HDLRuby description. This is not the case for inner signals and instances: they are accessible only within the scope they are declared in.
|
861
852
|
|
862
|
-
A scope is a region of the code where locally declared objects are accessible. Each system has its
|
853
|
+
A scope is a region of the code where locally declared objects are accessible. Each system has its scope that cannot be accessible from another part of an HDLRuby description. For example, in the following code signals `d` and `qb` as well as instance `dffI` cannot be accessed from outside system `div2`:
|
863
854
|
|
864
855
|
```ruby
|
865
856
|
system :div2 do
|
@@ -873,7 +864,7 @@ system :div2 do
|
|
873
864
|
|
874
865
|
```
|
875
866
|
|
876
|
-
For robustness or, readability purpose, it is possible to add inner scope inside existing scope using the `sub` keyword as follows:
|
867
|
+
For robustness or, readability purpose, it is possible to add inner scope inside the existing scope using the `sub` keyword as follows:
|
877
868
|
|
878
869
|
```ruby
|
879
870
|
sub do
|
@@ -881,7 +872,7 @@ sub do
|
|
881
872
|
end
|
882
873
|
```
|
883
874
|
|
884
|
-
For example, in the code
|
875
|
+
For example, in the code below signal `sig` is not accessible from outside the additional inner scope of system `sys`
|
885
876
|
|
886
877
|
```ruby
|
887
878
|
system :sys do
|
@@ -912,7 +903,7 @@ system :sys do
|
|
912
903
|
end
|
913
904
|
```
|
914
905
|
|
915
|
-
Within
|
906
|
+
Within the same scope, it is not possible to declare multiple signals or instances with the same name. However, it is possible to declare a signal or an instance with a name identical to one previously declared outside the scope: the inner-most declaration will be used.
|
916
907
|
|
917
908
|
|
918
909
|
#### Named scopes
|
@@ -930,7 +921,7 @@ Where:
|
|
930
921
|
* `<name>` is the name of the scope.
|
931
922
|
* `<code>` is the code within the scope.
|
932
923
|
|
933
|
-
Contrary to the case of scopes without name, signals and instances declared within a named scope can be accessed outside using this name as reference. For example, in the code
|
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`:
|
934
925
|
|
935
926
|
```ruby
|
936
927
|
sub :scop do
|
@@ -958,11 +949,11 @@ In addition, it is possible to declare inner signals within an execution block.
|
|
958
949
|
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.
|
959
950
|
|
960
951
|
An event represents a specific change of state of a signal.
|
961
|
-
For example, a rising edge of a clock signal named `clk` will be represented by event `clk.posedge`. In HDLRuby, events are obtained directly from
|
962
|
-
expressions using the following methods: `posedge` for rising edge, `negedge` for falling edge, and `edge` for any edge.
|
952
|
+
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
|
+
expressions using the following methods: `posedge` for a rising edge, `negedge` for a falling edge, and `edge` for any edge.
|
963
954
|
Events are described in more detail in section [Events](#events).
|
964
955
|
|
965
|
-
When one of the events of the sensitivity list of a behavior occurs, the behavior is executed, i.e., each of its statements is executed in sequence. A statement can represent a data transmission to a signal, a control flow, a nested execution block or the declaration of an inner signal (as stated
|
956
|
+
When one of the events of the sensitivity list of a behavior occurs, the behavior is executed, i.e., each of its statements is executed in sequence. A statement can represent a data transmission to a signal, a control flow, a nested execution block, or the declaration of an inner signal (as stated
|
966
957
|
earlier). Statements are described in more detail in section [statements](#statements). In this section, we focus on the transmission statements and the block statements.
|
967
958
|
|
968
959
|
A transmission statement is declared using the arrow operator `<=` as follows:
|
@@ -973,8 +964,8 @@ A transmission statement is declared using the arrow operator `<=` as follows:
|
|
973
964
|
|
974
965
|
The `<destination>` must be a reference to a signal, and the `<source>` can be any expression. A transmission has therefore the same structure as a connection. However, its execution model is different: whereas a connection is continuously executed, a transmission is only executed during the execution of its block.
|
975
966
|
|
976
|
-
A block comprises a list of statements. It is used for adding hierarchy
|
977
|
-
By default, a top block is created when declaring a behavior, and it inherits from its execution mode. For example, with the following code the top block of the behavior is sequential.
|
967
|
+
A block comprises a list of statements. It is used for adding hierarchy to a behavior. Blocks can be either parallel or sequential, i.e., their transmission statements are respectively non-blocking or blocking.
|
968
|
+
By default, a top block is created when declaring a behavior, and it inherits from its execution mode. For example, with the following code, the top block of the behavior is sequential.
|
978
969
|
|
979
970
|
```ruby
|
980
971
|
system :with_sequential_behavior do
|
@@ -985,7 +976,7 @@ end
|
|
985
976
|
```
|
986
977
|
|
987
978
|
It is possible to declare new blocks within an existing block.
|
988
|
-
For declaring a sub
|
979
|
+
For declaring a sub-block with the same execution mode as the upper one, the keyword `sub` is used. For example, the following code declares a sub-block within a sequential block, with the same execution mode:
|
989
980
|
|
990
981
|
```ruby
|
991
982
|
system :with_sequential_behavior do
|
@@ -998,7 +989,7 @@ system :with_sequential_behavior do
|
|
998
989
|
end
|
999
990
|
```
|
1000
991
|
|
1001
|
-
A sub
|
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:
|
1002
993
|
|
1003
994
|
```ruby
|
1004
995
|
system :with_sequential_behavior do
|
@@ -1011,7 +1002,7 @@ system :with_sequential_behavior do
|
|
1011
1002
|
end
|
1012
1003
|
```
|
1013
1004
|
|
1014
|
-
Sub blocks have their
|
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
|
1015
1006
|
declare three different inner signals all called `sig` as follows:
|
1016
1007
|
|
1017
1008
|
```ruby
|
@@ -1052,7 +1043,7 @@ system :shift16 do
|
|
1052
1043
|
end
|
1053
1044
|
```
|
1054
1045
|
|
1055
|
-
In the example above, the order of the transmission statements is of no consequence. This is not the case for the following example,
|
1046
|
+
In the example above, the order of the transmission statements is of no consequence. This is not the case for the following example, which implements the same register using a sequential block. In this second example, putting the statement `reg[0] <= din` in the last place would have led to an invalid functionality for a shift register.
|
1056
1047
|
|
1057
1048
|
```ruby
|
1058
1049
|
system :shift16 do
|
@@ -1107,7 +1098,7 @@ end
|
|
1107
1098
|
( a <= b+1 ).at(clk.posedge)
|
1108
1099
|
```
|
1109
1100
|
|
1110
|
-
For sake of consistency, this operator can also be applied
|
1101
|
+
For sake of consistency, this operator can also be applied to block statements as follows, but it is probably less readable than the standard declaration of behaviors:
|
1111
1102
|
|
1112
1103
|
```ruby
|
1113
1104
|
( seq do
|
@@ -1149,17 +1140,56 @@ end
|
|
1149
1140
|
```
|
1150
1141
|
|
1151
1142
|
__Note__:
|
1152
|
-
- While of no practical use for simple circuit
|
1143
|
+
- While of no practical use for simple circuit descriptions, this feature can be used in advanced generic component descriptions.
|
1144
|
+
|
1145
|
+
|
1146
|
+
### Reconfiguration
|
1147
|
+
|
1148
|
+
In HDLRuby, dynamically reconfigurable devices are modeled by instances having more than one system. Adding systems to an instance is done as follows:
|
1149
|
+
|
1150
|
+
```ruby
|
1151
|
+
<instance>.choice(<list of named systems>)
|
1152
|
+
```
|
1153
|
+
|
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):
|
1155
|
+
|
1156
|
+
```ruby
|
1157
|
+
sys0 :dev012 # dev012 is at first a standard instance of sys0
|
1158
|
+
dev012.choice(conf1: sys1, conf2: sys2) # Now dev012 is reconfigurable
|
1159
|
+
```
|
1160
|
+
|
1161
|
+
After the code above, instance `dev012` can be dynamically reconfigured to `sys0`, `sys1`, and `sys2` with respective names `dev012`, `conf1`, and `conf2`.
|
1162
|
+
|
1163
|
+
__Note:__
|
1164
|
+
The name of the initial system in the reconfigurations is set to be the name of the instance.
|
1165
|
+
|
1166
|
+
A reconfigurable instance can then be reconfigured using the command `configure` as follows:
|
1167
|
+
|
1168
|
+
```ruby
|
1169
|
+
<instance>.configure(<name or index>)
|
1170
|
+
```
|
1171
|
+
|
1172
|
+
In the code above, the argument of `configure` can either be the name of the configuration as previously declared with `choice`, or its index in order of declaration. For example in the following code, instance `dev012` is reconfigured to system `sys1`, then system `sys0` the system `sys2`:
|
1173
|
+
|
1174
|
+
```ruby
|
1175
|
+
dev012.configure(:conf1)
|
1176
|
+
!1000.ns
|
1177
|
+
dev012.configure(:dev012)
|
1178
|
+
!1000.ns
|
1179
|
+
dev012.configure(2)
|
1180
|
+
```
|
1181
|
+
|
1182
|
+
These reconfiguration commands are treated as regular RTL statements in HDLRuby and are supported by the simulator. However, in the current version of the HDLRuby, these statements are ignored when generating Verilog HDL or VHDL code.
|
1153
1183
|
|
1154
1184
|
|
1155
1185
|
## Events
|
1156
1186
|
<a name="events"></a>
|
1157
1187
|
|
1158
|
-
Each behavior of a system is associated with a list of events, called
|
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.
|
1159
1189
|
|
1160
|
-
There are three kinds of
|
1190
|
+
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
|
1161
1191
|
represent the instants when their corresponding signals vary from 1 to 0 and the change events represent the instants when their corresponding signals vary.
|
1162
|
-
Events are declared directly from the signals, using the `posedge` operator for positive edge, the `negedge` operator for negative edge, and the `change` operator for change. For example, the following code declares 3 behaviors activated respectively on the positive edge, the negative edge and any change of the `clk` signal.
|
1192
|
+
Events are declared directly from the signals, using the `posedge` operator for a positive edge, the `negedge` operator for a negative edge, and the `change` operator for change. For example, the following code declares 3 behaviors activated respectively on the positive edge, the negative edge, and any change of the `clk` signal.
|
1163
1193
|
|
1164
1194
|
```ruby
|
1165
1195
|
inner :clk
|
@@ -1184,8 +1214,8 @@ __Note:__
|
|
1184
1214
|
<a name="statements"></a>
|
1185
1215
|
|
1186
1216
|
Statements are the basic elements of a behavioral description. They are regrouped in blocks that specify their execution mode (parallel or sequential).
|
1187
|
-
There are four kinds of statements: the transmit statement
|
1188
|
-
that changes the execution flow of the behavior, the block statement (described earlier) and the inner signal declaration.
|
1217
|
+
There are four kinds of statements: the transmit statement which computes expressions and sends the result to the target signals, the control statement
|
1218
|
+
that changes the execution flow of the behavior, the block statement (described earlier), and the inner signal declaration.
|
1189
1219
|
|
1190
1220
|
__Note__:
|
1191
1221
|
|
@@ -1196,7 +1226,7 @@ __Note__:
|
|
1196
1226
|
|
1197
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.
|
1198
1228
|
|
1199
|
-
For example, 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`:
|
1229
|
+
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`:
|
1200
1230
|
|
1201
1231
|
```ruby
|
1202
1232
|
s0 <= 3
|
@@ -1272,7 +1302,7 @@ that the current synthesis tools do not really synthesize hardware from such loo
|
|
1272
1302
|
__Notes__:
|
1273
1303
|
|
1274
1304
|
- HDLRuby being based on Ruby, it is highly recommended to avoid `for` or `while` constructs and to use enumerators instead.
|
1275
|
-
- The Ruby `if` and `case` statements can also be used, but they do not represent any hardware.
|
1305
|
+
- The Ruby `if` and `case` statements can also be used, but they do not represent any hardware. They are executed when the corresponding system is instantiated. For example, the following code will display `Hello world!` when the described system is instantiated, provided the generic parameter `param` is not nil.
|
1276
1306
|
|
1277
1307
|
```ruby
|
1278
1308
|
system :say_hello do |param = nil|
|
@@ -1285,38 +1315,38 @@ __Notes__:
|
|
1285
1315
|
## Types
|
1286
1316
|
<a name="types"></a>
|
1287
1317
|
|
1288
|
-
Each signal and each expression is associated with a data type
|
1289
|
-
bit
|
1318
|
+
Each signal and each expression is associated with a data type that describes the kind of value it can represent. In HDLRuby, the data types represent
|
1319
|
+
bit-vectors associated with the way they should be interpreted, i.e., as bit strings, unsigned values, signed values, or hierarchical contents.
|
1290
1320
|
|
1291
1321
|
### Type construction
|
1292
1322
|
|
1293
|
-
There are five basic types, `bit`, `signed`, `unsigned`, `integer
|
1323
|
+
There are five basic types, `bit`, `signed`, `unsigned`, `integer`, and `float` that represent respectively single bit logical values, single-bit unsigned values, single-bit signed values, Ruby integer values, and Ruby floating-point values (double precision). The first three types are HW and support four-valued logic, whereas the two last ones are SW (but are compatible with HW) and only support Boolean logic. Ruby integers can represent any element of **Z** (the mathematical integers) and have for that purpose a variable bit-width.
|
1294
1324
|
|
1295
1325
|
|
1296
1326
|
The other types are built from them using a combination of the two following
|
1297
1327
|
type operators.
|
1298
1328
|
|
1299
|
-
__The vector operator__ `[]` is used for building types representing vectors of single or multiple other types. A vector whose elements have all the same type
|
1329
|
+
__The vector operator__ `[]` is used for building types representing vectors of single or multiple other types. A vector whose elements have all the same type is declared as follows:
|
1300
1330
|
|
1301
1331
|
```ruby
|
1302
1332
|
<type>[<range>]
|
1303
1333
|
```
|
1304
1334
|
|
1305
1335
|
The `<range>` of a vector type indicates the position of the starting and ending bits.
|
1306
|
-
|
1336
|
+
An `n..0` range can also be abbreviated to `n+1`. For instance, the two following types are identical:
|
1307
1337
|
|
1308
1338
|
```ruby
|
1309
1339
|
bit[7..0]
|
1310
1340
|
bit[8]
|
1311
1341
|
```
|
1312
1342
|
|
1313
|
-
A vector of multiple types, also called tuple, is declared as follows:
|
1343
|
+
A vector of multiple types, also called a tuple, is declared as follows:
|
1314
1344
|
|
1315
1345
|
```ruby
|
1316
1346
|
[<type 0>, <type 1>, ... ]
|
1317
1347
|
```
|
1318
1348
|
|
1319
|
-
For example, the following code declares the type of the vectors made of an 8-bit logical, a 16-bit signed and a 16-bit unsigned values:
|
1349
|
+
For example, the following code declares the type of the vectors made of an 8-bit logical, a 16-bit signed, and a 16-bit unsigned values:
|
1320
1350
|
|
1321
1351
|
```ruby
|
1322
1352
|
[ bit[8], signed[16], unsigned[16] ]
|
@@ -1328,7 +1358,7 @@ __The structure operator__ `{}` is used for building hierarchical types made of
|
|
1328
1358
|
{ <name 0>: <type 0>, <name 1>: <type 1>, ... }
|
1329
1359
|
```
|
1330
1360
|
|
1331
|
-
For instance, the following code declares a hierarchical type with an 8-bit
|
1361
|
+
For instance, the following code declares a hierarchical type with an 8-bit subtype named `header` and a 24-bit subtype named `data`:
|
1332
1362
|
|
1333
1363
|
```ruby
|
1334
1364
|
{ header: bit[7..0], data: bit[23..0] }
|
@@ -1378,9 +1408,9 @@ end
|
|
1378
1408
|
|
1379
1409
|
### Type compatibility and conversion
|
1380
1410
|
|
1381
|
-
The basis of all the types in HDLRuby is the vector of bits (
|
1411
|
+
The basis of all the types in HDLRuby is the vector of bits (bit vector) where each bit can have four values: 0, 1, Z, and X (for undefined). Bit vectors are by default unsigned but can be set to be signed. When performing computations between signals of different bit-vector types, the shorter signal is extended to the size of the larger one preserving its sign if it is signed.
|
1382
1412
|
|
1383
|
-
While the underlying structure of any HDLRuby type is the
|
1413
|
+
While the underlying structure of any HDLRuby type is the bit vector, complex types can be defined. When using such types in computational expressions and assignments they are first implicitly converted to an unsigned bit vector of the same size.
|
1384
1414
|
|
1385
1415
|
## Expressions
|
1386
1416
|
<a name="expressions"></a>
|
@@ -1392,7 +1422,7 @@ They include [immediate values](#values), [reference to signals](#references) an
|
|
1392
1422
|
### Immediate values
|
1393
1423
|
<a name="values"></a>
|
1394
1424
|
|
1395
|
-
The immediate values of HDLRuby can represent vectors of `bit`, `unsigned
|
1425
|
+
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 enforce it in the header.
|
1396
1426
|
|
1397
1427
|
The vector type specifiers are the followings:
|
1398
1428
|
|
@@ -1400,7 +1430,7 @@ The vector type specifiers are the followings:
|
|
1400
1430
|
|
1401
1431
|
- `u`: `unsigned` type, (equivalent to `b` and can be used for avoiding confusion with the binary specifier),
|
1402
1432
|
|
1403
|
-
- `s`: `signed` type, the last figure is sign
|
1433
|
+
- `s`: `signed` type, the last figure is sign-extended if required by the binary, octal, and hexadecimal bases, but not for the decimal base.
|
1404
1434
|
|
1405
1435
|
The base specifiers are the followings:
|
1406
1436
|
|
@@ -1427,7 +1457,7 @@ _s8o144
|
|
1427
1457
|
|
1428
1458
|
__Notes__:
|
1429
1459
|
|
1430
|
-
- 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:
|
1460
|
+
- 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:
|
1431
1461
|
|
1432
1462
|
```ruby
|
1433
1463
|
[3..0].inner :sig
|
@@ -1438,7 +1468,7 @@ __Notes__:
|
|
1438
1468
|
### References
|
1439
1469
|
<a name="references"></a>
|
1440
1470
|
|
1441
|
-
References are expressions used to designate signals
|
1471
|
+
References are expressions used to designate signals or a part of signals.
|
1442
1472
|
|
1443
1473
|
The simplest reference is simply the name of a signal. It designates the signal corresponding to this name in the current scope. For instance, in the
|
1444
1474
|
following code, inner signal `sig0` is declared, and therefore the name *sig0* becomes a reference to designate this signal.
|
@@ -1451,13 +1481,13 @@ inner :sig0
|
|
1451
1481
|
sig0 <= 0
|
1452
1482
|
```
|
1453
1483
|
|
1454
|
-
For designating a signal of another system, or a sub
|
1484
|
+
For designating a signal of another system, or a sub-signal in a hierarchical signal, you can use the `.` operator as follows:
|
1455
1485
|
|
1456
1486
|
```ruby
|
1457
1487
|
<parent name>.<signal name>
|
1458
1488
|
```
|
1459
1489
|
|
1460
|
-
For example, in the following code, input signal `d` of system instance `dff0` is connected to sub
|
1490
|
+
For example, in the following code, input signal `d` of system instance `dff0` is connected to sub-signal `sub0` of hierarchical signal `sig`.
|
1461
1491
|
|
1462
1492
|
```ruby
|
1463
1493
|
system :dff do
|
@@ -1555,7 +1585,7 @@ __Notes__:
|
|
1555
1585
|
|
1556
1586
|
- The operator precedence is the one of Ruby.
|
1557
1587
|
|
1558
|
-
- 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
|
1588
|
+
- 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.
|
1559
1589
|
|
1560
1590
|
#### Assignment operators
|
1561
1591
|
<a name="assignment"></a>
|
@@ -1582,19 +1612,19 @@ __Notes__:
|
|
1582
1612
|
|
1583
1613
|
- The `<`, `>`, `<=` and `>=` operators can only be used on vectors of `bit`, `unsigned` or `signed` values, `integer` or `float` values.
|
1584
1614
|
|
1585
|
-
- When compared, values of type different from vector of `signed` and from `float` are considered as vectors of `unsigned`.
|
1615
|
+
- When compared, values of a type different from the vector of `signed` and from `float` are considered as vectors of `unsigned`.
|
1586
1616
|
|
1587
1617
|
|
1588
1618
|
#### Logic and shift operators
|
1589
1619
|
<a name="logic"></a>
|
1590
1620
|
|
1591
|
-
In HDLRuby, the logic operators are all bitwise. For performing Boolean computations, it is necessary to use single
|
1621
|
+
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.
|
1592
1622
|
|
1593
|
-
__Note__: there
|
1623
|
+
__Note__: there are two reasons why there are no Boolean operators
|
1594
1624
|
|
1595
|
-
1. Ruby language does not support redefinition of the Boolean operators
|
1625
|
+
1. Ruby language does not support the redefinition of the Boolean operators
|
1596
1626
|
|
1597
|
-
2. In Ruby, each value
|
1627
|
+
2. In Ruby, each value that is not `false` nor `nil` is assumed to be true. This is perfectly relevant for software, but not for hardware where the basic data types are bit vectors. Hence, it seemed preferable to support Boolean computation for one-bit values only, which can be done through bitwise operations.
|
1598
1628
|
|
1599
1629
|
The shift operators are `<<` and `>>` and have the same meaning as their Ruby equivalent. They do not change the bit width and preserve the sign for `signed` values.
|
1600
1630
|
|
@@ -1605,7 +1635,7 @@ The rotation operators are `rl` and `rr` for respectively left and right bit rot
|
|
1605
1635
|
<expression>.rr(<other expression>)
|
1606
1636
|
```
|
1607
1637
|
|
1608
|
-
For example, for rotating left signal `sig` 3 times, the following code can be used:
|
1638
|
+
For example, for rotating the left signal `sig` 3 times, the following code can be used:
|
1609
1639
|
|
1610
1640
|
```ruby
|
1611
1641
|
sig.rl(3)
|
@@ -1619,7 +1649,7 @@ selection operators](#concat) for more details about these operators.
|
|
1619
1649
|
<a name="conversion"></a>
|
1620
1650
|
|
1621
1651
|
The conversion operators are used to change the type of an expression.
|
1622
|
-
There are two kinds of such operators: the type pun that
|
1652
|
+
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.
|
1623
1653
|
|
1624
1654
|
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:
|
1625
1655
|
|
@@ -1628,12 +1658,12 @@ The type puns include `to_bit`, `to_unsigned` and `to_signed` that convert expre
|
|
1628
1658
|
sig.to_bit <= _b01010011
|
1629
1659
|
```
|
1630
1660
|
|
1631
|
-
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
|
1661
|
+
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)).
|
1632
1662
|
These operators comprise the bit width conversions: `ljust`, `rjust`, `zext` and `sext`.
|
1633
1663
|
|
1634
1664
|
More precisely, the bit width conversions operate as follows:
|
1635
1665
|
|
1636
|
-
- `ljust` and `rjust` increase the size from respectively the left or the right side of the bit vector. They take as argument the width of the new type and the value (0 or 1) of the bits to add. For example, the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
|
1666
|
+
- `ljust` and `rjust` increase the size from respectively the left or the right side of the bit vector. They take as an argument the width of the new type and the value (0 or 1) of the bits to add. For example, the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
|
1637
1667
|
|
1638
1668
|
```ruby
|
1639
1669
|
[7..0].inner :sig0
|
@@ -1642,7 +1672,7 @@ More precisely, the bit width conversions operate as follows:
|
|
1642
1672
|
sig1 <= sig0.ljust(12,1)
|
1643
1673
|
```
|
1644
1674
|
|
1645
|
-
- `zext` increases the size by adding several 0 bits on the most significant bit side, this side depending on the endianness of the expression. This conversion takes as argument the width of the resulting type. For example, the following code increases the size of `sig0` to 12 bits by adding 0 on the left:
|
1675
|
+
- `zext` increases the size by adding several 0 bits on the most significant bit side, this side depending on the endianness of the expression. This conversion takes as an argument the width of the resulting type. For example, the following code increases the size of `sig0` to 12 bits by adding 0 on the left:
|
1646
1676
|
|
1647
1677
|
```ruby
|
1648
1678
|
signed[7..0].inner :sig0
|
@@ -1651,7 +1681,7 @@ More precisely, the bit width conversions operate as follows:
|
|
1651
1681
|
sig1 <= sig0.zext(12)
|
1652
1682
|
```
|
1653
1683
|
|
1654
|
-
- `sext` increases the size by duplicating the most significant bit, the side of the extension depending on the endianness of the expression. This conversion takes as argument the width of the resulting type. For example, the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
|
1684
|
+
- `sext` increases the size by duplicating the most significant bit, the side of the extension depending on the endianness of the expression. This conversion takes as an argument the width of the resulting type. For example, the following code increases the size of `sig0` to 12 bits by adding 1 on the right:
|
1655
1685
|
|
1656
1686
|
```ruby
|
1657
1687
|
signed[0..7].inner :sig0
|
@@ -1782,15 +1812,15 @@ Where:
|
|
1782
1812
|
|
1783
1813
|
__Notes__:
|
1784
1814
|
|
1785
|
-
- Functions have their
|
1815
|
+
- Functions have their scope, so any declaration within a function is local. It is also forbidden to declare interface signals (input, output, or inout) within a function.
|
1786
1816
|
|
1787
|
-
- Like the Ruby proc objects, the last statement of a function's code serves as return value. For instance, the following function returns `1` (in this example the function does not have any argument):
|
1817
|
+
- Like the Ruby proc objects, the last statement of a function's code serves as the return value. For instance, the following function returns `1` (in this example the function does not have any argument):
|
1788
1818
|
|
1789
1819
|
```ruby
|
1790
1820
|
function :one { 1 }
|
1791
1821
|
```
|
1792
1822
|
|
1793
|
-
- Functions can accept any kind of object as argument, including variadic arguments or blocks of code as shown below with a function
|
1823
|
+
- Functions can accept any kind of object as an argument, including variadic arguments or blocks of code as shown below with a function that applies the code passed as an argument to all the variadic arguments of `args`:
|
1794
1824
|
|
1795
1825
|
```ruby
|
1796
1826
|
function :apply do |*args, &code|
|
@@ -1827,7 +1857,7 @@ Where:
|
|
1827
1857
|
* `code` is the code of the function.
|
1828
1858
|
|
1829
1859
|
These functions are called the same way HDLRuby functions are called, but this operation pastes the code of the function as is within the code.
|
1830
|
-
Moreover, these functions do not have any scope so
|
1860
|
+
Moreover, these functions do not have any scope so any inner signal or instance declared within them will be added to the object they are invoked in.
|
1831
1861
|
|
1832
1862
|
For example, the following function will add input `in0` to any system where it is invoked:
|
1833
1863
|
|
@@ -1878,7 +1908,7 @@ Ruby functions can be compared to the macros of the C languages: they are more f
|
|
1878
1908
|
### Time values
|
1879
1909
|
<a name="time_val"></a>
|
1880
1910
|
|
1881
|
-
In HDLRuby, time values can be created using the time operators: `s` for seconds, `ms` for millisecond, `us` for microseconds, `ns` for nanoseconds, `ps` for picoseconds. For example, the followings are all indicating one second
|
1911
|
+
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:
|
1882
1912
|
|
1883
1913
|
```ruby
|
1884
1914
|
1.s
|
@@ -1892,7 +1922,7 @@ In HDLRuby, time values can be created using the time operators: `s` for seconds
|
|
1892
1922
|
### Time behaviors and time statements
|
1893
1923
|
<a name="time_beh"></a>
|
1894
1924
|
|
1895
|
-
Like the other HDL, HDLRuby provides specific statements that
|
1925
|
+
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.
|
1896
1926
|
|
1897
1927
|
```ruby
|
1898
1928
|
timed do
|
@@ -1903,7 +1933,7 @@ end
|
|
1903
1933
|
A time behavior does not have any sensitivity list, but it can include any statement supported by a standard behavior in addition to the time statements.
|
1904
1934
|
There are two kinds of such statements:
|
1905
1935
|
|
1906
|
-
- The `wait` statements: such a statement blocks the execution of the behavior for the time given in argument. For example, the following code waits 10ns before proceeding:
|
1936
|
+
- The `wait` statements: such a statement blocks the execution of the behavior for the time given in the argument. For example, the following code waits for 10ns before proceeding:
|
1907
1937
|
|
1908
1938
|
```ruby
|
1909
1939
|
wait(10.ns)
|
@@ -1915,7 +1945,7 @@ There are two kinds of such statements:
|
|
1915
1945
|
!10.ns
|
1916
1946
|
```
|
1917
1947
|
|
1918
|
-
- The `repeat` statements: such a statement takes as argument a time value and a block. The execution of the block is repeated until the delay given by the time value argument expires. For example, the following code executes repeatedly the inversion of the `clk` signal every 10 nanoseconds for 10 seconds (i.e., it simulates a clock signal for 10 seconds):
|
1948
|
+
- The `repeat` statements: such a statement takes as argument a time value and a block. The execution of the block is repeated until the delay that is given by the time value argument expires. For example, the following code executes repeatedly the inversion of the `clk` signal every 10 nanoseconds for 10 seconds (i.e., it simulates a clock signal for 10 seconds):
|
1919
1949
|
|
1920
1950
|
```ruby
|
1921
1951
|
repeat(10.s) do
|
@@ -1931,7 +1961,7 @@ sequential blocks. The execution semantic is the following:
|
|
1931
1961
|
|
1932
1962
|
- A sequential block in a time behavior is executed sequentially.
|
1933
1963
|
|
1934
|
-
- A parallel block in a time behavior is executed in semi-parallel fashion as follows:
|
1964
|
+
- A parallel block in a time behavior is executed in a semi-parallel fashion as follows:
|
1935
1965
|
|
1936
1966
|
1. Statements are grouped in sequence until a time statement is met.
|
1937
1967
|
|
@@ -1948,7 +1978,7 @@ sequential blocks. The execution semantic is the following:
|
|
1948
1978
|
|
1949
1979
|
### Using Ruby in HDLRuby
|
1950
1980
|
|
1951
|
-
Since HDLRuby is pure Ruby code, the constructs of Ruby can be freely used without any compatibility
|
1981
|
+
Since HDLRuby is pure Ruby code, the constructs of Ruby can be freely used without any compatibility issues. Moreover, this Ruby code will not interfere with the synthesizability of the design. It is then possible to define Ruby classes, methods, or modules whose execution generates constructs of
|
1952
1982
|
HDLRuby.
|
1953
1983
|
|
1954
1984
|
|
@@ -1972,7 +2002,7 @@ For example, the following code describes an empty system with two generic param
|
|
1972
2002
|
system(:nothing) { |a,b| }
|
1973
2003
|
```
|
1974
2004
|
|
1975
|
-
The generic parameters can be anything: values, data types, signals, systems, Ruby variables, and so on. For example, the following system uses generic argument `t` as a type for an input signal, generic argument `w` as a bit range for an output signal and generic argument `s` as a system used for creating instance `sI` whose input and output signals `i` and `o` are connected respectively to signals `isig` and `osig`.
|
2005
|
+
The generic parameters can be anything: values, data types, signals, systems, Ruby variables, and so on. For example, the following system uses generic argument `t` as a type for an input signal, generic argument `w` as a bit range for an output signal, and generic argument `s` as a system used for creating instance `sI` whose input and output signals `i` and `o` are connected respectively to signals `isig` and `osig`.
|
1976
2006
|
|
1977
2007
|
```ruby
|
1978
2008
|
system :something do |t,w,s|
|
@@ -2005,7 +2035,7 @@ For example, the following code describes a bit-vector type with generic number
|
|
2005
2035
|
type(:bitvec) { |width| bit[width] }
|
2006
2036
|
```
|
2007
2037
|
|
2008
|
-
Like with the systems, the generic parameters of types can be any kind of
|
2038
|
+
Like with the systems, the generic parameters of types can be any kind of object, and it is also possible to use variadic arguments.
|
2009
2039
|
|
2010
2040
|
|
2011
2041
|
|
@@ -2013,13 +2043,13 @@ Like with the systems, the generic parameters of types can be any kind of object
|
|
2013
2043
|
|
2014
2044
|
##### Specializing generic systems
|
2015
2045
|
|
2016
|
-
A generic system is specialized by invoking its name and passing as argument the values corresponding to the generic arguments as follows:
|
2046
|
+
A generic system is specialized by invoking its name and passing as an argument the values corresponding to the generic arguments as follows:
|
2017
2047
|
|
2018
2048
|
```ruby
|
2019
2049
|
<system name>(<generic argument value's list>)
|
2020
2050
|
```
|
2021
2051
|
|
2022
|
-
If
|
2052
|
+
If fewer values are provided than the number of generic arguments, the system is partially specialized. However, only a fully specialized system can be instantiated.
|
2023
2053
|
|
2024
2054
|
A specialized system can also be used for inheritance. For example, assuming system `sys` has 2 generic arguments, it can be specialized and used for building system `subsys` as follows:
|
2025
2055
|
|
@@ -2040,23 +2070,23 @@ end
|
|
2040
2070
|
|
2041
2071
|
__Note:__
|
2042
2072
|
|
2043
|
-
- In the example above, generic parameter `param` of `subsys_gen` is used for specializing system `sys`.
|
2073
|
+
- In the example above, the generic parameter `param` of `subsys_gen` is used for specializing system `sys`.
|
2044
2074
|
|
2045
2075
|
|
2046
2076
|
##### Specializing generic types
|
2047
2077
|
|
2048
|
-
A generic type is specialized by invoking its name and passing as argument the values corresponding to the generic arguments as follows:
|
2078
|
+
A generic type is specialized by invoking its name and passing as an argument the values corresponding to the generic arguments as follows:
|
2049
2079
|
|
2050
2080
|
```ruby
|
2051
2081
|
<type name>(<generic argument value's list>)
|
2052
2082
|
```
|
2053
2083
|
|
2054
|
-
If
|
2084
|
+
If fewer values are provided than the number of generic arguments, the type is partially specialized. However, only a fully specialized type can be used for declaring signals.
|
2055
2085
|
|
2056
2086
|
|
2057
2087
|
##### Use of signals as generic parameters
|
2058
2088
|
|
2059
|
-
Signals passed as generic arguments to systems can be used for making generic connections to the instance of the system. For that purpose, the generic argument has to be declared as input, output or inout port in the body of the system as follows:
|
2089
|
+
Signals passed as generic arguments to systems can be used for making generic connections to the instance of the system. For that purpose, the generic argument has to be declared as input, output, or inout port in the body of the system as follows:
|
2060
2090
|
|
2061
2091
|
```ruby
|
2062
2092
|
system :<system_name> do |sig|
|
@@ -2065,7 +2095,7 @@ system :<system_name> do |sig|
|
|
2065
2095
|
end
|
2066
2096
|
```
|
2067
2097
|
|
2068
|
-
In the code above, `sig` is a generic argument assumed to be a signal. The second line declares the port to which sig will connected to when instantiating. From there, port `my_sig` can be used like any other port of the system. Such a system is
|
2098
|
+
In the code above, `sig` is a generic argument assumed to be a signal. The second line declares the port to which sig will be connected to when instantiating. From there, port `my_sig` can be used like any other port of the system. Such a system is then instantiated as follows:
|
2069
2099
|
|
2070
2100
|
```ruby
|
2071
2101
|
system_name(some_sig) :<instance_name>
|
@@ -2083,7 +2113,7 @@ In the code above, `some_sig` is a signal available in the current context. This
|
|
2083
2113
|
In HDLRuby, a system can inherit from the content of one or several other parent systems using the `include` command as follows: `include <list of
|
2084
2114
|
systems>`. Such an include can be put anywhere in the body of a system, but the resulting content will be accessible only after this command.
|
2085
2115
|
|
2086
|
-
For example, the following code describes first a simple D-FF, and then
|
2116
|
+
For example, the following code describes first a simple D-FF, and then uses it to describe a FF with an additional reversed output (`qb`):
|
2087
2117
|
|
2088
2118
|
```ruby
|
2089
2119
|
system :dff do
|
@@ -2122,7 +2152,7 @@ end
|
|
2122
2152
|
|
2123
2153
|
__Note__:
|
2124
2154
|
|
2125
|
-
* As a matter of implementation, HDLRuby systems can be viewed as sets of methods used for accessing various constructs (signals, instances). Hence inheritance in HDLRuby is closer the Ruby mixin mechanism than to a true software inheritance.
|
2155
|
+
* As a matter of implementation, HDLRuby systems can be viewed as sets of methods used for accessing various constructs (signals, instances). Hence inheritance in HDLRuby is closer to the Ruby mixin mechanism than to a true software inheritance.
|
2126
2156
|
|
2127
2157
|
|
2128
2158
|
#### About inner signals and system instances
|
@@ -2180,11 +2210,11 @@ section.
|
|
2180
2210
|
|
2181
2211
|
#### Shadowed signals and instances
|
2182
2212
|
|
2183
|
-
It is possible in HDLRuby to declare a signal or an instance whose name is identical to one used in one of the included systems. In such a case, the corresponding construct of the included system is still present, but it is not directly accessible even if exported, they are said to be shadowed.
|
2213
|
+
It is possible in HDLRuby to declare a signal or an instance whose name is identical to the one used in one of the included systems. In such a case, the corresponding construct of the included system is still present, but it is not directly accessible even if exported, they are said to be shadowed.
|
2184
2214
|
|
2185
|
-
|
2215
|
+
To access the shadowed signals or instances, a system must be reinterpreted as the relevant parent system using the `as` operator as follows: `as(system)`.
|
2186
2216
|
|
2187
|
-
For example, in the following code signal `db` of system `dff_db` is shadowed by signal `db` of system `dff_shadow`, but it is accessed using the `as` operator.
|
2217
|
+
For example, in the following code signal, `db` of system `dff_db` is shadowed by signal `db` of system `dff_shadow`, but it is accessed using the `as` operator.
|
2188
2218
|
|
2189
2219
|
```ruby
|
2190
2220
|
system :dff_db do
|
@@ -2287,9 +2317,9 @@ fix32.define_operator(:*) do |left,right|
|
|
2287
2317
|
end
|
2288
2318
|
```
|
2289
2319
|
|
2290
|
-
Please notice, that in the code above, the left value has been
|
2320
|
+
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.
|
2291
2321
|
|
2292
|
-
|
2322
|
+
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.
|
2293
2323
|
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):
|
2294
2324
|
|
2295
2325
|
```ruby
|
@@ -2308,7 +2338,7 @@ end
|
|
2308
2338
|
|
2309
2339
|
### Predicate and access methods
|
2310
2340
|
|
2311
|
-
|
2341
|
+
To get information about the current state of the hardware description HDLRuby provides the following predicates:
|
2312
2342
|
|
2313
2343
|
| predicate name | predicate type | predicate meaning |
|
2314
2344
|
| :--- | :--- | :--- |
|
@@ -2340,7 +2370,7 @@ Several enumerators are also provided for accessing the internals of the current
|
|
2340
2370
|
|
2341
2371
|
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.
|
2342
2372
|
|
2343
|
-
|
2373
|
+
To ease the design of standardized libraries, the following global signals are defined by default:
|
2344
2374
|
|
2345
2375
|
| signal name | signal type | signal function |
|
2346
2376
|
| :--- | :--- | :--- |
|
@@ -2357,7 +2387,7 @@ __Note__:
|
|
2357
2387
|
### Defining and executing Ruby methods within HDLRuby constructs
|
2358
2388
|
<a name="method"></a>
|
2359
2389
|
|
2360
|
-
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
|
2390
|
+
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.
|
2361
2391
|
|
2362
2392
|
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`.
|
2363
2393
|
|
@@ -2385,9 +2415,9 @@ end
|
|
2385
2415
|
|
2386
2416
|
__Warning__:
|
2387
2417
|
|
2388
|
-
- In the above example, the semantic of `some_arrow` changes depending on where it is invoked from
|
2418
|
+
- In the above example, the semantic of `some_arrow` changes depending on where it is invoked from, e.g., within a system, it is a connection, within a behavior, it is a transmission.
|
2389
2419
|
|
2390
|
-
- Using Ruby methods for describing hardware might lead to weak code, for example the
|
2420
|
+
- Using Ruby methods for describing hardware might lead to weak code, for example, in the following code, the method declares `in0` as an input signal. Hence, while used in `sys0` no problem happens, an exception will be raised for `sys1` because a signal `in0` is already declared and will also be raised for `sys2` because it is not possible to declare an input from within a behavior.
|
2391
2421
|
|
2392
2422
|
```ruby
|
2393
2423
|
def in_decl
|
@@ -2410,7 +2440,7 @@ __Warning__:
|
|
2410
2440
|
end
|
2411
2441
|
```
|
2412
2442
|
|
2413
|
-
Like any other Ruby method, methods defined in HDLRuby support variadic arguments
|
2443
|
+
Like any other Ruby method, methods defined in HDLRuby support variadic arguments named arguments, and block arguments. For example, the following method can be used to connect a driver to multiple signals:
|
2414
2444
|
|
2415
2445
|
```ruby
|
2416
2446
|
def mconnect(driver, *signals)
|
@@ -2451,11 +2481,11 @@ end
|
|
2451
2481
|
|
2452
2482
|
In the code above:
|
2453
2483
|
|
2454
|
-
- the default initialization of `rst` to `$rst` allows
|
2484
|
+
- the default initialization of `rst` to `$rst` allows resetting the counter even if no such signal is provided as an argument.
|
2455
2485
|
|
2456
|
-
- `sub` ensures that the `count` signal
|
2486
|
+
- `sub` ensures that the `count` signal does not conflict with another signal with the same name.
|
2457
2487
|
|
2458
|
-
- the `instance_eval` keyword is a standard Ruby method that executes the block passed as argument in context.
|
2488
|
+
- the `instance_eval` keyword is a standard Ruby method that executes the block passed as an argument in context.
|
2459
2489
|
|
2460
2490
|
The following is an example that switches a LED on after 1000000 clock cycles using the previously defined `after` ruby method:
|
2461
2491
|
|
@@ -2478,13 +2508,13 @@ __Note__:
|
|
2478
2508
|
|
2479
2509
|
### Dynamic description
|
2480
2510
|
|
2481
|
-
When describing a system, it is possible to disconnect or
|
2511
|
+
When describing a system, it is possible to disconnect or completely undefine a signal or an instance.
|
2482
2512
|
|
2483
2513
|
|
2484
2514
|
## Extending HDLRuby
|
2485
2515
|
<a name="extend"></a>
|
2486
2516
|
|
2487
|
-
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 extension.
|
2517
|
+
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.
|
2488
2518
|
|
2489
2519
|
### Extending HDLRuby constructs globally
|
2490
2520
|
|
@@ -2521,7 +2551,7 @@ The following table gives the class of each construct of HDLRuby.
|
|
2521
2551
|
|
2522
2552
|
### Extending HDLRuby constructs locally
|
2523
2553
|
|
2524
|
-
By local extension of a hardware construct, we mean that while the construct will be changed, all the other constructs will remain unchanged. This is achieved like in Ruby by accessing the
|
2554
|
+
By local extension of a hardware construct, we mean that while the construct will be changed, all the other constructs will remain unchanged. This is achieved like in Ruby by accessing the Eigen class using the `singleton_class` method and extending it using the `class_eval` method. For example, with the following code, only system `dff` will respond to method `interface_size`:
|
2525
2555
|
|
2526
2556
|
```ruby
|
2527
2557
|
dff.singleton_class.class_eval do
|
@@ -2557,7 +2587,7 @@ end
|
|
2557
2587
|
|
2558
2588
|
### Modifying the generation behavior
|
2559
2589
|
|
2560
|
-
The main purpose of allowing global and local extensions for hardware constructs is to give the user the possibility
|
2590
|
+
The main purpose of allowing global and local extensions for hardware constructs is to give the user the possibility to implement its synthesis methods. For example, one may want to implement some algorithm for a given kind of system. For that purpose, the user can define an abstract system (without any hardware content), that holds the specific algorithm as follows:
|
2561
2591
|
|
2562
2592
|
```ruby
|
2563
2593
|
system(:my_base) {}
|
@@ -2569,7 +2599,7 @@ my_base.singleton_instance.class_eval do
|
|
2569
2599
|
end
|
2570
2600
|
```
|
2571
2601
|
|
2572
|
-
Then, when this system named `my_base` is included
|
2602
|
+
Then, when this system named `my_base` is included in another system, this latter will inherit from the algorithms implemented inside method `my_generation` as shown in the following code:
|
2573
2603
|
|
2574
2604
|
```ruby
|
2575
2605
|
system :some_system, my_base do
|
@@ -2613,7 +2643,7 @@ This way, calling directly `to_low` will automatically use `my_generation`.
|
|
2613
2643
|
# Standard library
|
2614
2644
|
<a name="library"></a>
|
2615
2645
|
|
2616
|
-
The standard libraries are included
|
2646
|
+
The standard libraries are included in the module `Std`.
|
2617
2647
|
They can be loaded as follows, where `<library name>` is the name of the
|
2618
2648
|
library:
|
2619
2649
|
|
@@ -2632,9 +2662,9 @@ include HDLRuby::High::Std
|
|
2632
2662
|
## Clocks
|
2633
2663
|
<a name="clocks"></a>
|
2634
2664
|
|
2635
|
-
The `clocks` library provides utilities for
|
2665
|
+
The `clocks` library provides utilities for easier handling of clock synchronizations.
|
2636
2666
|
|
2637
|
-
It adds the possibility to multiply events by integer. The result is a new event whose frequency is divided by the integer multiplicand. For example, the following code describes a D-FF that memorizes each three clock cycles.
|
2667
|
+
It adds the possibility to multiply events by an integer. The result is a new event whose frequency is divided by the integer multiplicand. For example, the following code describes a D-FF that memorizes each three clock cycles.
|
2638
2668
|
|
2639
2669
|
```ruby
|
2640
2670
|
require 'std/clocks'
|
@@ -2656,7 +2686,7 @@ __Note__: this library does generate all the RTL code for the circuit handling t
|
|
2656
2686
|
|
2657
2687
|
This library provides two new constructs for implementing synthesizable wait statements.
|
2658
2688
|
|
2659
|
-
The first construct is the `after` statement that activates a block after a given number of
|
2689
|
+
The first construct is the `after` statement that activates a block after a given number of clock cycles is passed. Its syntax is the following:
|
2660
2690
|
|
2661
2691
|
```ruby
|
2662
2692
|
after(<number>,<clock>,<reset>)
|
@@ -2670,7 +2700,7 @@ Where:
|
|
2670
2700
|
|
2671
2701
|
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.
|
2672
2702
|
|
2673
|
-
The second construct is the `before` statement that activates a block until a given number of
|
2703
|
+
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.
|
2674
2704
|
|
2675
2705
|
|
2676
2706
|
## Decoder
|
@@ -2690,7 +2720,7 @@ Where `signal` is the signal to decode and `block` is a procedure block (i.e., R
|
|
2690
2720
|
entry(<pattern>) <block>
|
2691
2721
|
```
|
2692
2722
|
|
2693
|
-
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
|
2723
|
+
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.
|
2694
2724
|
|
2695
2725
|
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`:
|
2696
2726
|
|
@@ -2701,7 +2731,7 @@ decoder(ir) do
|
|
2701
2731
|
end
|
2702
2732
|
```
|
2703
2733
|
|
2704
|
-
|
2734
|
+
It can be noticed for field `z` in the example above that the bits are not required to be contiguous.
|
2705
2735
|
|
2706
2736
|
## FSM
|
2707
2737
|
<a name="fsm"></a>
|
@@ -2714,9 +2744,9 @@ A finite state machine can be declared anywhere provided it is outside a behavio
|
|
2714
2744
|
fsm(<event>,<reset>,<mode>) <block>
|
2715
2745
|
```
|
2716
2746
|
|
2717
|
-
Where `event` is the event (rising falling edge of a signal) activating the state transitions, `rst` is the reset signal, and `mode` is the default execution mode and `block` is the execution block describing the states of the FSM. This last parameter can be either `:sync` for synchronous (Moore type) or `:async` for asynchronous (Mealy type).
|
2747
|
+
Where `event` is the event (rising or falling edge of a signal) activating the state transitions, `rst` is the reset signal, and `mode` is the default execution mode and `block` is the execution block describing the states of the FSM. This last parameter can be either `:sync` for synchronous (Moore type) or `:async` for asynchronous (Mealy type).
|
2718
2748
|
|
2719
|
-
The states of
|
2749
|
+
The states of an FSM are described as follows:
|
2720
2750
|
|
2721
2751
|
```ruby
|
2722
2752
|
<kind>(<name>) <block>
|
@@ -2737,19 +2767,19 @@ default <block>
|
|
2737
2767
|
|
2738
2768
|
Where `block` is the action to execute.
|
2739
2769
|
|
2740
|
-
State transitions are by default set to be from one state to the following in the description order. If no more transition is declared the next one is the first declared transition. A specific transition is defined using the `goto` statement as last statement of the action block as follows:
|
2770
|
+
State transitions are by default set to be from one state to the following in the description order. If no more transition is declared the next one is the first declared transition. A specific transition is defined using the `goto` statement as the last statement of the action block as follows:
|
2741
2771
|
|
2742
2772
|
```ruby
|
2743
2773
|
goto(<condition>,<names>)
|
2744
2774
|
```
|
2745
2775
|
|
2746
|
-
Where `condition` is a signal whose value is used as index for
|
2776
|
+
Where `condition` is a signal whose value is used as an index for selecting the target state among the ones specified in the `names` list. For example, the following statement indicates to go to the state named `st_a` if the `cond` is 0, `st_b` if the condition is 1, and `st_c` if the condition is 2, otherwise this specific transition is ignored:
|
2747
2777
|
|
2748
2778
|
```ruby
|
2749
2779
|
goto(cond,:st_a,:st_b,:st_c)
|
2750
2780
|
```
|
2751
2781
|
|
2752
|
-
Several goto statements can be used, the last one having priority provided it is taken (i.e., its condition
|
2782
|
+
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.
|
2753
2783
|
|
2754
2784
|
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`):
|
2755
2785
|
|
@@ -2779,7 +2809,7 @@ end
|
|
2779
2809
|
## Fixed-point (fixpoint)
|
2780
2810
|
<a name="fixpoint"></a>
|
2781
2811
|
|
2782
|
-
This library provides a new fixed point set of data types. These new data types can be bit vectors, unsigned or signed
|
2812
|
+
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:
|
2783
2813
|
|
2784
2814
|
```ruby
|
2785
2815
|
bit[<integer part range>,<fractional part range>]
|
@@ -2787,21 +2817,21 @@ unsigned[<integer part range>,<fractional part range>]
|
|
2787
2817
|
signed[<integer part range>,<fractional part range>]
|
2788
2818
|
```
|
2789
2819
|
|
2790
|
-
For example a signed 4-bit integer part 4-bit fractional part fixed point inner signal named `sig` can be declared as follows:
|
2820
|
+
For example, a signed 4-bit integer part 4-bit fractional part fixed point inner signal named `sig` can be declared as follows:
|
2791
2821
|
|
2792
2822
|
```ruby
|
2793
2823
|
bit[4,4].inner :sig
|
2794
2824
|
```
|
2795
2825
|
|
2796
|
-
When performing computation with fixed
|
2826
|
+
When performing computation with fixed-point types, HDLRuby ensures that the result's decimal point position is correct.
|
2797
2827
|
|
2798
|
-
In addition to the fixed point data type, a method is added to the literal objects (Numeric) to convert them to fixed
|
2828
|
+
In addition to the fixed point data type, a method is added to the literal objects (Numeric) to convert them to fixed-point representation:
|
2799
2829
|
|
2800
2830
|
```ruby
|
2801
2831
|
<litteral>.to_fix(<number of bits after the decimal point>)
|
2802
2832
|
```
|
2803
2833
|
|
2804
|
-
For example the following code converts a floating
|
2834
|
+
For example, the following code converts a floating-point value to a fixed point value with 16 bits after the decimal point:
|
2805
2835
|
|
2806
2836
|
```
|
2807
2837
|
3.178.to_fix(16)
|
@@ -2811,14 +2841,14 @@ For example the following code converts a floating point value to a fixed point
|
|
2811
2841
|
## Channel
|
2812
2842
|
<a name="channel"></a>
|
2813
2843
|
|
2814
|
-
This library provides a unified interface to complex communication protocols through a new kind of
|
2844
|
+
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.
|
2815
2845
|
|
2816
2846
|
### Using a channel
|
2817
2847
|
|
2818
2848
|
A channel is used similarly to a pipe: it has an input where data can be written and an output where data can be read. The ordering of the data and the synchronization depend on the internals of the channel, e.g., a channel can be FIFO or LIFO. The interaction with the channel is done using the following methods:
|
2819
2849
|
|
2820
|
-
* `write(<args>) <block>`: write to the channel and execute `block` when `write` completes. `args` is a list of arguments required for performing the write that
|
2821
|
-
* `read(<args>) <block>`: read the channel and execute `block` when the read completes. `args` is a list of arguments required for performing the write that
|
2850
|
+
* `write(<args>) <block>`: write to the channel and execute `block` when `write` completes. `args` is a list of arguments required for performing the write that depends on the channel.
|
2851
|
+
* `read(<args>) <block>`: read the channel and execute `block` when the read completes. `args` is a list of arguments required for performing the write that depends on the channel.
|
2822
2852
|
|
2823
2853
|
|
2824
2854
|
For example, a system sending successive 8-bit values through a channel can be described as follows:
|
@@ -2840,15 +2870,15 @@ system :producer8 do |channel|
|
|
2840
2870
|
end
|
2841
2871
|
```
|
2842
2872
|
|
2843
|
-
__Note__: In the code above, the channel is passed as generic argument of the system.
|
2873
|
+
__Note__: In the code above, the channel is passed as a generic argument of the system.
|
2844
2874
|
|
2845
2875
|
The access points to a channel can also be handled individually by declaring ports using the following methods:
|
2846
2876
|
|
2847
|
-
* `input <name>`: declares a port for reading from the channel and
|
2848
|
-
* `output <name>`: declares a port for writing to the channel and
|
2849
|
-
* `inout <name>`: declares a port for reading and writing to the channel and
|
2877
|
+
* `input <name>`: declares a port for reading from the channel and associates them to `name` if any
|
2878
|
+
* `output <name>`: declares a port for writing to the channel and associates them to `name` if any
|
2879
|
+
* `inout <name>`: declares a port for reading and writing to the channel and associates them to `name` if any
|
2850
2880
|
|
2851
|
-
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
|
2881
|
+
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:
|
2852
2882
|
|
2853
2883
|
* `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.
|
2854
2884
|
|
@@ -2860,11 +2890,11 @@ For example, assuming `mem` is a channel whose read and write access have as arg
|
|
2860
2890
|
|
2861
2891
|
### Channel branches
|
2862
2892
|
|
2863
|
-
Some
|
2893
|
+
Some channels may include several branches, they are accessed by name using the following method:
|
2864
2894
|
|
2865
|
-
* `branch(<name>)`: gets branch named `name` from the channel. This name can be
|
2895
|
+
* `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.
|
2866
2896
|
|
2867
|
-
A branch is a full
|
2897
|
+
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`:
|
2868
2898
|
|
2869
2899
|
```ruby
|
2870
2900
|
br = ch.branch(0)
|
@@ -2874,13 +2904,13 @@ par(clk.posedge) { br.read(val) }
|
|
2874
2904
|
|
2875
2905
|
### Declaring a channel
|
2876
2906
|
|
2877
|
-
A new channel is declared
|
2907
|
+
A new channel is declared using the keyword `channel` as follows:
|
2878
2908
|
|
2879
2909
|
```ruby
|
2880
2910
|
channel <name> <block>
|
2881
2911
|
```
|
2882
2912
|
|
2883
|
-
Where `name` is the name of the channel and `block` is a procedure block describing the channel. This block can contain any HDLRuby code, and is comparable to the content of a block describing a system with the difference that it does not have standard input, output and inout ports are declared differently and that it supports following additional keywords:
|
2913
|
+
Where `name` is the name of the channel and `block` is a procedure block describing the channel. This block can contain any HDLRuby code, and is comparable to the content of a block describing a system with the difference that it does not have standard input, output, and inout ports are declared differently, and that it supports the following additional keywords:
|
2884
2914
|
|
2885
2915
|
* `reader_input <list of names>`: declares the input ports on the reader side. The list must give the names of the inner signals of the channel that can be read using the reader procedure.
|
2886
2916
|
* `reader_output <list of names>`: declares the output ports on the reader side. The list must give the names of the inner signals of the channel that can be written using the reader procedure.
|
@@ -2888,20 +2918,20 @@ Where `name` is the name of the channel and `block` is a procedure block describ
|
|
2888
2918
|
* `writer_input <list of names>`: declares the input ports on the writer side. The list must give the names of the inner signals of the channel that can be read using the writer procedure.
|
2889
2919
|
* `writer_output <list of names>`: declares the output ports on the writer side. The list must give the names of the inner signals of the channel that can be written using the writer procedure.
|
2890
2920
|
* `writer_inout <list of names>`: declares the inout ports on the writer side. The list must give the names of the inner signals of the channel that can be written using the writer procedure.
|
2891
|
-
* `accesser_input <list of names>`: declares the input ports on both the reader and writer
|
2892
|
-
* `accesser_output <list of names>`: declares the output ports on both the reader and writer
|
2893
|
-
* `accesser_inout <list of names>`: declares the inout ports on both the reader and writer
|
2921
|
+
* `accesser_input <list of names>`: declares the input ports on both the reader and writer sides. The list must give the names of the inner signals of the channel that can be read using the writer procedure.
|
2922
|
+
* `accesser_output <list of names>`: declares the output ports on both the reader and writer sides. The list must give the names of the inner signals of the channel that can be written using the writer procedure.
|
2923
|
+
* `accesser_inout <list of names>`: declares the inout ports on both the reader and writer sides. The list must give the names of the inner signals of the channel that can be written using the writer procedure.
|
2894
2924
|
* `reader <block>`: defines the reader's access procedure.
|
2895
|
-
This procedure is invoked by method `read` of the channel (please refer to the previous example).
|
2925
|
+
This procedure is invoked by the method `read` of the channel (please refer to the previous example).
|
2896
2926
|
The first argument of the block must be the following:
|
2897
2927
|
- `blk`: the block to execute when the read completes.
|
2898
|
-
Other arguments can be freely defined
|
2928
|
+
Other arguments can be freely defined and will be required by the `read` method.
|
2899
2929
|
* `writer < block>`: defines the writer's access procedure.
|
2900
|
-
This procedure is invoked by method `write` of the channel (please refer to the previous example).
|
2930
|
+
This procedure is invoked by the method `write` of the channel (please refer to the previous example).
|
2901
2931
|
The first argument of the block must be the following:
|
2902
2932
|
- `blk`: the block to execute when the write completes.
|
2903
|
-
Other arguments can be freely defined
|
2904
|
-
* `brancher(name) <block>`: defines branch named +name+ described in `block`. The content of block can be any content valid for a channel, with the additional possibility to access the internals of the upper channel.
|
2933
|
+
Other arguments can be freely defined and will be required by the `write` command.
|
2934
|
+
* `brancher(name) <block>`: defines branch named +name+ described in `block`. The content of the block can be any content valid for a channel, with the additional possibility to access the internals of the upper channel.
|
2905
2935
|
|
2906
2936
|
For example, a channel implemented by a simple register of generic type `typ`, that can be set to 0 using the `reset` command can be described as follows:
|
2907
2937
|
|
@@ -2934,7 +2964,7 @@ end
|
|
2934
2964
|
|
2935
2965
|
__Notes__:
|
2936
2966
|
|
2937
|
-
* The described channel assumes that
|
2967
|
+
* The described channel assumes that the `write` method of the channel is invoked within a clocked process (otherwise, the register will become a latch).
|
2938
2968
|
* The described channel supports the `read` and `write` methods to be invoked with or without a block.
|
2939
2969
|
|
2940
2970
|
|
@@ -2944,7 +2974,7 @@ Like systems, a channel must be instantiated for being used, and the instantiati
|
|
2944
2974
|
<channel name> :<instance name>
|
2945
2975
|
```
|
2946
2976
|
|
2947
|
-
And in case there
|
2977
|
+
And in case there is a generic parameter, the instantiation procedure is as follows:
|
2948
2978
|
|
2949
2979
|
```ruby
|
2950
2980
|
<channel name>(:<instance name>).(<generic parameters>)
|
@@ -2986,17 +3016,7 @@ end
|
|
2986
3016
|
|
2987
3017
|
__Note__:
|
2988
3018
|
|
2989
|
-
* The code of the circuits, in the examples `producer8`, `consumer8
|
2990
|
-
|
2991
|
-
|
2992
|
-
## Reconf
|
2993
|
-
<a name="reconf"></a>
|
2994
|
-
|
2995
|
-
This library provides a unified interface to partially (or dynamically) reconfigurable devices.
|
2996
|
-
|
2997
|
-
__Warning__:
|
2998
|
-
|
2999
|
-
While the framework of this library is completed, not target reconfigurable device is defined yet.
|
3019
|
+
* 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.
|
3000
3020
|
|
3001
3021
|
|
3002
3022
|
## Pipeline
|
@@ -3022,7 +3042,7 @@ The naming convention of the samples is the following:
|
|
3022
3042
|
|
3023
3043
|
* `<name>.rb`: default type of sample.
|
3024
3044
|
* `<name>_gen.rb`: generic parameters are required for processing the sample.
|
3025
|
-
* `<name>_bench.rb`: sample including a simulation benchmark, these are the only samples that can be simulated using `hdrcc -S`. Please notice that such sample cannot be converted to VHDL
|
3045
|
+
* `<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.
|
3026
3046
|
|
3027
3047
|
|
3028
3048
|
# Contributing
|
@@ -3042,5 +3062,5 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/civol/
|
|
3042
3062
|
|
3043
3063
|
# License
|
3044
3064
|
|
3045
|
-
The gem is available as open
|
3065
|
+
The gem is available as open-source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
3046
3066
|
|